forked from nikita/muzika-gromche
Rewrite track choosing event to custom netcode
This commit is contained in:
parent
1aa8c1ddfa
commit
0dca416958
|
@ -3,6 +3,7 @@
|
||||||
## MuzikaGromche 1337.69.420
|
## MuzikaGromche 1337.69.420
|
||||||
|
|
||||||
- Fix certain object hanging around after being disabled.
|
- Fix certain object hanging around after being disabled.
|
||||||
|
- CSync proved to be unreliable for config syncing, so rewrote track selection to custom netcode.
|
||||||
|
|
||||||
## MuzikaGromche 13.37.9001 - Chromaberrated Edition
|
## MuzikaGromche 13.37.9001 - Chromaberrated Edition
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<Project>
|
||||||
|
<Target Name="NetcodePatch" AfterTargets="PostBuildEvent">
|
||||||
|
<Exec Command="dotnet netcode-patch -nv 1.5.2 "$(TargetPath)" @(ReferencePathWithRefAssemblies->'"%(Identity)"', ' ')"/>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
|
@ -13,6 +13,9 @@
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<!-- NetcodePatch requires anything but 'full' -->
|
||||||
|
<DebugType>portable</DebugType>
|
||||||
|
|
||||||
<PackageReadmeFile>../README.md</PackageReadmeFile>
|
<PackageReadmeFile>../README.md</PackageReadmeFile>
|
||||||
<PackageProjectUrl>https://git.vilunov.me/ratijas/muzika-gromche</PackageProjectUrl>
|
<PackageProjectUrl>https://git.vilunov.me/ratijas/muzika-gromche</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://git.vilunov.me/ratijas/muzika-gromche</RepositoryUrl>
|
<RepositoryUrl>https://git.vilunov.me/ratijas/muzika-gromche</RepositoryUrl>
|
||||||
|
|
|
@ -9,6 +9,7 @@ using LethalConfig.ConfigItems.Options;
|
||||||
using LobbyCompatibility.Attributes;
|
using LobbyCompatibility.Attributes;
|
||||||
using LobbyCompatibility.Enums;
|
using LobbyCompatibility.Enums;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -16,6 +17,7 @@ using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
|
@ -482,6 +484,11 @@ namespace MuzikaGromche
|
||||||
return tracks[trackId];
|
return tracks[trackId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Track? FindTrackNamed(string name)
|
||||||
|
{
|
||||||
|
return Tracks.FirstOrDefault(track => track.Name == name);
|
||||||
|
}
|
||||||
|
|
||||||
internal static Track? CurrentTrack;
|
internal static Track? CurrentTrack;
|
||||||
internal static BeatTimeState? BeatTimeState;
|
internal static BeatTimeState? BeatTimeState;
|
||||||
|
|
||||||
|
@ -547,6 +554,7 @@ namespace MuzikaGromche
|
||||||
DiscoBallManager.Load();
|
DiscoBallManager.Load();
|
||||||
PoweredLightsAnimators.Load();
|
PoweredLightsAnimators.Load();
|
||||||
var harmony = new Harmony(PluginInfo.PLUGIN_NAME);
|
var harmony = new Harmony(PluginInfo.PLUGIN_NAME);
|
||||||
|
harmony.PatchAll(typeof(GameNetworkManagerPatch));
|
||||||
harmony.PatchAll(typeof(JesterPatch));
|
harmony.PatchAll(typeof(JesterPatch));
|
||||||
harmony.PatchAll(typeof(EnemyAIPatch));
|
harmony.PatchAll(typeof(EnemyAIPatch));
|
||||||
harmony.PatchAll(typeof(PoweredLightsAnimatorsPatch));
|
harmony.PatchAll(typeof(PoweredLightsAnimatorsPatch));
|
||||||
|
@ -554,6 +562,7 @@ namespace MuzikaGromche
|
||||||
harmony.PatchAll(typeof(DiscoBallTilePatch));
|
harmony.PatchAll(typeof(DiscoBallTilePatch));
|
||||||
harmony.PatchAll(typeof(DiscoBallDespawnPatch));
|
harmony.PatchAll(typeof(DiscoBallDespawnPatch));
|
||||||
harmony.PatchAll(typeof(SpawnRatePatch));
|
harmony.PatchAll(typeof(SpawnRatePatch));
|
||||||
|
NetcodePatcher();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -561,6 +570,23 @@ namespace MuzikaGromche
|
||||||
Logger.LogError("Could not load audio file " + string.Join(", ", failed));
|
Logger.LogError("Could not load audio file " + string.Join(", ", failed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void NetcodePatcher()
|
||||||
|
{
|
||||||
|
var types = Assembly.GetExecutingAssembly().GetTypes();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
var attributes = method.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), false);
|
||||||
|
if (attributes.Length > 0)
|
||||||
|
{
|
||||||
|
method.Invoke(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public readonly record struct Language(string Short, string Full)
|
public readonly record struct Language(string Short, string Full)
|
||||||
|
@ -680,7 +706,7 @@ namespace MuzikaGromche
|
||||||
public AudioClip LoadedLoop = null!;
|
public AudioClip LoadedLoop = null!;
|
||||||
|
|
||||||
// How often this track should be chosen, relative to the sum of weights of all tracks.
|
// How often this track should be chosen, relative to the sum of weights of all tracks.
|
||||||
public SyncedEntry<int> Weight = null!;
|
public ConfigEntry<int> Weight = null!;
|
||||||
|
|
||||||
public string FileNameStart => $"{Name}Start.{Ext}";
|
public string FileNameStart => $"{Name}Start.{Ext}";
|
||||||
public string FileNameLoop => $"{Name}Loop.{Ext}";
|
public string FileNameLoop => $"{Name}Loop.{Ext}";
|
||||||
|
@ -1428,7 +1454,7 @@ namespace MuzikaGromche
|
||||||
|
|
||||||
public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null!;
|
public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null!;
|
||||||
|
|
||||||
public static SyncedEntry<bool> OverrideSpawnRates { get; private set; } = null!;
|
public static ConfigEntry<bool> OverrideSpawnRates { get; private set; } = null!;
|
||||||
|
|
||||||
public static bool ShouldSkipWindingPhase { get; private set; } = false;
|
public static bool ShouldSkipWindingPhase { get; private set; } = false;
|
||||||
|
|
||||||
|
@ -1456,12 +1482,11 @@ namespace MuzikaGromche
|
||||||
|
|
||||||
SkipExplicitTracks = configFile.Bind("General", "Skip Explicit Tracks", false,
|
SkipExplicitTracks = configFile.Bind("General", "Skip Explicit Tracks", false,
|
||||||
new ConfigDescription("When choosing tracks at random, skip the ones with Explicit Content/Lyrics."));
|
new ConfigDescription("When choosing tracks at random, skip the ones with Explicit Content/Lyrics."));
|
||||||
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(SkipExplicitTracks, requiresRestart: false));
|
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(SkipExplicitTracks, Default(new BoolCheckBoxOptions())));
|
||||||
|
|
||||||
OverrideSpawnRates = configFile.BindSyncedEntry("General", "Override Spawn Rates", false,
|
OverrideSpawnRates = configFile.Bind("General", "Override Spawn Rates", false,
|
||||||
new ConfigDescription("Deviate from vanilla spawn rates to experience content of this mod more often."));
|
new ConfigDescription("Deviate from vanilla spawn rates to experience content of this mod more often."));
|
||||||
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(OverrideSpawnRates.Entry, Default(new BoolCheckBoxOptions())));
|
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(OverrideSpawnRates, Default(new BoolCheckBoxOptions())));
|
||||||
CSyncHackAddSyncedEntry(OverrideSpawnRates);
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
SetupEntriesToSkipWinding(configFile);
|
SetupEntriesToSkipWinding(configFile);
|
||||||
|
@ -1489,11 +1514,11 @@ namespace MuzikaGromche
|
||||||
if (CanModifyWeightsNow())
|
if (CanModifyWeightsNow())
|
||||||
{
|
{
|
||||||
var tracks = Plugin.Tracks.Where(t => t.Language.Equals(language)).ToList();
|
var tracks = Plugin.Tracks.Where(t => t.Language.Equals(language)).ToList();
|
||||||
var isOff = tracks.All(t => t.Weight.LocalValue == 0);
|
var isOff = tracks.All(t => t.Weight.Value == 0);
|
||||||
var newWeight = isOff ? 50 : 0;
|
var newWeight = isOff ? 50 : 0;
|
||||||
foreach (var t in tracks)
|
foreach (var t in tracks)
|
||||||
{
|
{
|
||||||
t.Weight.LocalValue = newWeight;
|
t.Weight.Value = newWeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1504,13 +1529,12 @@ namespace MuzikaGromche
|
||||||
// Create slider entry for track
|
// Create slider entry for track
|
||||||
string warning = track.IsExplicit ? "Explicit Content/Lyrics!\n\n" : "";
|
string warning = track.IsExplicit ? "Explicit Content/Lyrics!\n\n" : "";
|
||||||
string description = $"Language: {language.Full}\n\n{warning}Random (relative) chance of selecting this track.\n\nSet to zero to effectively disable the track.";
|
string description = $"Language: {language.Full}\n\n{warning}Random (relative) chance of selecting this track.\n\nSet to zero to effectively disable the track.";
|
||||||
track.Weight = configFile.BindSyncedEntry(
|
track.Weight = configFile.Bind(
|
||||||
new ConfigDefinition(section, track.Name),
|
new ConfigDefinition(section, track.Name),
|
||||||
50,
|
50,
|
||||||
new ConfigDescription(description, chanceRange, track));
|
new ConfigDescription(description, chanceRange, track));
|
||||||
|
|
||||||
LethalConfigManager.AddConfigItem(new IntSliderConfigItem(track.Weight.Entry, Default(new IntSliderOptions())));
|
LethalConfigManager.AddConfigItem(new IntSliderConfigItem(track.Weight, Default(new IntSliderOptions())));
|
||||||
CSyncHackAddSyncedEntry(track.Weight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigManager.Register(this);
|
ConfigManager.Register(this);
|
||||||
|
@ -1774,6 +1798,78 @@ namespace MuzikaGromche
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GameNetworkManager))]
|
||||||
|
static class GameNetworkManagerPatch
|
||||||
|
{
|
||||||
|
const string JesterEnemyPrefabName = "JesterEnemy";
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(GameNetworkManager.Start))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
static void StartPrefix(GameNetworkManager __instance)
|
||||||
|
{
|
||||||
|
var networkPrefab = NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs
|
||||||
|
.FirstOrDefault(prefab => prefab.Prefab.name == JesterEnemyPrefabName);
|
||||||
|
if (networkPrefab == null)
|
||||||
|
{
|
||||||
|
Debug.LogError($"{nameof(MuzikaGromche)} JesterEnemy prefab not found!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Log($"{nameof(MuzikaGromche)} Patching {nameof(JesterAI)} with {nameof(MuzikaGromcheJesterNetworkBehaviour)} component");
|
||||||
|
networkPrefab.Prefab.AddComponent<MuzikaGromcheJesterNetworkBehaviour>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuzikaGromcheJesterNetworkBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public override void OnNetworkSpawn()
|
||||||
|
{
|
||||||
|
ChooseTrackDeferred();
|
||||||
|
foreach (var track in Plugin.Tracks)
|
||||||
|
{
|
||||||
|
track.Weight.SettingChanged += (_, _) => ChooseTrackDeferred();
|
||||||
|
}
|
||||||
|
Config.SkipExplicitTracks.SettingChanged += (_, _) => ChooseTrackDeferred();
|
||||||
|
base.OnNetworkSpawn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch multiple weights changes in a single network RPC
|
||||||
|
private Coroutine? DeferredCoroutine = null;
|
||||||
|
|
||||||
|
private void ChooseTrackDeferred()
|
||||||
|
{
|
||||||
|
if (DeferredCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(DeferredCoroutine);
|
||||||
|
DeferredCoroutine = null;
|
||||||
|
}
|
||||||
|
DeferredCoroutine = StartCoroutine(ChooseTrackDeferredCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator ChooseTrackDeferredCoroutine()
|
||||||
|
{
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
DeferredCoroutine = null;
|
||||||
|
ChooseTrackServerRpc();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public void SetTrackClientRpc(string name)
|
||||||
|
{
|
||||||
|
Debug.Log($"{nameof(MuzikaGromche)} SetTrackClientRpc {name}");
|
||||||
|
Plugin.CurrentTrack = Plugin.FindTrackNamed(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ServerRpc]
|
||||||
|
public void ChooseTrackServerRpc()
|
||||||
|
{
|
||||||
|
var track = Plugin.ChooseTrack();
|
||||||
|
Debug.Log($"{nameof(MuzikaGromche)} ChooseTrackServerRpc {track.Name}");
|
||||||
|
SetTrackClientRpc(track.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// farAudio is during windup, Start overrides popGoesTheWeaselTheme
|
// farAudio is during windup, Start overrides popGoesTheWeaselTheme
|
||||||
// creatureVoice is when popped, Loop overrides screamingSFX
|
// creatureVoice is when popped, Loop overrides screamingSFX
|
||||||
[HarmonyPatch(typeof(JesterAI))]
|
[HarmonyPatch(typeof(JesterAI))]
|
||||||
|
@ -1820,6 +1916,14 @@ namespace MuzikaGromche
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
static void JesterUpdatePostfix(JesterAI __instance, State __state)
|
static void JesterUpdatePostfix(JesterAI __instance, State __state)
|
||||||
{
|
{
|
||||||
|
if (Plugin.CurrentTrack == null)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Debug.Log($"{nameof(MuzikaGromche)} CurrentTrack is not set!");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (__instance.previousState == 1 && __state.previousState != 1)
|
if (__instance.previousState == 1 && __state.previousState != 1)
|
||||||
{
|
{
|
||||||
// if just started winding up
|
// if just started winding up
|
||||||
|
@ -1828,7 +1932,6 @@ namespace MuzikaGromche
|
||||||
__instance.creatureVoice.Stop();
|
__instance.creatureVoice.Stop();
|
||||||
|
|
||||||
// ...and start modded music
|
// ...and start modded music
|
||||||
Plugin.CurrentTrack = Plugin.ChooseTrack();
|
|
||||||
Plugin.BeatTimeState = new BeatTimeState(Plugin.CurrentTrack);
|
Plugin.BeatTimeState = new BeatTimeState(Plugin.CurrentTrack);
|
||||||
// Set up custom popup timer, which is shorter than Start audio
|
// Set up custom popup timer, which is shorter than Start audio
|
||||||
__instance.popUpTimer = Plugin.CurrentTrack.WindUpTimer;
|
__instance.popUpTimer = Plugin.CurrentTrack.WindUpTimer;
|
||||||
|
@ -1878,9 +1981,9 @@ namespace MuzikaGromche
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage the timeline: switch color of the lights according to the current playback/beat position.
|
// Manage the timeline: switch color of the lights according to the current playback/beat position.
|
||||||
if (__instance.previousState == 1 || __instance.previousState == 2)
|
if ((__instance.previousState == 1 || __instance.previousState == 2) && Plugin.BeatTimeState != null)
|
||||||
{
|
{
|
||||||
var events = Plugin.BeatTimeState!.Update(start: __instance.farAudio, loop: __instance.creatureVoice);
|
var events = Plugin.BeatTimeState.Update(start: __instance.farAudio, loop: __instance.creatureVoice);
|
||||||
foreach (var ev in events)
|
foreach (var ev in events)
|
||||||
{
|
{
|
||||||
switch (ev)
|
switch (ev)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"evaisa.netcodepatcher.cli": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"commands": [
|
||||||
|
"netcode-patch"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue