Remove remaining CSync code and references

There were issues with clients not being able to join, potentially
caused by linked (even though actually unused) CSync library.
This commit is contained in:
ivan tkachenko 2025-08-22 15:10:34 +03:00
parent b3767cbbf0
commit 4516b853cd
4 changed files with 70 additions and 131 deletions

View File

@ -5,6 +5,7 @@
- Added a new track OnePartiyaUdar in Japanese language.
- Remastered recently added tracks at conventional 44100 Hz for better stitching.
- Improved playback experience: use precise DSP time and up-front scheduing for seamless audio stitching, add custom Audio Sources to improve reliability.
- Removed remaining CSync code and package references even from debug builds.
## MuzikaGromche 1337.420.9001 - Multiverse Edition

View File

@ -38,12 +38,6 @@
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" PrivateAssets="all" Private="false" />
<PackageReference Include="UnityEngine.Modules" Version="2022.3.9" PrivateAssets="all" Private="false" />
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.1" PrivateAssets="all" Private="false" />
<!--
Publicize internal methods, so we could generate config entries for tracks at runtime instead
of generating code at compile time. See https://github.com/lc-sigurd/CSync/issues/11
It is an optional dependency now, but there is no sane way to mark it as such.
-->
<PackageReference Include="Sigurd.BepInEx.CSync" Version="5.0.1" Publicize="true" PrivateAssets="all" Private="false" />
<PackageReference Include="AinaVT-LethalConfig" Version="1.4.6" PrivateAssets="all" Private="false" />
<PackageReference Include="TeamBMX.LobbyCompatibility" Version="1.*" PrivateAssets="all" Private="false" />
</ItemGroup>

View File

@ -19,17 +19,9 @@ using Unity.Netcode;
using UnityEngine;
using UnityEngine.Networking;
#if DEBUG
using CSync.Extensions;
using CSync.Lib;
#endif
namespace MuzikaGromche
{
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
#if DEBUG
[BepInDependency("com.sigurd.csync", "5.0.1")]
#endif
[BepInDependency("ainavt.lc.lethalconfig", "1.4.6")]
[BepInDependency("watergun.v72lightfix", BepInDependency.DependencyFlags.SoftDependency)]
[BepInDependency("BMX.LobbyCompatibility", BepInDependency.DependencyFlags.HardDependency)]
@ -1794,25 +1786,7 @@ namespace MuzikaGromche
readonly public int TotalWeights { get; }
}
#if DEBUG
static class SyncedEntryExtensions
{
// Update local values on clients. Even though the clients couldn't
// edit them, they could at least see the new values.
public static void SyncHostToLocal<T>(this SyncedEntry<T> entry)
{
entry.Changed += (sender, args) =>
{
args.ChangedEntry.LocalValue = args.NewValue;
};
}
}
#endif
class Config
#if DEBUG
: SyncedConfig2<Config>
#endif
{
public static ConfigEntry<bool> DisplayLyrics { get; private set; } = null!;
@ -1866,9 +1840,6 @@ namespace MuzikaGromche
#endif
internal Config(ConfigFile configFile)
#if DEBUG
: base(PluginInfo.PLUGIN_GUID)
#endif
{
DisplayLyrics = configFile.Bind("General", "Display Lyrics", true,
new ConfigDescription("Display lyrics in the HUD tooltip when you hear the music."));
@ -1936,10 +1907,6 @@ namespace MuzikaGromche
LethalConfigManager.AddConfigItem(new IntSliderConfigItem(track.Weight, Default(new IntSliderOptions())));
}
#if DEBUG
ConfigManager.Register(this);
#endif
}
internal static IAudioTrack OverrideCurrentTrack(IAudioTrack track)
@ -1952,16 +1919,6 @@ namespace MuzikaGromche
#endif
}
#if DEBUG
// HACK because CSync doesn't provide an API to register a list of config entries
// See https://github.com/lc-sigurd/CSync/issues/11
private void CSyncHackAddSyncedEntry(SyncedEntryBase entryBase)
{
// This is basically what ConfigFile.PopulateEntryContainer does
EntryContainer.Add(entryBase.BoxedEntry.ToSyncedEntryIdentifier(), entryBase);
}
#endif
public static CanModifyResult CanModifyIfHost()
{
var startOfRound = StartOfRound.Instance;
@ -1999,33 +1956,29 @@ namespace MuzikaGromche
#if DEBUG
private void SetupEntriesForExtrapolation(ConfigFile configFile)
{
var syncedEntry = configFile.BindSyncedEntry("General", "Extrapolate Audio Playback Time", true,
var entry = configFile.Bind("General", "Extrapolate Audio Playback Time", true,
new ConfigDescription("AudioSource only updates its playback position about 20 times per second.\n\nUse extrapolation technique to predict playback time between updates for smoother color animations."));
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(syncedEntry.Entry, Default(new BoolCheckBoxOptions())));
CSyncHackAddSyncedEntry(syncedEntry);
syncedEntry.Changed += (sender, args) => apply();
syncedEntry.SyncHostToLocal();
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(entry, Default(new BoolCheckBoxOptions())));
entry.SettingChanged += (sender, args) => apply();
apply();
void apply()
{
ExtrapolateTime = syncedEntry.Value;
ExtrapolateTime = entry.Value;
}
}
private void SetupEntriesToSkipWinding(ConfigFile configFile)
{
var syncedEntry = configFile.BindSyncedEntry("General", "Skip Winding Phase", false,
var entry = configFile.Bind("General", "Skip Winding Phase", false,
new ConfigDescription("Skip most of the wind-up/intro music.\n\nUse this option to test your Loop audio segment."));
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(syncedEntry.Entry, Default(new BoolCheckBoxOptions())));
CSyncHackAddSyncedEntry(syncedEntry);
syncedEntry.Changed += (sender, args) => apply();
syncedEntry.SyncHostToLocal();
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(entry, Default(new BoolCheckBoxOptions())));
entry.SettingChanged += (sender, args) => apply();
apply();
void apply()
{
ShouldSkipWindingPhase = syncedEntry.Value;
ShouldSkipWindingPhase = entry.Value;
}
}
@ -2034,31 +1987,27 @@ namespace MuzikaGromche
const string section = "Palette";
const int maxCustomPaletteSize = 8;
// Declare and initialize early to avoid "Use of unassigned local variable"
SyncedEntry<int> customPaletteSizeSyncedEntry = null!;
var customPaletteSyncedEntries = new SyncedEntry<string>[maxCustomPaletteSize];
ConfigEntry<int> customPaletteSizeEntry = null!;
var customPaletteEntries = new ConfigEntry<string>[maxCustomPaletteSize];
var loadButton = new GenericButtonConfigItem(section, "Load Palette from the Current Track",
"Override custom palette with the built-in palette of the current track.", "Load", load);
loadButton.ButtonOptions.CanModifyCallback = CanModifyIfHost;
LethalConfigManager.AddConfigItem(loadButton);
customPaletteSizeSyncedEntry = configFile.BindSyncedEntry(section, "Palette Size", 0, new ConfigDescription(
customPaletteSizeEntry = configFile.Bind(section, "Palette Size", 0, new ConfigDescription(
"Number of colors in the custom palette.\n\nIf set to non-zero, custom palette overrides track's own built-in palette.",
new AcceptableValueRange<int>(0, maxCustomPaletteSize)));
LethalConfigManager.AddConfigItem(new IntSliderConfigItem(customPaletteSizeSyncedEntry.Entry, Default(new IntSliderOptions())));
CSyncHackAddSyncedEntry(customPaletteSizeSyncedEntry);
customPaletteSizeSyncedEntry.Changed += (sender, args) => apply();
customPaletteSizeSyncedEntry.SyncHostToLocal();
LethalConfigManager.AddConfigItem(new IntSliderConfigItem(customPaletteSizeEntry, Default(new IntSliderOptions())));
customPaletteSizeEntry.SettingChanged += (sender, args) => apply();
for (int i = 0; i < maxCustomPaletteSize; i++)
{
string entryName = $"Custom Color {i + 1}";
var customColorSyncedEntry = configFile.BindSyncedEntry(section, entryName, "#FFFFFF", "Choose color for the custom palette");
customPaletteSyncedEntries[i] = customColorSyncedEntry;
LethalConfigManager.AddConfigItem(new HexColorInputFieldConfigItem(customColorSyncedEntry.Entry, Default(new HexColorInputFieldOptions())));
CSyncHackAddSyncedEntry(customColorSyncedEntry);
customColorSyncedEntry.Changed += (sender, args) => apply();
customColorSyncedEntry.SyncHostToLocal();
var customColorEntry = configFile.Bind(section, entryName, "#FFFFFF", "Choose color for the custom palette");
customPaletteEntries[i] = customColorEntry;
LethalConfigManager.AddConfigItem(new HexColorInputFieldConfigItem(customColorEntry, Default(new HexColorInputFieldOptions())));
customColorEntry.SettingChanged += (sender, args) => apply();
}
apply();
@ -2069,25 +2018,25 @@ namespace MuzikaGromche
var colors = palette.Colors;
var count = Math.Min(colors.Count(), maxCustomPaletteSize);
customPaletteSizeSyncedEntry.LocalValue = colors.Count();
customPaletteSizeEntry.Value = colors.Count();
for (int i = 0; i < maxCustomPaletteSize; i++)
{
var color = i < count ? colors[i] : Color.white;
string colorHex = $"#{ColorUtility.ToHtmlStringRGB(color)}";
customPaletteSyncedEntries[i].LocalValue = colorHex;
customPaletteEntries[i].Value = colorHex;
}
}
void apply()
{
int size = customPaletteSizeSyncedEntry.Value;
int size = customPaletteSizeEntry.Value;
if (size == 0 || size > maxCustomPaletteSize)
{
PaletteOverride = null;
}
else
{
var colors = customPaletteSyncedEntries.Select(entry => entry.Value).Take(size).ToArray();
var colors = customPaletteEntries.Select(entry => entry.Value).Take(size).ToArray();
PaletteOverride = Palette.Parse(colors);
}
}
@ -2099,93 +2048,89 @@ namespace MuzikaGromche
var colorTransitionRange = new AcceptableValueRange<float>(0f, 1f);
// Declare and initialize early to avoid "Use of unassigned local variable"
List<(Action<IAudioTrack?> Load, Action Apply)> entries = [];
SyncedEntry<bool> overrideTimingsSyncedEntry = null!;
SyncedEntry<float> fadeOutBeatSyncedEntry = null!;
SyncedEntry<float> fadeOutDurationSyncedEntry = null!;
SyncedEntry<string> flickerLightsTimeSeriesSyncedEntry = null!;
SyncedEntry<string> lyricsTimeSeriesSyncedEntry = null!;
SyncedEntry<float> beatsOffsetSyncedEntry = null!;
SyncedEntry<float> colorTransitionInSyncedEntry = null!;
SyncedEntry<float> colorTransitionOutSyncedEntry = null!;
SyncedEntry<string> colorTransitionEasingSyncedEntry = null!;
ConfigEntry<bool> overrideTimingsEntry = null!;
ConfigEntry<float> fadeOutBeatEntry = null!;
ConfigEntry<float> fadeOutDurationEntry = null!;
ConfigEntry<string> flickerLightsTimeSeriesEntry = null!;
ConfigEntry<string> lyricsTimeSeriesEntry = null!;
ConfigEntry<float> beatsOffsetEntry = null!;
ConfigEntry<float> colorTransitionInEntry = null!;
ConfigEntry<float> colorTransitionOutEntry = null!;
ConfigEntry<string> colorTransitionEasingEntry = null!;
var loadButton = new GenericButtonConfigItem(section, "Load Timings from the Current Track",
"Override custom timings with the built-in timings of the current track.", "Load", load);
loadButton.ButtonOptions.CanModifyCallback = CanModifyIfHost;
LethalConfigManager.AddConfigItem(loadButton);
overrideTimingsSyncedEntry = configFile.BindSyncedEntry(section, "Override Timings", false,
overrideTimingsEntry = configFile.Bind(section, "Override Timings", false,
new ConfigDescription("If checked, custom timings override track's own built-in timings."));
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(overrideTimingsSyncedEntry.Entry, Default(new BoolCheckBoxOptions())));
CSyncHackAddSyncedEntry(overrideTimingsSyncedEntry);
overrideTimingsSyncedEntry.Changed += (sender, args) => apply();
overrideTimingsSyncedEntry.SyncHostToLocal();
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(overrideTimingsEntry, Default(new BoolCheckBoxOptions())));
overrideTimingsEntry.SettingChanged += (sender, args) => apply();
fadeOutBeatSyncedEntry = configFile.BindSyncedEntry(section, "Fade Out Beat", 0f,
fadeOutBeatEntry = configFile.Bind(section, "Fade Out Beat", 0f,
new ConfigDescription("The beat at which to start fading out", new AcceptableValueRange<float>(-1000f, 0)));
fadeOutDurationSyncedEntry = configFile.BindSyncedEntry(section, "Fade Out Duration", 0f,
fadeOutDurationEntry = configFile.Bind(section, "Fade Out Duration", 0f,
new ConfigDescription("Duration of fading out", new AcceptableValueRange<float>(0, 10)));
flickerLightsTimeSeriesSyncedEntry = configFile.BindSyncedEntry(section, "Flicker Lights Time Series", "",
flickerLightsTimeSeriesEntry = configFile.Bind(section, "Flicker Lights Time Series", "",
new ConfigDescription("Time series of beat offsets when to flicker the lights."));
lyricsTimeSeriesSyncedEntry = configFile.BindSyncedEntry(section, "Lyrics Time Series", "",
lyricsTimeSeriesEntry = configFile.Bind(section, "Lyrics Time Series", "",
new ConfigDescription("Time series of beat offsets when to show lyrics lines."));
beatsOffsetSyncedEntry = configFile.BindSyncedEntry(section, "Beats Offset", 0f,
beatsOffsetEntry = configFile.Bind(section, "Beats Offset", 0f,
new ConfigDescription("How much to offset the whole beat. More is later", new AcceptableValueRange<float>(-0.5f, 0.5f)));
colorTransitionInSyncedEntry = configFile.BindSyncedEntry(section, "Color Transition In", 0.25f,
colorTransitionInEntry = configFile.Bind(section, "Color Transition In", 0.25f,
new ConfigDescription("Fraction of a beat *before* the whole beat when the color transition should start.", colorTransitionRange));
colorTransitionOutSyncedEntry = configFile.BindSyncedEntry(section, "Color Transition Out", 0.25f,
colorTransitionOutEntry = configFile.Bind(section, "Color Transition Out", 0.25f,
new ConfigDescription("Fraction of a beat *after* the whole beat when the color transition should end.", colorTransitionRange));
colorTransitionEasingSyncedEntry = configFile.BindSyncedEntry(section, "Color Transition Easing", Easing.Linear.Name,
colorTransitionEasingEntry = configFile.Bind(section, "Color Transition Easing", Easing.Linear.Name,
new ConfigDescription("Interpolation/easing method to use for color transitions", new AcceptableValueList<string>(Easing.AllNames)));
var floatSliderOptions = Default(new FloatSliderOptions());
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(fadeOutBeatSyncedEntry.Entry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(fadeOutDurationSyncedEntry.Entry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new TextInputFieldConfigItem(flickerLightsTimeSeriesSyncedEntry.Entry, Default(new TextInputFieldOptions())));
LethalConfigManager.AddConfigItem(new TextInputFieldConfigItem(lyricsTimeSeriesSyncedEntry.Entry, Default(new TextInputFieldOptions())));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(beatsOffsetSyncedEntry.Entry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionInSyncedEntry.Entry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionOutSyncedEntry.Entry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new TextDropDownConfigItem(colorTransitionEasingSyncedEntry.Entry, Default(new TextDropDownOptions())));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(fadeOutBeatEntry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(fadeOutDurationEntry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new TextInputFieldConfigItem(flickerLightsTimeSeriesEntry, Default(new TextInputFieldOptions())));
LethalConfigManager.AddConfigItem(new TextInputFieldConfigItem(lyricsTimeSeriesEntry, Default(new TextInputFieldOptions())));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(beatsOffsetEntry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionInEntry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionOutEntry, floatSliderOptions));
LethalConfigManager.AddConfigItem(new TextDropDownConfigItem(colorTransitionEasingEntry, Default(new TextDropDownOptions())));
registerStruct(fadeOutBeatSyncedEntry, t => t.FadeOutBeat, x => FadeOutBeatOverride = x);
registerStruct(fadeOutDurationSyncedEntry, t => t.FadeOutDuration, x => FadeOutDurationOverride = x);
registerArray(flickerLightsTimeSeriesSyncedEntry, t => t.FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = xs, float.Parse, sort: true);
registerArray(lyricsTimeSeriesSyncedEntry, t => t.LyricsTimeSeries, xs => LyricsTimeSeriesOverride = xs, float.Parse, sort: true);
registerStruct(beatsOffsetSyncedEntry, t => t.BeatsOffset, x => BeatsOffsetOverride = x);
registerStruct(colorTransitionInSyncedEntry, t => t.ColorTransitionIn, x => ColorTransitionInOverride = x);
registerStruct(colorTransitionOutSyncedEntry, t => t.ColorTransitionOut, x => ColorTransitionOutOverride = x);
registerClass(colorTransitionEasingSyncedEntry, t => t.ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x);
registerStruct(fadeOutBeatEntry, t => t.FadeOutBeat, x => FadeOutBeatOverride = x);
registerStruct(fadeOutDurationEntry, t => t.FadeOutDuration, x => FadeOutDurationOverride = x);
registerArray(flickerLightsTimeSeriesEntry, t => t.FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = xs, float.Parse, sort: true);
registerArray(lyricsTimeSeriesEntry, t => t.LyricsTimeSeries, xs => LyricsTimeSeriesOverride = xs, float.Parse, sort: true);
registerStruct(beatsOffsetEntry, t => t.BeatsOffset, x => BeatsOffsetOverride = x);
registerStruct(colorTransitionInEntry, t => t.ColorTransitionIn, x => ColorTransitionInOverride = x);
registerStruct(colorTransitionOutEntry, t => t.ColorTransitionOut, x => ColorTransitionOutOverride = x);
registerClass(colorTransitionEasingEntry, t => t.ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x);
void register<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action applier)
void register<T>(ConfigEntry<T> entry, Func<IAudioTrack, T> getter, Action applier)
{
CSyncHackAddSyncedEntry(syncedEntry);
syncedEntry.SyncHostToLocal();
syncedEntry.Changed += (sender, args) => applier();
entry.SettingChanged += (sender, args) => applier();
void loader(IAudioTrack? track)
{
// if track is null, set everything to defaults
syncedEntry.LocalValue = track == null ? (T)syncedEntry.Entry.DefaultValue : getter(track);
entry.Value = track == null ? (T)entry.DefaultValue : getter(track);
}
entries.Add((loader, applier));
}
void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : struct =>
register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null));
void registerClass<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : class =>
register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null));
void registerArray<T>(SyncedEntry<string> syncedEntry, Func<IAudioTrack, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct =>
register(syncedEntry,
void registerStruct<T>(ConfigEntry<T> entry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : struct =>
register(entry, getter, () => setter.Invoke(overrideTimingsEntry.Value ? entry.Value : null));
void registerClass<T>(ConfigEntry<T> entry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : class =>
register(entry, getter, () => setter.Invoke(overrideTimingsEntry.Value ? entry.Value : null));
void registerArray<T>(ConfigEntry<string> entry, Func<IAudioTrack, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct =>
register(entry,
(track) => string.Join(", ", getter(track)),
() =>
{
var values = parseStringArray(syncedEntry.Value, parser, sort);
var values = parseStringArray(entry.Value, parser, sort);
if (values != null)
{
// ensure the entry is sorted and formatted
syncedEntry.LocalValue = string.Join(", ", values);
entry.Value = string.Join(", ", values);
}
setter.Invoke(overrideTimingsSyncedEntry.Value ? values : null);
setter.Invoke(overrideTimingsEntry.Value ? values : null);
});
T[]? parseStringArray<T>(string str, Func<string, T> parser, bool sort = false) where T : struct

View File

@ -36,7 +36,6 @@ Any player can change their personal preferences locally.
1. Actually not limited to Inverse teleporter or Titan.
[`CSync`]: https://thunderstore.io/c/lethal-company/p/Sigurd/CSync/
[`LethalConfig`]: https://thunderstore.io/c/lethal-company/p/AinaVT/LethalConfig/
[`LobbyCompatibility`]: https://thunderstore.io/c/lethal-company/p/BMX/LobbyCompatibility/
[`V70PoweredLights_Fix`]: https://thunderstore.io/c/lethal-company/p/WaterGun/V70PoweredLights_Fix/