From 81b6bce360e769d7ad5f917a01e0f0289dc5ea72 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 04:50:24 +0000 Subject: [PATCH 01/70] clear trailing whitespace; add `UseGameLibs` property --- CSync/CSync.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CSync/CSync.csproj b/CSync/CSync.csproj index 6a15b57..dfd6c28 100644 --- a/CSync/CSync.csproj +++ b/CSync/CSync.csproj @@ -43,7 +43,7 @@ - + @@ -65,8 +65,8 @@ $(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll - - + + From 166ee1c1dda9506819a765ae73d450f7ba05505c Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:55:42 +0000 Subject: [PATCH 02/70] add synced entry delta message class --- CSync/Lib/SyncedConfigDefinition.cs | 54 +++++++++++++++++++++++++++++ CSync/Lib/SyncedEntryDelta.cs | 54 +++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 CSync/Lib/SyncedConfigDefinition.cs create mode 100644 CSync/Lib/SyncedEntryDelta.cs diff --git a/CSync/Lib/SyncedConfigDefinition.cs b/CSync/Lib/SyncedConfigDefinition.cs new file mode 100644 index 0000000..7a82114 --- /dev/null +++ b/CSync/Lib/SyncedConfigDefinition.cs @@ -0,0 +1,54 @@ +using System; +using BepInEx.Configuration; +using Unity.Collections; +using Unity.Netcode; + +namespace CSync.Lib; + +internal struct SyncedConfigDefinition : INetworkSerializable, System.IEquatable +{ + public FixedString128Bytes Section; + public FixedString128Bytes Key; + + public SyncedConfigDefinition(FixedString128Bytes section, FixedString128Bytes key) + { + Section = section; + Key = key; + } + + public readonly ConfigDefinition ToConfigDefinition() + { + return new ConfigDefinition(Section.Value, Key.Value); + } + + public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter + { + if (serializer.IsReader) + { + var reader = serializer.GetFastBufferReader(); + reader.ReadValueSafe(out Section); + reader.ReadValueSafe(out Key); + } + else + { + var writer = serializer.GetFastBufferWriter(); + writer.WriteValueSafe(Section); + writer.WriteValueSafe(Key); + } + } + + public bool Equals(SyncedConfigDefinition other) + { + return Section.Equals(other.Section) && Key.Equals(other.Key); + } + + public override bool Equals(object? obj) + { + return obj is SyncedConfigDefinition other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(Section, Key); + } +} diff --git a/CSync/Lib/SyncedEntryDelta.cs b/CSync/Lib/SyncedEntryDelta.cs new file mode 100644 index 0000000..0bb6658 --- /dev/null +++ b/CSync/Lib/SyncedEntryDelta.cs @@ -0,0 +1,54 @@ +using System; +using Unity.Collections; +using Unity.Netcode; + +namespace CSync.Lib; + +internal struct SyncedEntryDelta : INetworkSerializable, IEquatable +{ + public SyncedConfigDefinition Definition; + public FixedString128Bytes ConfigFileName; + public FixedString512Bytes SerializedValue; + + public SyncedEntryDelta(FixedString128Bytes configFileName, SyncedConfigDefinition definition, FixedString512Bytes serializedValue) + { + ConfigFileName = configFileName; + Definition = definition; + SerializedValue = serializedValue; + } + + public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter + { + if (serializer.IsReader) + { + serializer.SerializeValue(ref Definition); + + var reader = serializer.GetFastBufferReader(); + reader.ReadValueSafe(out ConfigFileName); + reader.ReadValueSafe(out SerializedValue); + } + else + { + serializer.SerializeValue(ref Definition); + + var writer = serializer.GetFastBufferWriter(); + writer.WriteValueSafe(ConfigFileName); + writer.WriteValueSafe(SerializedValue); + } + } + + public bool Equals(SyncedEntryDelta other) + { + return Definition.Equals(other.Definition) && ConfigFileName.Equals(other.ConfigFileName) && SerializedValue.Equals(other.SerializedValue); + } + + public override bool Equals(object? obj) + { + return obj is SyncedEntryDelta other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(Definition, ConfigFileName, SerializedValue); + } +} From 9b01c1dd77259fbf5ba446bdabfa9ad90839d5ae Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:56:00 +0000 Subject: [PATCH 03/70] wireframe behaviour class --- CSync/Lib/ConfigSyncBehaviour.cs | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 CSync/Lib/ConfigSyncBehaviour.cs diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs new file mode 100644 index 0000000..c94ab94 --- /dev/null +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -0,0 +1,34 @@ +using System; +using Unity.Netcode; + +namespace CSync.Lib; + +public class ConfigSyncBehaviour : NetworkBehaviour +{ + private NetworkVariable HostDisabledSync = new(); + private NetworkList Deltas; + + private void Awake() + { + Deltas = new NetworkList(); + } + + public override void OnNetworkSpawn() + { + if (IsServer) + { + HostDisabledSync.Value = false; // todo: use config value here + // todo: populate the list + } + + if (IsClient) + { + Deltas.OnListChanged += OnClientDeltaListChanged; + } + } + + private void OnClientDeltaListChanged(NetworkListEvent args) + { + throw new NotImplementedException(); + } +} From ce63a2f33ee5891ed6847a31bd28430b33bb5cc0 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:56:12 +0000 Subject: [PATCH 04/70] drop net framework --- CSync/CSync.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CSync/CSync.csproj b/CSync/CSync.csproj index dfd6c28..9600855 100644 --- a/CSync/CSync.csproj +++ b/CSync/CSync.csproj @@ -1,6 +1,6 @@ - netstandard2.1;net472;net48 + netstandard2.1 com.sigurd.csync Configuration file syncing library for BepInEx. @@ -47,6 +47,7 @@ + From a7a868e1ffe7566069687f19772292c190497821 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:56:48 +0000 Subject: [PATCH 05/70] fix the bind overloads and remove the shit one --- CSync/Util/Extensions.cs | 73 ++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/CSync/Util/Extensions.cs b/CSync/Util/Extensions.cs index 5bf2f5c..bc430ab 100644 --- a/CSync/Util/Extensions.cs +++ b/CSync/Util/Extensions.cs @@ -1,7 +1,5 @@ using BepInEx.Configuration; using CSync.Lib; -using System.Runtime.Serialization; -using Unity.Netcode; namespace CSync.Util; @@ -12,33 +10,47 @@ public static class Extensions { /// /// Binds an entry to this file and returns the converted synced entry. /// - /// The currently selected config file. + /// The currently selected config file. /// The category that this entry should show under. /// The name/identifier of this entry. /// The value assigned to this entry if not changed. - /// The description indicating what this entry does. - public static SyncedEntry BindSyncedEntry(this ConfigFile cfg, - string section, string key, V defaultVal, string desc + /// The description indicating what this entry does. + public static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + string section, + string key, + V defaultVal, + string description ) { - return cfg.Bind(section, key, defaultVal, desc).ToSyncedEntry(); + return configFile.BindSyncedEntry(new ConfigDefinition(section, key), defaultVal, new ConfigDescription(description)); } - public static SyncedEntry BindSyncedEntry(this ConfigFile cfg, - string section, string key, V defaultVal, ConfigDescription desc + public static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + string section, + string key, + V defaultValue, + ConfigDescription? desc = null ) { - return cfg.BindSyncedEntry(section, key, defaultVal, desc.Description); + return configFile.BindSyncedEntry(new ConfigDefinition(section, key), defaultValue, desc); } - public static SyncedEntry BindSyncedEntry(this ConfigFile cfg, - ConfigDefinition definition, T defaultValue, ConfigDescription desc = null + public static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + ConfigDefinition definition, + V defaultValue, + string description ) { - return cfg.BindSyncedEntry(definition.Section, definition.Key, defaultValue, desc.Description); + return configFile.BindSyncedEntry(definition, defaultValue, new ConfigDescription(description)); } - public static SyncedEntry BindSyncedEntry(this ConfigFile cfg, - ConfigDefinition definition, T defaultValue, string desc + public static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + ConfigDefinition definition, + V defaultValue, + ConfigDescription? description = null ) { - return cfg.BindSyncedEntry(definition.Section, definition.Key, defaultValue, desc); + return configFile.Bind(definition, defaultValue, description).ToSyncedEntry(); } /// @@ -47,31 +59,4 @@ public static SyncedEntry BindSyncedEntry(this ConfigFile cfg, public static SyncedEntry ToSyncedEntry(this ConfigEntry entry) { return new SyncedEntry(entry); } - - /// - /// Helper method to grab a value from SerializationInfo and cast it to the specified type. - /// - public static T GetObject(this SerializationInfo info, string key) { - return (T) info.GetValue(key, typeof(T)); - } - - internal static ConfigEntry Reconstruct(this ConfigFile cfg, SerializationInfo info) { - ConfigDefinition definition = new(info.GetString("Section"), info.GetString("Key")); - ConfigDescription description = new(info.GetString("Description")); - - return cfg.Bind(definition, info.GetObject("DefaultValue"), description); - } - - internal static void SendMessage(this FastBufferWriter stream, string guid, string label, ulong clientId = 0uL) { - bool fragment = stream.Capacity > 1300; - NetworkDelivery delivery = fragment ? NetworkDelivery.ReliableFragmentedSequenced : NetworkDelivery.Reliable; - - if (fragment) Plugin.Logger.LogDebug( - $"{guid} - Size of stream ({stream.Capacity}) was past the max buffer size.\n" + - "Config instance will be sent in fragments to avoid overflowing the buffer." - ); - - var msgManager = NetworkManager.Singleton.CustomMessagingManager; - msgManager.SendNamedMessage($"{guid}_{label}", clientId, stream, delivery); - } -} \ No newline at end of file +} From 7ef004412f51122dd3d25224ec26d5ba7daa705d Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:57:56 +0000 Subject: [PATCH 06/70] add config entry extensions --- CSync/Util/ConfigEntryExtensions.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 CSync/Util/ConfigEntryExtensions.cs diff --git a/CSync/Util/ConfigEntryExtensions.cs b/CSync/Util/ConfigEntryExtensions.cs new file mode 100644 index 0000000..b3dd70c --- /dev/null +++ b/CSync/Util/ConfigEntryExtensions.cs @@ -0,0 +1,12 @@ +using BepInEx.Configuration; +using CSync.Lib; + +namespace CSync.Util; + +internal static class ConfigEntryExtensions +{ + internal static SyncedConfigDefinition ToSynced(this ConfigDefinition definition) + { + return new(definition.Section, definition.Key); + } +} From 81234828640bfd8aaf6cc7808893481672d42e88 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:58:26 +0000 Subject: [PATCH 07/70] rename `Extensions` --- CSync/Util/{Extensions.cs => SyncedBindingExtensions.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename CSync/Util/{Extensions.cs => SyncedBindingExtensions.cs} (97%) diff --git a/CSync/Util/Extensions.cs b/CSync/Util/SyncedBindingExtensions.cs similarity index 97% rename from CSync/Util/Extensions.cs rename to CSync/Util/SyncedBindingExtensions.cs index bc430ab..b104e11 100644 --- a/CSync/Util/Extensions.cs +++ b/CSync/Util/SyncedBindingExtensions.cs @@ -6,7 +6,7 @@ namespace CSync.Util; /// /// Contains helpful extension methods to aid with synchronization and reduce code duplication. /// -public static class Extensions { +public static class SyncedBindingExtensions { /// /// Binds an entry to this file and returns the converted synced entry. /// From 21f8ae950e9f888448b5c952f5b4f7bcfec90ced Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:58:42 +0000 Subject: [PATCH 08/70] don't `Init` (for now) --- CSync/Lib/ConfigManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 44f476b..da6600a 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -42,7 +42,7 @@ public static void Register(T config) where T : SyncedConfig, ISynchroniza return; } - config.InitInstance(config); + //config.InitInstance(config); Instances.Add(guid, config); } @@ -53,4 +53,4 @@ public static void Register(T config) where T : SyncedConfig, ISynchroniza public interface ISynchronizable { void SetupSync(); void RevertSync(); -} \ No newline at end of file +} From 552b605e8feee7ca65c68f87c7cb543b5683ca01 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:58:56 +0000 Subject: [PATCH 09/70] fix the synced entry --- CSync/Lib/SyncedEntry.cs | 60 +++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/CSync/Lib/SyncedEntry.cs b/CSync/Lib/SyncedEntry.cs index 23dd347..f9b8886 100644 --- a/CSync/Lib/SyncedEntry.cs +++ b/CSync/Lib/SyncedEntry.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Runtime.Serialization; using BepInEx.Configuration; using CSync.Util; @@ -10,19 +9,24 @@ namespace CSync.Lib; /// Wrapper class around a BepInEx .
/// Can serialize and deserialize itself to avoid runtime errors when syncing configs.
///
-[Serializable] -public class SyncedEntry : ISerializable { - [NonSerialized] public readonly ConfigEntry Entry; +public class SyncedEntry +{ + public ConfigEntry Entry { get; } - string ConfigFileName => Path.GetFileName(Entry.ConfigFile.ConfigFilePath); - public string Key => Entry.Definition.Key; - public string Section => Entry.Definition.Section; - public string Description => Entry.Description.Description; - public object DefaultValue => Entry.DefaultValue; + public V LocalValue + { + get => Entry.Value; + set => Entry.Value = value!; + } + + protected V _valueOverride; + protected bool _valueOverridden; public V Value { - get => Entry.Value; - set => Entry.Value = value; + get { + if (_valueOverridden) return _valueOverride; + return LocalValue; + } } public static implicit operator V(SyncedEntry e) => e.Value; @@ -32,32 +36,18 @@ public event EventHandler SettingChanged { remove => Entry.SettingChanged -= value; } - public SyncedEntry(ConfigEntry cfgEntry) { - Entry = cfgEntry; - } - - // Deserialization - SyncedEntry(SerializationInfo info, StreamingContext ctx) { - // Reconstruct or get cached file - string fileName = info.GetString("ConfigFileName"); - ConfigFile cfg = ConfigManager.GetConfigFile(fileName); - - // Reconstruct entry and reassign its value. - Entry = cfg.Reconstruct(info); - Value = info.GetObject("CurrentValue"); - } - - // Serialization - public void GetObjectData(SerializationInfo info, StreamingContext context) { - info.AddValue("ConfigFileName", ConfigFileName); - info.AddValue("Key", Key); - info.AddValue("Section", Section); - info.AddValue("Description", Description); - info.AddValue("DefaultValue", DefaultValue); - info.AddValue("CurrentValue", Value); + public SyncedEntry(ConfigEntry entry) + { + Entry = entry; } public override string ToString() { - return $"Key: {Key}\nDefault Value: {DefaultValue}\nCurrent Value: {Value}"; + return $"Key: {Entry.Definition.Key}\nLocal Value: {LocalValue}\nCurrent Value: {Value}"; } + + internal SyncedEntryDelta ToDelta() => new SyncedEntryDelta( + configFileName: Path.GetFileName(Entry.ConfigFile.ConfigFilePath), + definition: Entry.Definition.ToSynced(), + serializedValue: TomlTypeConverter.ConvertToString(LocalValue, typeof(V)) + ); } From 067abe539393f1206cf6805d1faa8ed363e9a919 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:59:12 +0000 Subject: [PATCH 10/70] take out all the cruft --- CSync/Lib/SyncedConfig.cs | 92 ++++-------------------------------- CSync/Lib/SyncedInstance.cs | 63 ------------------------ CSync/Util/ByteSerializer.cs | 35 -------------- 3 files changed, 10 insertions(+), 180 deletions(-) delete mode 100644 CSync/Lib/SyncedInstance.cs delete mode 100644 CSync/Util/ByteSerializer.cs diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index b8eac1c..e29d7ae 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -1,8 +1,4 @@ using System; -using Unity.Collections; -using Unity.Netcode; - -using CSync.Util; namespace CSync.Lib; @@ -10,21 +6,21 @@ namespace CSync.Lib; /// Wrapper class allowing the config class (type parameter) to be synchronized.

/// Stores the mod's unique identifier and handles registering and sending of named messages. /// -[Serializable] -public class SyncedConfig(string guid) : SyncedInstance, ISynchronizable where T : class { +public class SyncedConfig(string guid) : ISynchronizable where T : class +{ static void LogErr(string str) => Plugin.Logger.LogError(str); static void LogDebug(string str) => Plugin.Logger.LogDebug(str); /// /// Invoked on the host when a client requests to sync. /// - [field:NonSerialized] public event EventHandler SyncRequested; + public event EventHandler? SyncRequested; internal void OnSyncRequested() => SyncRequested?.Invoke(this, EventArgs.Empty); /// /// Invoked on the client when they receive the host config. /// - [field:NonSerialized] public event EventHandler SyncReceived; + public event EventHandler? SyncReceived; internal void OnSyncReceived() => SyncReceived?.Invoke(this, EventArgs.Empty); /// @@ -47,81 +43,13 @@ protected void EnableHostSyncControl(SyncedEntry hostSyncControlOption) { }; } - void ISynchronizable.SetupSync() { - if (IsHost) { - MessageManager.RegisterNamedMessageHandler($"{GUID}_OnRequestConfigSync", OnRequestSync); - return; - } - - MessageManager.RegisterNamedMessageHandler($"{GUID}_OnHostDisabledSyncing", OnHostDisabledSyncing); - MessageManager.RegisterNamedMessageHandler($"{GUID}_OnReceiveConfigSync", OnReceiveSync); - RequestSync(); - } - - void RequestSync() { - if (!IsClient) return; - - using FastBufferWriter stream = new(IntSize, Allocator.Temp); - - // Method `OnRequestSync` will then get called on the host. - stream.SendMessage(GUID, "OnRequestConfigSync"); - } - - internal void OnRequestSync(ulong clientId, FastBufferReader _) { - if (!IsHost) return; - OnSyncRequested(); - - if (SYNC_TO_CLIENTS != null && SYNC_TO_CLIENTS == false) { - using FastBufferWriter s = new(IntSize, Allocator.Temp); - s.SendMessage(GUID, "OnHostDisabledSyncing", clientId); - - LogDebug($"{GUID} - The host (you) has disabled syncing, sending clients a message!"); - return; - } - - LogDebug($"{GUID} - Config sync request received from client: {clientId}"); - - byte[] array = SerializeToBytes(Instance); - int value = array.Length; - - using FastBufferWriter stream = new(value + IntSize, Allocator.Temp); - - try { - stream.WriteValueSafe(in value, default); - stream.WriteBytesSafe(array); - - stream.SendMessage(GUID, "OnReceiveConfigSync", clientId); - } catch(Exception e) { - LogErr($"{GUID} - Error occurred syncing config with client: {clientId}\n{e}"); - } - } - - internal void OnReceiveSync(ulong _, FastBufferReader reader) { - OnSyncReceived(); - - if (!reader.TryBeginRead(IntSize)) { - LogErr($"{GUID} - Config sync error: Could not begin reading buffer."); - return; - } - - reader.ReadValueSafe(out int val, default); - if (!reader.TryBeginRead(val)) { - LogErr($"{GUID} - Config sync error: Host could not sync."); - return; - } - - byte[] data = new byte[val]; - reader.ReadBytesSafe(ref data, val); - - try { - SyncInstance(data); - } catch(Exception e) { - LogErr($"Error syncing config instance!\n{e}"); - } + public void SetupSync() + { + throw new NotImplementedException(); } - internal void OnHostDisabledSyncing(ulong _, FastBufferReader reader) { - OnSyncCompleted(); - LogDebug($"{GUID} - Host disabled syncing. The SyncComplete event will still be invoked."); + public void RevertSync() + { + throw new NotImplementedException(); } } diff --git a/CSync/Lib/SyncedInstance.cs b/CSync/Lib/SyncedInstance.cs deleted file mode 100644 index d16457f..0000000 --- a/CSync/Lib/SyncedInstance.cs +++ /dev/null @@ -1,63 +0,0 @@ -using CSync.Util; -using System; -using Unity.Netcode; - -namespace CSync.Lib; - -/// -/// Generic class that can be serialized to bytes.

-/// Handles syncing and reverting as well as holding references to the client-side and synchronized instances.

-///



-/// This class should always be inherited from, never use it directly! -///
-[Serializable] -public class SyncedInstance : ByteSerializer where T : class { - public static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager; - public static bool IsClient => NetworkManager.Singleton.IsClient; - public static bool IsHost => NetworkManager.Singleton.IsHost; - - /// - /// The instance of the class used to fall back to when reverting.

- /// All of the properties on this instance are unsynced and always the same. - ///
- public static T Default { get; private set; } - - /// - /// The current instance of the class.

- /// Properties contained in this instance can be synchronized. - ///
- public static T Instance { get; private set; } - - /// - /// Invoked when deserialization of data has finished and is assigned to. - /// - [field:NonSerialized] public event EventHandler SyncComplete; - internal void OnSyncCompleted() => SyncComplete?.Invoke(this, EventArgs.Empty); - - /// - /// Invoked when is set back to and no longer synced. - /// - [field:NonSerialized] public event EventHandler SyncReverted; - internal void OnSyncReverted() => SyncReverted?.Invoke(this, EventArgs.Empty); - - public static bool Synced; - - public void InitInstance(T instance) { - Default = instance; - Instance = instance; - } - - public void SyncInstance(byte[] data) { - Instance = DeserializeFromBytes(data); - Synced = Instance != default(T); - - OnSyncCompleted(); - } - - public void RevertSync() { - Instance = Default; - Synced = false; - - OnSyncReverted(); - } -} \ No newline at end of file diff --git a/CSync/Util/ByteSerializer.cs b/CSync/Util/ByteSerializer.cs deleted file mode 100644 index 6671f33..0000000 --- a/CSync/Util/ByteSerializer.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.IO; -using System; -using System.Runtime.Serialization; - -namespace CSync.Util; - -/// -/// Responsible for serializing to and from bytes via a .

-/// Uses as a fast and safer alternative to BinaryFormatter. -///
-[Serializable] -public class ByteSerializer { - [NonSerialized] - static readonly DataContractSerializer Serializer = new(typeof(T)); - - // Ensures the size of an integer is correct for the current system. - public static int IntSize => sizeof(int); - - public static byte[] SerializeToBytes(T val) { - using MemoryStream stream = new(); - - Serializer.WriteObject(stream, val); - return stream.ToArray(); - } - - public static T DeserializeFromBytes(byte[] data) { - using MemoryStream stream = new(data); - - try { - return (T) Serializer.ReadObject(stream); - } catch (Exception) { - return default; - } - } -} \ No newline at end of file From 3208635937896e4c341daa96898fad87a582effd Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Wed, 27 Mar 2024 22:05:18 +0000 Subject: [PATCH 11/70] remove redundant qualifier --- CSync/Lib/SyncedConfigDefinition.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/SyncedConfigDefinition.cs b/CSync/Lib/SyncedConfigDefinition.cs index 7a82114..65c6ca3 100644 --- a/CSync/Lib/SyncedConfigDefinition.cs +++ b/CSync/Lib/SyncedConfigDefinition.cs @@ -5,7 +5,7 @@ namespace CSync.Lib; -internal struct SyncedConfigDefinition : INetworkSerializable, System.IEquatable +internal struct SyncedConfigDefinition : INetworkSerializable, IEquatable { public FixedString128Bytes Section; public FixedString128Bytes Key; From 88971b589c72019b5420eaede5cb2cf25372fc7b Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:57:46 +0000 Subject: [PATCH 12/70] add netcodepatcher cli to tool manifest --- .config/dotnet-tools.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 6864ceb..3bb77b1 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -7,6 +7,12 @@ "commands": [ "tcli" ] + }, + "evaisa.netcodepatcher.cli": { + "version": "4.1.0", + "commands": [ + "netcode-patch" + ] } } } \ No newline at end of file From 723a8e6edf10d98893cd2c3e2f6bee05140168c3 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:58:02 +0000 Subject: [PATCH 13/70] add netcode patch target --- Directory.Build.targets | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 48c7dae..09b8185 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -13,4 +13,8 @@ $(MinVerMajor).$(MinVerMinor).$(MinVerPatch) - \ No newline at end of file + + + + + From 2b61f0a3a60cde90bce914c88e76201f5d9c352e Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:58:19 +0000 Subject: [PATCH 14/70] ensure netcode patch target completes before thunderstore pack --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index ed13220..25a5914 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -65,6 +65,7 @@ all + From f896d4fa01cd17dda62ec84623c33c376e6eeebd Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:58:35 +0000 Subject: [PATCH 15/70] publicize netcode so I can set `globalObjectIdHash` --- CSync/CSync.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CSync/CSync.csproj b/CSync/CSync.csproj index 9600855..b7e12fc 100644 --- a/CSync/CSync.csproj +++ b/CSync/CSync.csproj @@ -47,6 +47,7 @@ + @@ -62,12 +63,12 @@ $(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Collections.dll - + $(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll - + From f171cef2ab44b323da58259f46d63e2b27610c92 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:58:45 +0000 Subject: [PATCH 16/70] remove redundant patches --- CSync/Patches/JoinPatch.cs | 14 -------------- CSync/Patches/LeavePatch.cs | 13 ------------- 2 files changed, 27 deletions(-) delete mode 100644 CSync/Patches/JoinPatch.cs delete mode 100644 CSync/Patches/LeavePatch.cs diff --git a/CSync/Patches/JoinPatch.cs b/CSync/Patches/JoinPatch.cs deleted file mode 100644 index 8fb700d..0000000 --- a/CSync/Patches/JoinPatch.cs +++ /dev/null @@ -1,14 +0,0 @@ -using CSync.Lib; -using GameNetcodeStuff; -using HarmonyLib; - -namespace CSync.Patches; - -[HarmonyPatch(typeof(PlayerControllerB))] -internal class JoinPatch { - [HarmonyPostfix] - [HarmonyPatch("ConnectClientToPlayerObject")] - private static void SyncOnJoin() { - ConfigManager.SyncInstances(); - } -} diff --git a/CSync/Patches/LeavePatch.cs b/CSync/Patches/LeavePatch.cs deleted file mode 100644 index e71e3c9..0000000 --- a/CSync/Patches/LeavePatch.cs +++ /dev/null @@ -1,13 +0,0 @@ -using CSync.Lib; -using HarmonyLib; - -namespace CSync.Patches; - -[HarmonyPatch(typeof(GameNetworkManager))] -internal class LeavePatch { - [HarmonyPostfix] - [HarmonyPatch("StartDisconnect")] - private static void RevertOnDisconnect() { - ConfigManager.RevertSyncedInstances(); - } -} \ No newline at end of file From 3f791eb48582317f349ac5a0b8c6bf6181c96261 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:59:35 +0000 Subject: [PATCH 17/70] sort ordering of modifiers and fake not-null --- CSync/Plugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Plugin.cs b/CSync/Plugin.cs index b2ff2fc..34d1a33 100644 --- a/CSync/Plugin.cs +++ b/CSync/Plugin.cs @@ -14,7 +14,7 @@ namespace CSync; ///
[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] public class Plugin : BaseUnityPlugin { - internal static new ManualLogSource Logger { get; private set; } + internal new static ManualLogSource Logger { get; private set; } = null!; Harmony Patcher; From b464c5e85204b5a41803fd898011341097053fb5 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:59:46 +0000 Subject: [PATCH 18/70] make harmony internal + fake notnull --- CSync/Plugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Plugin.cs b/CSync/Plugin.cs index 34d1a33..29da868 100644 --- a/CSync/Plugin.cs +++ b/CSync/Plugin.cs @@ -16,7 +16,7 @@ namespace CSync; public class Plugin : BaseUnityPlugin { internal new static ManualLogSource Logger { get; private set; } = null!; - Harmony Patcher; + internal static Harmony Patcher = null!; private void Awake() { Logger = base.Logger; From 377c2f7cd33cb9847193ff7b2cf1b9c51fcae450 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:00:24 +0000 Subject: [PATCH 19/70] use `RelativePath` instead of `Name` --- CSync/Lib/SyncedEntryDelta.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CSync/Lib/SyncedEntryDelta.cs b/CSync/Lib/SyncedEntryDelta.cs index 0bb6658..5ff2551 100644 --- a/CSync/Lib/SyncedEntryDelta.cs +++ b/CSync/Lib/SyncedEntryDelta.cs @@ -7,12 +7,12 @@ namespace CSync.Lib; internal struct SyncedEntryDelta : INetworkSerializable, IEquatable { public SyncedConfigDefinition Definition; - public FixedString128Bytes ConfigFileName; + public FixedString128Bytes ConfigFileRelativePath; public FixedString512Bytes SerializedValue; - public SyncedEntryDelta(FixedString128Bytes configFileName, SyncedConfigDefinition definition, FixedString512Bytes serializedValue) + public SyncedEntryDelta(FixedString128Bytes configFileRelativePath, SyncedConfigDefinition definition, FixedString512Bytes serializedValue) { - ConfigFileName = configFileName; + ConfigFileRelativePath = configFileRelativePath; Definition = definition; SerializedValue = serializedValue; } @@ -24,7 +24,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade serializer.SerializeValue(ref Definition); var reader = serializer.GetFastBufferReader(); - reader.ReadValueSafe(out ConfigFileName); + reader.ReadValueSafe(out ConfigFileRelativePath); reader.ReadValueSafe(out SerializedValue); } else @@ -32,14 +32,14 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade serializer.SerializeValue(ref Definition); var writer = serializer.GetFastBufferWriter(); - writer.WriteValueSafe(ConfigFileName); + writer.WriteValueSafe(ConfigFileRelativePath); writer.WriteValueSafe(SerializedValue); } } public bool Equals(SyncedEntryDelta other) { - return Definition.Equals(other.Definition) && ConfigFileName.Equals(other.ConfigFileName) && SerializedValue.Equals(other.SerializedValue); + return Definition.Equals(other.Definition) && ConfigFileRelativePath.Equals(other.ConfigFileRelativePath) && SerializedValue.Equals(other.SerializedValue); } public override bool Equals(object? obj) @@ -49,6 +49,6 @@ public override bool Equals(object? obj) public override int GetHashCode() { - return HashCode.Combine(Definition, ConfigFileName, SerializedValue); + return HashCode.Combine(Definition, ConfigFileRelativePath, SerializedValue); } } From a31819d17f15f64bc9d30d9d98b3115ef022278b Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:00:35 +0000 Subject: [PATCH 20/70] add synced entry container --- CSync/Lib/SyncedEntryContainer.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CSync/Lib/SyncedEntryContainer.cs diff --git a/CSync/Lib/SyncedEntryContainer.cs b/CSync/Lib/SyncedEntryContainer.cs new file mode 100644 index 0000000..5fdcbd9 --- /dev/null +++ b/CSync/Lib/SyncedEntryContainer.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace CSync.Lib; + +public class SyncedEntryContainer : Dictionary<(string ConfigFileRelativePath, SyncedConfigDefinition Definition), SyncedEntryBase>, ISyncedEntryContainer +{ + public bool TryGetEntry(string configFileRelativePath, SyncedConfigDefinition configDefinition, [MaybeNullWhen(false)] out SyncedEntry entry) + { + if (TryGetValue((configFileRelativePath, configDefinition), out var entryBase)) + { + entry = (SyncedEntry)entryBase; + return true; + } + + entry = null; + return false; + } + + public bool TryGetEntry(string configFileRelativePath, string section, string key, [MaybeNullWhen(false)] out SyncedEntry entry) + { + return TryGetEntry(configFileRelativePath, new SyncedConfigDefinition(section, key), out entry); + } +} From 08b161210c01f95624283a31bfeb56f268c3e8a1 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:00:44 +0000 Subject: [PATCH 21/70] add synced entry base class --- CSync/Lib/SyncedEntryBase.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 CSync/Lib/SyncedEntryBase.cs diff --git a/CSync/Lib/SyncedEntryBase.cs b/CSync/Lib/SyncedEntryBase.cs new file mode 100644 index 0000000..d5aa31e --- /dev/null +++ b/CSync/Lib/SyncedEntryBase.cs @@ -0,0 +1,30 @@ +using System.IO; +using BepInEx.Configuration; +using CSync.Util; + +namespace CSync.Lib; + +public abstract class SyncedEntryBase +{ + public abstract ConfigEntryBase BoxedEntry { get; protected init; } + + public abstract object? BoxedValueOverride { get; set; } + protected internal bool ValueOverridden = false; + + internal SyncedEntryBase(ConfigEntryBase configEntry) + { + BoxedEntry = configEntry; + BoxedValueOverride = configEntry.DefaultValue; + } + + public void SetSerializedValueOverride(string value) + { + BoxedValueOverride = TomlTypeConverter.ConvertToValue(value, BoxedEntry.SettingType); + } + + internal SyncedEntryDelta ToDelta() => new SyncedEntryDelta( + configFileRelativePath: Path.GetFileName(BoxedEntry.ConfigFile.ConfigFilePath), + definition: BoxedEntry.Definition.ToSynced(), + serializedValue: BoxedEntry.GetSerializedValue() + ); +} From 29726b27b8c563893df64070872cbdd284b13687 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:00:58 +0000 Subject: [PATCH 22/70] inherit from the baseclass + do some wacky stuff --- CSync/Lib/SyncedEntry.cs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/CSync/Lib/SyncedEntry.cs b/CSync/Lib/SyncedEntry.cs index f9b8886..0226821 100644 --- a/CSync/Lib/SyncedEntry.cs +++ b/CSync/Lib/SyncedEntry.cs @@ -1,7 +1,5 @@ using System; -using System.IO; using BepInEx.Configuration; -using CSync.Util; namespace CSync.Lib; @@ -9,45 +7,47 @@ namespace CSync.Lib; /// Wrapper class around a BepInEx .
/// Can serialize and deserialize itself to avoid runtime errors when syncing configs.
/// -public class SyncedEntry +public sealed class SyncedEntry : SyncedEntryBase { - public ConfigEntry Entry { get; } + public ConfigEntry Entry { get; private set; } - public V LocalValue + public override ConfigEntryBase BoxedEntry + { + get => Entry; + protected init => Entry = (ConfigEntry) value; + } + + public T LocalValue { get => Entry.Value; set => Entry.Value = value!; } - protected V _valueOverride; - protected bool _valueOverridden; + private T _typedValueOverride; - public V Value { + public override object? BoxedValueOverride + { + get => _typedValueOverride; + set => _typedValueOverride = (T) value!; + } + + public T Value { get { - if (_valueOverridden) return _valueOverride; + if (ValueOverridden) return _typedValueOverride!; return LocalValue; } } - public static implicit operator V(SyncedEntry e) => e.Value; + public static implicit operator T(SyncedEntry e) => e.Value; public event EventHandler SettingChanged { add => Entry.SettingChanged += value; remove => Entry.SettingChanged -= value; } - public SyncedEntry(ConfigEntry entry) - { - Entry = entry; - } + public SyncedEntry(ConfigEntry entry) : base(entry) { } public override string ToString() { return $"Key: {Entry.Definition.Key}\nLocal Value: {LocalValue}\nCurrent Value: {Value}"; } - - internal SyncedEntryDelta ToDelta() => new SyncedEntryDelta( - configFileName: Path.GetFileName(Entry.ConfigFile.ConfigFilePath), - definition: Entry.Definition.ToSynced(), - serializedValue: TomlTypeConverter.ConvertToString(LocalValue, typeof(V)) - ); } From 8a4650fcf6ab838c4850408d4bfc089d16a1b543 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:01:23 +0000 Subject: [PATCH 23/70] make struct public --- CSync/Lib/SyncedConfigDefinition.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CSync/Lib/SyncedConfigDefinition.cs b/CSync/Lib/SyncedConfigDefinition.cs index 65c6ca3..25079fe 100644 --- a/CSync/Lib/SyncedConfigDefinition.cs +++ b/CSync/Lib/SyncedConfigDefinition.cs @@ -1,11 +1,10 @@ using System; -using BepInEx.Configuration; using Unity.Collections; using Unity.Netcode; namespace CSync.Lib; -internal struct SyncedConfigDefinition : INetworkSerializable, IEquatable +public struct SyncedConfigDefinition : INetworkSerializable, IEquatable { public FixedString128Bytes Section; public FixedString128Bytes Key; @@ -16,11 +15,6 @@ public SyncedConfigDefinition(FixedString128Bytes section, FixedString128Bytes k Key = key; } - public readonly ConfigDefinition ToConfigDefinition() - { - return new ConfigDefinition(Section.Value, Key.Value); - } - public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { if (serializer.IsReader) From 5ec7cfcbc31d527989201da5573d76028e998bda Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:01:35 +0000 Subject: [PATCH 24/70] add `ISyncedConfig` --- CSync/Lib/ISyncedConfig.cs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 CSync/Lib/ISyncedConfig.cs diff --git a/CSync/Lib/ISyncedConfig.cs b/CSync/Lib/ISyncedConfig.cs new file mode 100644 index 0000000..7081bb1 --- /dev/null +++ b/CSync/Lib/ISyncedConfig.cs @@ -0,0 +1,8 @@ +namespace CSync.Lib; + +public interface ISyncedConfig +{ + public string GUID { get; } + + public ISyncedEntryContainer EntryContainer { get; } +} From 74bb6340c37cfd95d73ddfaa71f2110fb4bcee26 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:01:46 +0000 Subject: [PATCH 25/70] add `ISyncedEntryContainer` --- CSync/Lib/ISyncedEntryContainer.cs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CSync/Lib/ISyncedEntryContainer.cs diff --git a/CSync/Lib/ISyncedEntryContainer.cs b/CSync/Lib/ISyncedEntryContainer.cs new file mode 100644 index 0000000..224b425 --- /dev/null +++ b/CSync/Lib/ISyncedEntryContainer.cs @@ -0,0 +1,5 @@ +using System.Collections.Generic; + +namespace CSync.Lib; + +public interface ISyncedEntryContainer : IDictionary<(string ConfigFileRelativePath, SyncedConfigDefinition Definition), SyncedEntryBase>; From fc822cb89ada6e3372be2991821e4d73a8da60f3 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:02:23 +0000 Subject: [PATCH 26/70] make a prefab, do nice stuff with the config file cache --- CSync/Lib/ConfigManager.cs | 84 +++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index da6600a..318cbd9 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -1,8 +1,13 @@ +using System; using BepInEx.Configuration; using BepInEx; using System.Collections.Generic; using System.IO; -using HarmonyLib; +using System.Security.Cryptography; +using System.Text; +using CSync.Util; +using Unity.Netcode; +using UnityEngine; namespace CSync.Lib; @@ -11,46 +16,69 @@ namespace CSync.Lib; /// Handles config registration, instance syncing and caching of BepInEx files.

/// public class ConfigManager { - internal static Dictionary FileCache = []; - internal static Dictionary Instances = []; + internal static readonly Dictionary FileCache = []; + internal static readonly Dictionary Instances = []; - internal static ConfigFile GetConfigFile(string fileName) { - bool exists = FileCache.TryGetValue(fileName, out ConfigFile cfg); - if (!exists) { - string absPath = Path.Combine(Paths.ConfigPath, fileName); + private static readonly Lazy LazyPrefab; + internal static GameObject Prefab => LazyPrefab.Value; - cfg = new(absPath, false); - FileCache.Add(fileName, cfg); - } + static ConfigManager() + { + LazyPrefab = new Lazy(() => + { + var container = new GameObject("CSyncPrefabContainer") + { + hideFlags = HideFlags.HideAndDontSave + }; + container.SetActive(false); + UnityEngine.Object.DontDestroyOnLoad(container); + + var prefab = new GameObject("ConfigSyncHolder"); + prefab.transform.SetParent(container.transform); + var networkObject = prefab.AddComponent(); + var hash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes($"{MyPluginInfo.PLUGIN_GUID}:ConfigSyncHolder")); + networkObject.GlobalObjectIdHash = BitConverter.ToUInt32(hash); + + return prefab; + }); + } + + internal static void AddToFileCache(ConfigFile configFile) + { + FileCache.TryAdd(configFile.GetConfigFileRelativePath(), configFile); + } + + internal static ConfigFile GetConfigFile(string relativePath) + { + if (FileCache.TryGetValue(relativePath, out ConfigFile configFile)) + return configFile; - return cfg; + string absolutePath = Path.GetFullPath(Path.Combine(Paths.BepInExRootPath, relativePath)); + configFile = new(absolutePath, false); + FileCache.Add(relativePath, configFile); + return configFile; } /// /// Register a config with CSync, making it responsible for synchronization.

/// After calling this method, all clients will receive the host's config upon joining. ///
- public static void Register(T config) where T : SyncedConfig, ISynchronizable { + public static void Register(T config) where T : SyncedConfig { + if (config is null) + { + throw new ArgumentNullException(nameof(config), "Config instance is null, cannot register."); + } + string guid = config.GUID; - if (config == null) { - Plugin.Logger.LogError($"An error occurred registering config: {guid}\nConfig instance cannot be null!"); + try { + Instances.Add(guid, config); } - - if (Instances.ContainsKey(guid)) { - Plugin.Logger.LogWarning($"Attempted to register config `{guid}` after it has already been registered!"); - return; + catch (ArgumentException exc) { + throw new InvalidOperationException($"Attempted to register config `{guid}`, but it has already been registered.", exc); } - //config.InitInstance(config); - Instances.Add(guid, config); + var syncBehaviour = Prefab.AddComponent(); + syncBehaviour.Config = config; } - - internal static void SyncInstances() => Instances.Values.Do(i => i.SetupSync()); - internal static void RevertSyncedInstances() => Instances.Values.Do(i => i.RevertSync()); -} - -public interface ISynchronizable { - void SetupSync(); - void RevertSync(); } From 28eaa5156b718fb00c9363293d7f62974da54843 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:02:52 +0000 Subject: [PATCH 27/70] complete implementation of sync behaviour --- CSync/Lib/ConfigSyncBehaviour.cs | 151 +++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 7 deletions(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index c94ab94..0de84d5 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -1,34 +1,171 @@ using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Unity.Netcode; +using UnityEngine; +using LogLevel = BepInEx.Logging.LogLevel; namespace CSync.Lib; public class ConfigSyncBehaviour : NetworkBehaviour { - private NetworkVariable HostDisabledSync = new(); - private NetworkList Deltas; + [SerializeField] + internal ISyncedConfig? Config; + + private ISyncedEntryContainer? _entryContainer; + internal ISyncedEntryContainer? EntryContainer => _entryContainer ??= Config?.EntryContainer; + + public bool SyncEnabled + { + get => _syncEnabled.Value; + set => _syncEnabled.Value = value; + } + + private readonly NetworkVariable _syncEnabled = new() { Value = true }; + private NetworkList _deltas = null!; + + [MemberNotNull(nameof(EntryContainer))] + private void EnsureEntryContainer() + { + if (EntryContainer is not null) return; + throw new InvalidOperationException("Entry container has not been assigned."); + } private void Awake() { - Deltas = new NetworkList(); + EnsureEntryContainer(); + _deltas = new NetworkList(); } public override void OnNetworkSpawn() { + EnsureEntryContainer(); + if (IsServer) { - HostDisabledSync.Value = false; // todo: use config value here - // todo: populate the list + foreach (var syncedEntryBase in EntryContainer.Values) + { + var currentIndex = _deltas.Count; + _deltas.Add(syncedEntryBase.ToDelta()); + + syncedEntryBase.BoxedEntry.ConfigFile.SettingChanged += (_, args) => + { + if (!ReferenceEquals(syncedEntryBase.BoxedEntry, args.ChangedSetting)) return; + _deltas[currentIndex] = syncedEntryBase.ToDelta(); + }; + } + + return; } if (IsClient) { - Deltas.OnListChanged += OnClientDeltaListChanged; + _syncEnabled.OnValueChanged += OnSyncEnabledChanged; + _deltas.OnListChanged += OnClientDeltaListChanged; + + foreach (var delta in _deltas) + { + UpdateOverrideValue(delta); + } + + if (_syncEnabled.Value) EnableOverrides(); + } + } + + public override void OnDestroy() + { + DisableOverrides(); + foreach (var delta in _deltas) + { + ResetOverrideValue(delta); + } + base.OnDestroy(); + } + + private void OnSyncEnabledChanged(bool previousValue, bool newValue) + { + if (previousValue == newValue) return; + + if (newValue) + { + EnableOverrides(); + } + else + { + DisableOverrides(); } } private void OnClientDeltaListChanged(NetworkListEvent args) { - throw new NotImplementedException(); + switch (args.Type) + { + case NetworkListEvent.EventType.Remove: + case NetworkListEvent.EventType.RemoveAt: + ResetOverrideValue(args.PreviousValue); + break; + case NetworkListEvent.EventType.Add: + case NetworkListEvent.EventType.Insert: + case NetworkListEvent.EventType.Value: + UpdateOverrideValue(args.Value); + break; + case NetworkListEvent.EventType.Clear: + foreach (var delta in _deltas) + { + ResetOverrideValue(delta); + } + break; + case NetworkListEvent.EventType.Full: + foreach (var delta in _deltas) + { + UpdateOverrideValue(delta); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void ResetOverrideValue(SyncedEntryDelta delta) + { + EnsureEntryContainer(); + try { + var entry = EntryContainer[(delta.ConfigFileRelativePath.Value, delta.Definition)]; + entry.BoxedValueOverride = entry.BoxedEntry.DefaultValue; + } + catch (KeyNotFoundException) { } + } + + private void UpdateOverrideValue(SyncedEntryDelta delta) + { + EnsureEntryContainer(); + try { + var entry = EntryContainer[(delta.ConfigFileRelativePath.Value, delta.Definition)]; + entry.SetSerializedValueOverride(delta.SerializedValue.Value); + } + catch (KeyNotFoundException) { + Plugin.Logger.Log(LogLevel.Warning, $"Setting \"{delta.Definition}\" could not be found, so its synced value override will be ignored."); + } + catch (Exception exc) { + Plugin.Logger.Log(LogLevel.Warning, $"Synced value override of setting \"{delta.Definition}\" could not be parsed and will be ignored. Reason: {exc.Message}; Value: {delta.SerializedValue.Value}"); + } + } + + private void EnableOverrides() + { + EnsureEntryContainer(); + foreach (var syncedEntryBase in EntryContainer.Values) + { + syncedEntryBase.ValueOverridden = true; + } + } + + private void DisableOverrides() + { + EnsureEntryContainer(); + foreach (var syncedEntryBase in EntryContainer.Values) + { + syncedEntryBase.ValueOverridden = false; + } } } From 5316ecb44f3b9b7cc7190a90a00a505314689659 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:03:07 +0000 Subject: [PATCH 28/70] add / tidy up extension methods --- CSync/Util/ConfigDefinitionExtensions.cs | 12 ++++++++++++ CSync/Util/ConfigEntryExtensions.cs | 5 +++-- CSync/Util/ConfigFileExtensions.cs | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 CSync/Util/ConfigDefinitionExtensions.cs create mode 100644 CSync/Util/ConfigFileExtensions.cs diff --git a/CSync/Util/ConfigDefinitionExtensions.cs b/CSync/Util/ConfigDefinitionExtensions.cs new file mode 100644 index 0000000..7067d58 --- /dev/null +++ b/CSync/Util/ConfigDefinitionExtensions.cs @@ -0,0 +1,12 @@ +using BepInEx.Configuration; +using CSync.Lib; + +namespace CSync.Util; + +internal static class ConfigDefinitionExtensions +{ + public static SyncedConfigDefinition ToSynced(this ConfigDefinition definition) + { + return new(definition.Section, definition.Key); + } +} diff --git a/CSync/Util/ConfigEntryExtensions.cs b/CSync/Util/ConfigEntryExtensions.cs index b3dd70c..7cc3b8b 100644 --- a/CSync/Util/ConfigEntryExtensions.cs +++ b/CSync/Util/ConfigEntryExtensions.cs @@ -5,8 +5,9 @@ namespace CSync.Util; internal static class ConfigEntryExtensions { - internal static SyncedConfigDefinition ToSynced(this ConfigDefinition definition) + public static (string ConfigFileRelativePath, SyncedConfigDefinition Definition) ToSyncedEntryIdentifier( + this ConfigEntryBase entry) { - return new(definition.Section, definition.Key); + return (entry.ConfigFile.GetConfigFileRelativePath(), entry.Definition.ToSynced()); } } diff --git a/CSync/Util/ConfigFileExtensions.cs b/CSync/Util/ConfigFileExtensions.cs new file mode 100644 index 0000000..42fcdaa --- /dev/null +++ b/CSync/Util/ConfigFileExtensions.cs @@ -0,0 +1,13 @@ +using System.IO; +using BepInEx; +using BepInEx.Configuration; + +namespace CSync.Util; + +internal static class ConfigFileExtensions +{ + public static string GetConfigFileRelativePath(this ConfigFile configFile) + { + return Path.GetRelativePath(Paths.BepInExRootPath, configFile.ConfigFilePath); + } +} From 4ce8b54beb44b520baf8a40ab1a761c5579067cb Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:03:23 +0000 Subject: [PATCH 29/70] ensure config files are cached when necessary --- CSync/Util/SyncedBindingExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSync/Util/SyncedBindingExtensions.cs b/CSync/Util/SyncedBindingExtensions.cs index b104e11..ef77da4 100644 --- a/CSync/Util/SyncedBindingExtensions.cs +++ b/CSync/Util/SyncedBindingExtensions.cs @@ -50,6 +50,7 @@ public static SyncedEntry BindSyncedEntry( V defaultValue, ConfigDescription? description = null ) { + ConfigManager.AddToFileCache(configFile); return configFile.Bind(definition, defaultValue, description).ToSyncedEntry(); } From acceacab41dd57c44cabff90bcc9136ab57c687d Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:03:43 +0000 Subject: [PATCH 30/70] synced config :) --- CSync/Lib/SyncedConfig.cs | 79 ++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index e29d7ae..6684b96 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -1,4 +1,11 @@ using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using CSync.Util; +using HarmonyLib; +using JetBrains.Annotations; namespace CSync.Lib; @@ -6,50 +13,54 @@ namespace CSync.Lib; /// Wrapper class allowing the config class (type parameter) to be synchronized.

/// Stores the mod's unique identifier and handles registering and sending of named messages. /// -public class SyncedConfig(string guid) : ISynchronizable where T : class +public class SyncedConfig : ISyncedConfig where T : SyncedConfig { - static void LogErr(string str) => Plugin.Logger.LogError(str); - static void LogDebug(string str) => Plugin.Logger.LogDebug(str); + public ISyncedEntryContainer EntryContainer { get; } = new SyncedEntryContainer(); - /// - /// Invoked on the host when a client requests to sync. - /// - public event EventHandler? SyncRequested; - internal void OnSyncRequested() => SyncRequested?.Invoke(this, EventArgs.Empty); - - /// - /// Invoked on the client when they receive the host config. - /// - public event EventHandler? SyncReceived; - internal void OnSyncReceived() => SyncReceived?.Invoke(this, EventArgs.Empty); - - /// - /// The mod name or abbreviation. After being given to the constructor, it cannot be changed. - /// - public readonly string GUID = guid; + static SyncedConfig() + { + var constructors = AccessTools.GetDeclaredConstructors(typeof(T)); - internal SyncedEntry SYNC_TO_CLIENTS { get; private set; } = null; + ConstructorInfo constructor; + try + { + constructor = constructors.Single(); + } + catch (InvalidOperationException exc) + { + throw new InvalidOperationException($"{typeof(T).Name} declares {constructors.Count} constructors. SyncedConfig subclasses must declare exactly one constructor.", exc); + } - /// - /// Allow the host to control whether clients can use their own config. - /// This MUST be called after binding the entry parameter. - /// - /// The entry for the host to use in your config file. - protected void EnableHostSyncControl(SyncedEntry hostSyncControlOption) { - SYNC_TO_CLIENTS = hostSyncControlOption; + Plugin.Patcher.Patch(constructor, postfix: new HarmonyMethod(AccessTools.Method(typeof(SyncedConfig), nameof(PostConstructor)))); + } - hostSyncControlOption.SettingChanged += (object sender, EventArgs e) => { - SYNC_TO_CLIENTS = hostSyncControlOption; - }; + [HarmonyPostfix] + [UsedImplicitly] + static void PostConstructor(T __instance) + { + __instance.PopulateEntryContainer(); } - public void SetupSync() + public SyncedConfig(string guid) { - throw new NotImplementedException(); + GUID = guid; } - public void RevertSync() + /// + /// The mod name or abbreviation. After being given to the constructor, it cannot be changed. + /// + public string GUID { get; } + + private void PopulateEntryContainer() { - throw new NotImplementedException(); + var fields = AccessTools.GetDeclaredFields(typeof(T)) + .Where(field => field.GetCustomAttribute() is not null) + .Where(field => typeof(SyncedEntryBase).IsAssignableFrom(field.FieldType)); + + foreach (var fieldInfo in fields) + { + var entryBase = (SyncedEntryBase)fieldInfo.GetValue(this); + EntryContainer.Add(entryBase.BoxedEntry.ToSyncedEntryIdentifier(), entryBase); + } } } From 8b11dd6d922563607d791c13dbc2f29bb82a123d Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:04:04 +0000 Subject: [PATCH 31/70] add patch for network prefab registration --- CSync/Patches/GameNetworkManagerPatch.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 CSync/Patches/GameNetworkManagerPatch.cs diff --git a/CSync/Patches/GameNetworkManagerPatch.cs b/CSync/Patches/GameNetworkManagerPatch.cs new file mode 100644 index 0000000..d32e5b9 --- /dev/null +++ b/CSync/Patches/GameNetworkManagerPatch.cs @@ -0,0 +1,22 @@ +using System.Diagnostics.CodeAnalysis; +using CSync.Lib; +using HarmonyLib; +using Unity.Netcode; + +namespace CSync.Patches; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[HarmonyPatch(typeof(GameNetworkManager))] +public static class GameNetworkManagerPatch +{ + [HarmonyPatch(nameof(GameNetworkManager.Start))] + [HarmonyPostfix] + public static void OnNetworkManagerStart(GameNetworkManager __instance) + { + if (NetworkManager.Singleton.NetworkConfig.Prefabs.Contains(ConfigManager.Prefab)) + return; + + NetworkManager.Singleton.AddNetworkPrefab(ConfigManager.Prefab); + } +} + From 6d82a43157d0d77e8b4d7d7153f45cf7e8defee9 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:04:14 +0000 Subject: [PATCH 32/70] add patch for network prefab instantiation --- CSync/Patches/StartOfRoundPatch.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 CSync/Patches/StartOfRoundPatch.cs diff --git a/CSync/Patches/StartOfRoundPatch.cs b/CSync/Patches/StartOfRoundPatch.cs new file mode 100644 index 0000000..f7a4dfd --- /dev/null +++ b/CSync/Patches/StartOfRoundPatch.cs @@ -0,0 +1,30 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using CSync.Lib; +using HarmonyLib; +using Unity.Netcode; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace CSync.Patches; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +[HarmonyPatch(typeof(StartOfRound))] +public static class StartOfRoundPatch +{ + [HarmonyPatch(nameof(StartOfRound.Start))] + [HarmonyPostfix] + public static void OnSessionStart(StartOfRound __instance) + { + if (!__instance.IsOwner) return; + + try { + var configManagerGameObject = Object.Instantiate(ConfigManager.Prefab, __instance.transform); + configManagerGameObject.hideFlags = HideFlags.None; + configManagerGameObject.GetComponent().Spawn(); + } + catch (Exception exc) { + Plugin.Logger.LogError($"Failed to instantiate config sync behaviours:\n{exc}"); + } + } +} From 9ba2851381c4b98b85e507719b9cd3e5ad7930fc Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:16:21 +0000 Subject: [PATCH 33/70] bring back the awful inheritance hierarchy --- CSync/Lib/SyncedConfig.cs | 2 +- CSync/Lib/SyncedInstance.cs | 5 +++++ CSync/Util/ByteSerializer.cs | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 CSync/Lib/SyncedInstance.cs create mode 100644 CSync/Util/ByteSerializer.cs diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 6684b96..6e31e6b 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -13,7 +13,7 @@ namespace CSync.Lib; /// Wrapper class allowing the config class (type parameter) to be synchronized.

/// Stores the mod's unique identifier and handles registering and sending of named messages. /// -public class SyncedConfig : ISyncedConfig where T : SyncedConfig +public class SyncedConfig : SyncedInstance, ISyncedConfig where T : SyncedConfig { public ISyncedEntryContainer EntryContainer { get; } = new SyncedEntryContainer(); diff --git a/CSync/Lib/SyncedInstance.cs b/CSync/Lib/SyncedInstance.cs new file mode 100644 index 0000000..0492d32 --- /dev/null +++ b/CSync/Lib/SyncedInstance.cs @@ -0,0 +1,5 @@ +using CSync.Util; + +namespace CSync.Lib; + +public class SyncedInstance : ByteSerializer; diff --git a/CSync/Util/ByteSerializer.cs b/CSync/Util/ByteSerializer.cs new file mode 100644 index 0000000..dad349f --- /dev/null +++ b/CSync/Util/ByteSerializer.cs @@ -0,0 +1,3 @@ +namespace CSync.Util; + +public class ByteSerializer; From 926dab499be593474a2d42751a7f5619c8bc575f Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:20:41 +0000 Subject: [PATCH 34/70] update netcode patcher to 4.1.1 --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3bb77b1..743cd84 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "evaisa.netcodepatcher.cli": { - "version": "4.1.0", + "version": "4.1.1", "commands": [ "netcode-patch" ] From 96aa7c17cb0e224142d977135b4802a3f31258fe Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:38:46 +0000 Subject: [PATCH 35/70] serialize the guid and look it up when needed --- CSync/Lib/ConfigManager.cs | 2 +- CSync/Lib/ConfigSyncBehaviour.cs | 11 +++++++++-- CSync/Lib/SyncedConfig.cs | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 318cbd9..71bbf42 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -79,6 +79,6 @@ public static void Register(T config) where T : SyncedConfig { } var syncBehaviour = Prefab.AddComponent(); - syncBehaviour.Config = config; + syncBehaviour.ConfigGuid = config.GUID; } } diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index 0de84d5..861576c 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -9,8 +9,15 @@ namespace CSync.Lib; public class ConfigSyncBehaviour : NetworkBehaviour { - [SerializeField] - internal ISyncedConfig? Config; + [field: SerializeField] + public string ConfigGuid { get; internal set; } + + private ISyncedConfig? Config { + get { + var success = ConfigManager.Instances.TryGetValue(ConfigGuid, out var config); + return config ?? null; + } + } private ISyncedEntryContainer? _entryContainer; internal ISyncedEntryContainer? EntryContainer => _entryContainer ??= Config?.EntryContainer; diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 6e31e6b..9fe7226 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Serialization; From e00aadb183e1edaac213a156accf83f1abfe7ced Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:57:41 +0000 Subject: [PATCH 36/70] use `success` from `TryGetValue` --- CSync/Lib/ConfigSyncBehaviour.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index 861576c..ce53e24 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -15,7 +15,7 @@ public class ConfigSyncBehaviour : NetworkBehaviour private ISyncedConfig? Config { get { var success = ConfigManager.Instances.TryGetValue(ConfigGuid, out var config); - return config ?? null; + return success ? config : null; } } From 5f4377634f68ecf9b0ba8c0021f87568e6a06883 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 03:46:58 +0000 Subject: [PATCH 37/70] mark byte serializer as obsolete --- CSync/Util/ByteSerializer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CSync/Util/ByteSerializer.cs b/CSync/Util/ByteSerializer.cs index dad349f..7901d1f 100644 --- a/CSync/Util/ByteSerializer.cs +++ b/CSync/Util/ByteSerializer.cs @@ -1,3 +1,6 @@ +using System; + namespace CSync.Util; +[Obsolete] public class ByteSerializer; From 3298dee78083c4748cd331a052310da545d15809 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 03:47:47 +0000 Subject: [PATCH 38/70] bring back legacy 'extensions' class --- CSync/Util/Extensions.cs | 87 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 CSync/Util/Extensions.cs diff --git a/CSync/Util/Extensions.cs b/CSync/Util/Extensions.cs new file mode 100644 index 0000000..4e4c0d8 --- /dev/null +++ b/CSync/Util/Extensions.cs @@ -0,0 +1,87 @@ +using System; +using BepInEx.Configuration; +using CSync.Lib; + +namespace CSync.Util; + +/// +/// Contains helpful extension methods to aid with synchronization and reduce code duplication. +/// +[Obsolete] +public static class Extensions { + /// + /// Binds an entry to this file and returns the converted synced entry. + /// + /// The currently selected config file. + /// The category that this entry should show under. + /// The name/identifier of this entry. + /// The value assigned to this entry if not changed. + /// The description indicating what this entry does. + private static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + string section, + string key, + T defaultValue, + string description + ) { + return SyncedBindingExtensions.BindSyncedEntry( + configFile, + section, + key, + defaultValue, + description + ); + } + + private static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + string section, + string key, + T defaultValue, + ConfigDescription? description = null + ) { + return SyncedBindingExtensions.BindSyncedEntry( + configFile, + section, + key, + defaultValue, + description + ); + } + + private static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + ConfigDefinition definition, + T defaultValue, + string description + ) { + return SyncedBindingExtensions.BindSyncedEntry( + configFile, + definition, + defaultValue, + description + ); + } + + private static SyncedEntry BindSyncedEntry( + this ConfigFile configFile, + ConfigDefinition definition, + T defaultValue, + ConfigDescription? description = null + ) { + return SyncedBindingExtensions.BindSyncedEntry( + configFile, + definition, + defaultValue, + description + ); + } + + /// + /// Converts this entry into a serializable alternative, allowing it to be synced. + /// + private static SyncedEntry ToSyncedEntry(this ConfigEntry entry) + { + return SyncedBindingExtensions.ToSyncedEntry(entry); + } +} From 06d0f4120094c75051af49f077e776a23bff32a2 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:28:24 +0000 Subject: [PATCH 39/70] make extensions public --- CSync/Util/Extensions.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CSync/Util/Extensions.cs b/CSync/Util/Extensions.cs index 4e4c0d8..f434ff8 100644 --- a/CSync/Util/Extensions.cs +++ b/CSync/Util/Extensions.cs @@ -1,5 +1,6 @@ using System; using BepInEx.Configuration; +using CSync.Extensions; using CSync.Lib; namespace CSync.Util; @@ -7,7 +8,7 @@ namespace CSync.Util; /// /// Contains helpful extension methods to aid with synchronization and reduce code duplication. /// -[Obsolete] +[Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static class Extensions { /// /// Binds an entry to this file and returns the converted synced entry. @@ -17,7 +18,7 @@ public static class Extensions { /// The name/identifier of this entry. /// The value assigned to this entry if not changed. /// The description indicating what this entry does. - private static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, string key, @@ -33,7 +34,7 @@ string description ); } - private static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, string key, @@ -49,7 +50,7 @@ private static SyncedEntry BindSyncedEntry( ); } - private static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, T defaultValue, @@ -63,7 +64,7 @@ string description ); } - private static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, T defaultValue, @@ -80,7 +81,7 @@ private static SyncedEntry BindSyncedEntry( /// /// Converts this entry into a serializable alternative, allowing it to be synced. /// - private static SyncedEntry ToSyncedEntry(this ConfigEntry entry) + public static SyncedEntry ToSyncedEntry(this ConfigEntry entry) { return SyncedBindingExtensions.ToSyncedEntry(entry); } From fb5c36343cb700dd4c1fab49a87032b529531503 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:28:53 +0000 Subject: [PATCH 40/70] move extensions to `CSync.Extensions` namespace --- CSync/{Util => Extensions}/ConfigDefinitionExtensions.cs | 2 +- CSync/{Util => Extensions}/ConfigEntryExtensions.cs | 3 ++- CSync/{Util => Extensions}/ConfigFileExtensions.cs | 2 +- CSync/{Util => Extensions}/SyncedBindingExtensions.cs | 2 +- CSync/Lib/ConfigManager.cs | 1 + CSync/Lib/SyncedConfig.cs | 1 + CSync/Lib/SyncedEntryBase.cs | 1 + 7 files changed, 8 insertions(+), 4 deletions(-) rename CSync/{Util => Extensions}/ConfigDefinitionExtensions.cs (90%) rename CSync/{Util => Extensions}/ConfigEntryExtensions.cs (88%) rename CSync/{Util => Extensions}/ConfigFileExtensions.cs (91%) rename CSync/{Util => Extensions}/SyncedBindingExtensions.cs (98%) diff --git a/CSync/Util/ConfigDefinitionExtensions.cs b/CSync/Extensions/ConfigDefinitionExtensions.cs similarity index 90% rename from CSync/Util/ConfigDefinitionExtensions.cs rename to CSync/Extensions/ConfigDefinitionExtensions.cs index 7067d58..d8d3a5c 100644 --- a/CSync/Util/ConfigDefinitionExtensions.cs +++ b/CSync/Extensions/ConfigDefinitionExtensions.cs @@ -1,7 +1,7 @@ using BepInEx.Configuration; using CSync.Lib; -namespace CSync.Util; +namespace CSync.Extensions; internal static class ConfigDefinitionExtensions { diff --git a/CSync/Util/ConfigEntryExtensions.cs b/CSync/Extensions/ConfigEntryExtensions.cs similarity index 88% rename from CSync/Util/ConfigEntryExtensions.cs rename to CSync/Extensions/ConfigEntryExtensions.cs index 7cc3b8b..0644368 100644 --- a/CSync/Util/ConfigEntryExtensions.cs +++ b/CSync/Extensions/ConfigEntryExtensions.cs @@ -1,7 +1,8 @@ using BepInEx.Configuration; using CSync.Lib; +using CSync.Util; -namespace CSync.Util; +namespace CSync.Extensions; internal static class ConfigEntryExtensions { diff --git a/CSync/Util/ConfigFileExtensions.cs b/CSync/Extensions/ConfigFileExtensions.cs similarity index 91% rename from CSync/Util/ConfigFileExtensions.cs rename to CSync/Extensions/ConfigFileExtensions.cs index 42fcdaa..39acca3 100644 --- a/CSync/Util/ConfigFileExtensions.cs +++ b/CSync/Extensions/ConfigFileExtensions.cs @@ -2,7 +2,7 @@ using BepInEx; using BepInEx.Configuration; -namespace CSync.Util; +namespace CSync.Extensions; internal static class ConfigFileExtensions { diff --git a/CSync/Util/SyncedBindingExtensions.cs b/CSync/Extensions/SyncedBindingExtensions.cs similarity index 98% rename from CSync/Util/SyncedBindingExtensions.cs rename to CSync/Extensions/SyncedBindingExtensions.cs index ef77da4..f594577 100644 --- a/CSync/Util/SyncedBindingExtensions.cs +++ b/CSync/Extensions/SyncedBindingExtensions.cs @@ -1,7 +1,7 @@ using BepInEx.Configuration; using CSync.Lib; -namespace CSync.Util; +namespace CSync.Extensions; /// /// Contains helpful extension methods to aid with synchronization and reduce code duplication. diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 71bbf42..9f5094f 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -5,6 +5,7 @@ using System.IO; using System.Security.Cryptography; using System.Text; +using CSync.Extensions; using CSync.Util; using Unity.Netcode; using UnityEngine; diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 9fe7226..92556c2 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Reflection; using System.Runtime.Serialization; +using CSync.Extensions; using CSync.Util; using HarmonyLib; using JetBrains.Annotations; diff --git a/CSync/Lib/SyncedEntryBase.cs b/CSync/Lib/SyncedEntryBase.cs index d5aa31e..5036198 100644 --- a/CSync/Lib/SyncedEntryBase.cs +++ b/CSync/Lib/SyncedEntryBase.cs @@ -1,5 +1,6 @@ using System.IO; using BepInEx.Configuration; +using CSync.Extensions; using CSync.Util; namespace CSync.Lib; From f939d06efa5a74c51df0909f047093a9123d5ccd Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:46:59 +0000 Subject: [PATCH 41/70] switch out `` for `` --- CSync/Extensions/SyncedBindingExtensions.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CSync/Extensions/SyncedBindingExtensions.cs b/CSync/Extensions/SyncedBindingExtensions.cs index f594577..2e2b5fd 100644 --- a/CSync/Extensions/SyncedBindingExtensions.cs +++ b/CSync/Extensions/SyncedBindingExtensions.cs @@ -15,39 +15,39 @@ public static class SyncedBindingExtensions { /// The name/identifier of this entry. /// The value assigned to this entry if not changed. /// The description indicating what this entry does. - public static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, string key, - V defaultVal, + T defaultVal, string description ) { return configFile.BindSyncedEntry(new ConfigDefinition(section, key), defaultVal, new ConfigDescription(description)); } - public static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, string key, - V defaultValue, + T defaultValue, ConfigDescription? desc = null ) { return configFile.BindSyncedEntry(new ConfigDefinition(section, key), defaultValue, desc); } - public static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, - V defaultValue, + T defaultValue, string description ) { return configFile.BindSyncedEntry(definition, defaultValue, new ConfigDescription(description)); } - public static SyncedEntry BindSyncedEntry( + public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, - V defaultValue, + T defaultValue, ConfigDescription? description = null ) { ConfigManager.AddToFileCache(configFile); @@ -57,7 +57,7 @@ public static SyncedEntry BindSyncedEntry( /// /// Converts this entry into a serializable alternative, allowing it to be synced. /// - public static SyncedEntry ToSyncedEntry(this ConfigEntry entry) { - return new SyncedEntry(entry); + public static SyncedEntry ToSyncedEntry(this ConfigEntry entry) { + return new SyncedEntry(entry); } } From 3598374ec8835e01c20b44f9be5d9db11c22ba09 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:47:18 +0000 Subject: [PATCH 42/70] mark all legacy extensions as obsolete --- CSync/Util/Extensions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CSync/Util/Extensions.cs b/CSync/Util/Extensions.cs index f434ff8..ff8f1af 100644 --- a/CSync/Util/Extensions.cs +++ b/CSync/Util/Extensions.cs @@ -18,6 +18,7 @@ public static class Extensions { /// The name/identifier of this entry. /// The value assigned to this entry if not changed. /// The description indicating what this entry does. + [Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, @@ -34,6 +35,7 @@ string description ); } + [Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, string section, @@ -50,6 +52,7 @@ public static SyncedEntry BindSyncedEntry( ); } + [Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, @@ -64,6 +67,7 @@ string description ); } + [Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static SyncedEntry BindSyncedEntry( this ConfigFile configFile, ConfigDefinition definition, @@ -81,6 +85,7 @@ public static SyncedEntry BindSyncedEntry( /// /// Converts this entry into a serializable alternative, allowing it to be synced. /// + [Obsolete($"Use {nameof(SyncedBindingExtensions)} instead.")] public static SyncedEntry ToSyncedEntry(this ConfigEntry entry) { return SyncedBindingExtensions.ToSyncedEntry(entry); From ebdfaa2a4c81f314d5205a9f01d921e973b82527 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:15:02 +0000 Subject: [PATCH 43/70] standardise trailing whitespace --- CSync/Patches/GameNetworkManagerPatch.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/CSync/Patches/GameNetworkManagerPatch.cs b/CSync/Patches/GameNetworkManagerPatch.cs index d32e5b9..c9dec07 100644 --- a/CSync/Patches/GameNetworkManagerPatch.cs +++ b/CSync/Patches/GameNetworkManagerPatch.cs @@ -19,4 +19,3 @@ public static void OnNetworkManagerStart(GameNetworkManager __instance) NetworkManager.Singleton.AddNetworkPrefab(ConfigManager.Prefab); } } - From fa49702b3ac3d10f001d8d29382b1fa605a62fff Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:15:34 +0000 Subject: [PATCH 44/70] remove unused `using` directives --- CSync/Extensions/ConfigEntryExtensions.cs | 1 - CSync/Lib/ConfigManager.cs | 1 - CSync/Lib/SyncedConfig.cs | 1 - CSync/Lib/SyncedEntryBase.cs | 1 - 4 files changed, 4 deletions(-) diff --git a/CSync/Extensions/ConfigEntryExtensions.cs b/CSync/Extensions/ConfigEntryExtensions.cs index 0644368..ad6b39f 100644 --- a/CSync/Extensions/ConfigEntryExtensions.cs +++ b/CSync/Extensions/ConfigEntryExtensions.cs @@ -1,6 +1,5 @@ using BepInEx.Configuration; using CSync.Lib; -using CSync.Util; namespace CSync.Extensions; diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 9f5094f..5b06288 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -6,7 +6,6 @@ using System.Security.Cryptography; using System.Text; using CSync.Extensions; -using CSync.Util; using Unity.Netcode; using UnityEngine; diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 92556c2..8383d1b 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -3,7 +3,6 @@ using System.Reflection; using System.Runtime.Serialization; using CSync.Extensions; -using CSync.Util; using HarmonyLib; using JetBrains.Annotations; diff --git a/CSync/Lib/SyncedEntryBase.cs b/CSync/Lib/SyncedEntryBase.cs index 5036198..9365992 100644 --- a/CSync/Lib/SyncedEntryBase.cs +++ b/CSync/Lib/SyncedEntryBase.cs @@ -1,7 +1,6 @@ using System.IO; using BepInEx.Configuration; using CSync.Extensions; -using CSync.Util; namespace CSync.Lib; From 55cc153e0e4c688a0d8398e21edec0a9b78ca1a9 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 06:55:49 +0000 Subject: [PATCH 45/70] update netcode patcher CLI --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 743cd84..f8763a7 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "evaisa.netcodepatcher.cli": { - "version": "4.1.1", + "version": "4.2.0", "commands": [ "netcode-patch" ] From 07d737f6feeb786e960e86685faeb7914a9f743f Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 08:06:30 -0600 Subject: [PATCH 46/70] publicize LC --- CSync/CSync.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/CSync.csproj b/CSync/CSync.csproj index b7e12fc..593124b 100644 --- a/CSync/CSync.csproj +++ b/CSync/CSync.csproj @@ -57,7 +57,7 @@ - + $(LethalCompanyDir)Lethal Company_Data\Managed\Assembly-CSharp.dll From 40dad421338efa073673a3a789b64e7358069626 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 16:43:43 -0600 Subject: [PATCH 47/70] add IdentityEqualityComparer.cs --- .../Generic/IdentityEqualityComparer.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 CSync/Util/Collections/Generic/IdentityEqualityComparer.cs diff --git a/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs b/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs new file mode 100644 index 0000000..dc4bfd3 --- /dev/null +++ b/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs @@ -0,0 +1,23 @@ +/* + * This file is largely based upon + * https://github.com/lc-sigurd/sigurd/blob/90b885a2612fb4667bcf4b882d128cea6038976b/SigurdLib.Util/Collections/Generic/IdentityEqualityComparer.cs + * Copyright (c) 2024 Sigurd Team + * The Sigurd Team license this file to themselves under the LGPL-3.0-or-later license. + * + * Copyright (C) 2024 Sigurd Team + * The Sigurd Team license this file to you under the CC-BY-NC-SA-4.0 license. + */ + +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace CSync.Util.Collections.Generic; + +// https://stackoverflow.com/a/8946825 +public sealed class IdentityEqualityComparer : IEqualityComparer + where T : class +{ + public int GetHashCode(T value) => RuntimeHelpers.GetHashCode(value); + + public bool Equals(T left, T right) => ReferenceEquals(left, right); +} From 4c1a2c332ca7e5b7602ef81d5b26fe2cfa511e22 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 16:44:17 -0600 Subject: [PATCH 48/70] remove `IdentityEqualityComparer.cs` --- .../Generic/IdentityEqualityComparer.cs | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 CSync/Util/Collections/Generic/IdentityEqualityComparer.cs diff --git a/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs b/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs deleted file mode 100644 index dc4bfd3..0000000 --- a/CSync/Util/Collections/Generic/IdentityEqualityComparer.cs +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is largely based upon - * https://github.com/lc-sigurd/sigurd/blob/90b885a2612fb4667bcf4b882d128cea6038976b/SigurdLib.Util/Collections/Generic/IdentityEqualityComparer.cs - * Copyright (c) 2024 Sigurd Team - * The Sigurd Team license this file to themselves under the LGPL-3.0-or-later license. - * - * Copyright (C) 2024 Sigurd Team - * The Sigurd Team license this file to you under the CC-BY-NC-SA-4.0 license. - */ - -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace CSync.Util.Collections.Generic; - -// https://stackoverflow.com/a/8946825 -public sealed class IdentityEqualityComparer : IEqualityComparer - where T : class -{ - public int GetHashCode(T value) => RuntimeHelpers.GetHashCode(value); - - public bool Equals(T left, T right) => ReferenceEquals(left, right); -} From 32454d4bcb75884e4610c98db3f1a7f69f245f65 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:51:59 -0600 Subject: [PATCH 49/70] register config instances using a specialized (serializable!) key --- CSync/Lib/ConfigManager.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 5b06288..911352d 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -6,6 +6,7 @@ using System.Security.Cryptography; using System.Text; using CSync.Extensions; +using JetBrains.Annotations; using Unity.Netcode; using UnityEngine; @@ -17,7 +18,7 @@ namespace CSync.Lib; /// public class ConfigManager { internal static readonly Dictionary FileCache = []; - internal static readonly Dictionary Instances = []; + internal static readonly Dictionary Instances = []; private static readonly Lazy LazyPrefab; internal static GameObject Prefab => LazyPrefab.Value; @@ -69,16 +70,21 @@ public static void Register(T config) where T : SyncedConfig { throw new ArgumentNullException(nameof(config), "Config instance is null, cannot register."); } - string guid = config.GUID; + var assemblyQualifiedTypeName = typeof(T).AssemblyQualifiedName ?? throw new ArgumentException(nameof(config)); + var key = new InstanceKey(config.GUID, assemblyQualifiedTypeName); try { - Instances.Add(guid, config); + Instances.Add(key, config); } catch (ArgumentException exc) { - throw new InvalidOperationException($"Attempted to register config `{guid}`, but it has already been registered.", exc); + throw new InvalidOperationException($"Attempted to register config instance of type `{typeof(T)}`, but an instance has already been registered.", exc); } var syncBehaviour = Prefab.AddComponent(); - syncBehaviour.ConfigGuid = config.GUID; + syncBehaviour.ConfigInstanceKey = key; } + + [UsedImplicitly] + [Serializable] + internal readonly record struct InstanceKey(string Guid, string AssemblyQualifiedName); } From 0bb318a9f63b4e4ff56d32c44c0019236677e937 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:52:52 -0600 Subject: [PATCH 50/70] add event to populate config entries --- CSync/Lib/ConfigManager.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 911352d..b5f47cf 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -20,6 +20,9 @@ public class ConfigManager { internal static readonly Dictionary FileCache = []; internal static readonly Dictionary Instances = []; + private static event Action? OnPopulateEntriesRequested; + internal static void PopulateEntries() => OnPopulateEntriesRequested?.Invoke(); + private static readonly Lazy LazyPrefab; internal static GameObject Prefab => LazyPrefab.Value; @@ -80,6 +83,9 @@ public static void Register(T config) where T : SyncedConfig { throw new InvalidOperationException($"Attempted to register config instance of type `{typeof(T)}`, but an instance has already been registered.", exc); } + config.Instance = config; + OnPopulateEntriesRequested += config.PopulateEntryContainer; + var syncBehaviour = Prefab.AddComponent(); syncBehaviour.ConfigInstanceKey = key; } From fb1bae6b605c9f6d604efe85cd8dc264f6499ce5 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:53:11 -0600 Subject: [PATCH 51/70] replace `ConfigGuid` with `ConfigInstanceKey` --- CSync/Lib/ConfigSyncBehaviour.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index ce53e24..2f34225 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -10,11 +10,11 @@ namespace CSync.Lib; public class ConfigSyncBehaviour : NetworkBehaviour { [field: SerializeField] - public string ConfigGuid { get; internal set; } + internal ConfigManager.InstanceKey ConfigInstanceKey { get; set; } private ISyncedConfig? Config { get { - var success = ConfigManager.Instances.TryGetValue(ConfigGuid, out var config); + var success = ConfigManager.Instances.TryGetValue(ConfigInstanceKey, out var config); return success ? config : null; } } From 1213b249e0592806421534516b738d5723cf98b3 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:53:35 -0600 Subject: [PATCH 52/70] populate entries when a session starts --- CSync/Patches/StartOfRoundPatch.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSync/Patches/StartOfRoundPatch.cs b/CSync/Patches/StartOfRoundPatch.cs index f7a4dfd..b170ce4 100644 --- a/CSync/Patches/StartOfRoundPatch.cs +++ b/CSync/Patches/StartOfRoundPatch.cs @@ -19,6 +19,7 @@ public static void OnSessionStart(StartOfRound __instance) if (!__instance.IsOwner) return; try { + ConfigManager.PopulateEntries(); var configManagerGameObject = Object.Instantiate(ConfigManager.Prefab, __instance.transform); configManagerGameObject.hideFlags = HideFlags.None; configManagerGameObject.GetComponent().Spawn(); From 56849fe64c234c8f9ae003ebd299940c1282ea25 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:54:09 -0600 Subject: [PATCH 53/70] remove subclass ctor patch --- CSync/Lib/SyncedConfig.cs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 8383d1b..b4398cc 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; using System.Reflection; using System.Runtime.Serialization; @@ -16,30 +15,6 @@ public class SyncedConfig : SyncedInstance, ISyncedConfig where T : Synced { public ISyncedEntryContainer EntryContainer { get; } = new SyncedEntryContainer(); - static SyncedConfig() - { - var constructors = AccessTools.GetDeclaredConstructors(typeof(T)); - - ConstructorInfo constructor; - try - { - constructor = constructors.Single(); - } - catch (InvalidOperationException exc) - { - throw new InvalidOperationException($"{typeof(T).Name} declares {constructors.Count} constructors. SyncedConfig subclasses must declare exactly one constructor.", exc); - } - - Plugin.Patcher.Patch(constructor, postfix: new HarmonyMethod(AccessTools.Method(typeof(SyncedConfig), nameof(PostConstructor)))); - } - - [HarmonyPostfix] - [UsedImplicitly] - static void PostConstructor(T __instance) - { - __instance.PopulateEntryContainer(); - } - public SyncedConfig(string guid) { GUID = guid; From cb57e40bc30a8b8a214a131802c2447702872405 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:54:18 -0600 Subject: [PATCH 54/70] add `PublicAPI` attribute --- CSync/Lib/SyncedConfig.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index b4398cc..86d61ca 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -11,6 +11,7 @@ namespace CSync.Lib; /// Wrapper class allowing the config class (type parameter) to be synchronized.

/// Stores the mod's unique identifier and handles registering and sending of named messages. ///
+[PublicAPI] public class SyncedConfig : SyncedInstance, ISyncedConfig where T : SyncedConfig { public ISyncedEntryContainer EntryContainer { get; } = new SyncedEntryContainer(); From 197b24cbf228abfc990a09c598ed5185d89f6580 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:54:27 -0600 Subject: [PATCH 55/70] make `PopulateEntryContainer` `internal` --- CSync/Lib/SyncedConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/SyncedConfig.cs b/CSync/Lib/SyncedConfig.cs index 86d61ca..e460f73 100644 --- a/CSync/Lib/SyncedConfig.cs +++ b/CSync/Lib/SyncedConfig.cs @@ -26,7 +26,7 @@ public SyncedConfig(string guid) /// public string GUID { get; } - private void PopulateEntryContainer() + internal void PopulateEntryContainer() { var fields = AccessTools.GetDeclaredFields(typeof(T)) .Where(field => field.GetCustomAttribute() is not null) From 0465a5c4d48aa0cdebdd0d71c545dbeabd64d078 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:54:40 -0600 Subject: [PATCH 56/70] add `.Instance` back to `SyncedInstance` --- CSync/Lib/SyncedInstance.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CSync/Lib/SyncedInstance.cs b/CSync/Lib/SyncedInstance.cs index 0492d32..d946fa3 100644 --- a/CSync/Lib/SyncedInstance.cs +++ b/CSync/Lib/SyncedInstance.cs @@ -2,4 +2,7 @@ namespace CSync.Lib; -public class SyncedInstance : ByteSerializer; +public class SyncedInstance : ByteSerializer +{ + public T? Instance { get; internal set; } +} From d0e6ca8b78c83d89bfa323ae97a496257f778b6c Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 19:07:50 -0600 Subject: [PATCH 57/70] add `PublicAPI` annotation --- CSync/Lib/ConfigManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index b5f47cf..c91fe73 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -16,6 +16,7 @@ namespace CSync.Lib; /// Helper class enabling the user to easily setup CSync.

/// Handles config registration, instance syncing and caching of BepInEx files.

/// +[PublicAPI] public class ConfigManager { internal static readonly Dictionary FileCache = []; internal static readonly Dictionary Instances = []; From 5abc461e780e8158516c9ae3a753139857fc3976 Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 19:09:10 -0600 Subject: [PATCH 58/70] make `InstanceKey` public --- CSync/Lib/ConfigManager.cs | 2 +- CSync/Lib/ConfigSyncBehaviour.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index c91fe73..85408b0 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -93,5 +93,5 @@ public static void Register(T config) where T : SyncedConfig { [UsedImplicitly] [Serializable] - internal readonly record struct InstanceKey(string Guid, string AssemblyQualifiedName); + public readonly record struct InstanceKey(string Guid, string AssemblyQualifiedName); } diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index 2f34225..2529950 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -10,7 +10,7 @@ namespace CSync.Lib; public class ConfigSyncBehaviour : NetworkBehaviour { [field: SerializeField] - internal ConfigManager.InstanceKey ConfigInstanceKey { get; set; } + public ConfigManager.InstanceKey ConfigInstanceKey { get; internal set; } private ISyncedConfig? Config { get { From 5b1eae2a3732c6940c8a2fdcf8ad5b60abaef12b Mon Sep 17 00:00:00 2001 From: Lordfirespeed <28568841+Lordfirespeed@users.noreply.github.com> Date: Sat, 30 Mar 2024 20:05:20 -0600 Subject: [PATCH 59/70] ensure `InstanceKey` is serialized correctly --- CSync/Lib/ConfigManager.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 85408b0..4a01abb 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -2,6 +2,7 @@ using BepInEx.Configuration; using BepInEx; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Security.Cryptography; using System.Text; @@ -93,5 +94,13 @@ public static void Register(T config) where T : SyncedConfig { [UsedImplicitly] [Serializable] - public readonly record struct InstanceKey(string Guid, string AssemblyQualifiedName); + [SuppressMessage("ReSharper", "Unity.RedundantSerializeFieldAttribute")] // they are *not* redundant! + public readonly record struct InstanceKey(string Guid, string AssemblyQualifiedName) + { + [field: SerializeField] + public string Guid { get; } + + [field: SerializeField] + public string AssemblyQualifiedName { get; } + } } From 091c4d8de48b8a97346eb0aa427251e378e23854 Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:26:17 -0600 Subject: [PATCH 60/70] Update ConfigManager.cs --- CSync/Lib/ConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/ConfigManager.cs b/CSync/Lib/ConfigManager.cs index 4a01abb..f9ed84c 100644 --- a/CSync/Lib/ConfigManager.cs +++ b/CSync/Lib/ConfigManager.cs @@ -85,7 +85,7 @@ public static void Register(T config) where T : SyncedConfig { throw new InvalidOperationException($"Attempted to register config instance of type `{typeof(T)}`, but an instance has already been registered.", exc); } - config.Instance = config; + SyncedInstance.Instance = config; OnPopulateEntriesRequested += config.PopulateEntryContainer; var syncBehaviour = Prefab.AddComponent(); From e54861cb64d671d4ae5a980a173b236dd5110364 Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:26:42 -0600 Subject: [PATCH 61/70] Update SyncedInstance.cs --- CSync/Lib/SyncedInstance.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Lib/SyncedInstance.cs b/CSync/Lib/SyncedInstance.cs index d946fa3..30cf7a1 100644 --- a/CSync/Lib/SyncedInstance.cs +++ b/CSync/Lib/SyncedInstance.cs @@ -2,7 +2,7 @@ namespace CSync.Lib; -public class SyncedInstance : ByteSerializer +public class SyncedInstance : ByteSerializer where T : class { - public T? Instance { get; internal set; } + public static T? Instance { get; internal set; } } From 2f923d4e918516649286e7dd18e72cd1a01ecc3a Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:28:19 -0600 Subject: [PATCH 62/70] Populate entries on all clients --- CSync/Patches/StartOfRoundPatch.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CSync/Patches/StartOfRoundPatch.cs b/CSync/Patches/StartOfRoundPatch.cs index b170ce4..2a8821b 100644 --- a/CSync/Patches/StartOfRoundPatch.cs +++ b/CSync/Patches/StartOfRoundPatch.cs @@ -16,10 +16,11 @@ public static class StartOfRoundPatch [HarmonyPostfix] public static void OnSessionStart(StartOfRound __instance) { + ConfigManager.PopulateEntries(); + if (!__instance.IsOwner) return; try { - ConfigManager.PopulateEntries(); var configManagerGameObject = Object.Instantiate(ConfigManager.Prefab, __instance.transform); configManagerGameObject.hideFlags = HideFlags.None; configManagerGameObject.GetComponent().Spawn(); From 64286b21469d936672e5fbaff74a96a3accde44a Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:59:07 -0600 Subject: [PATCH 63/70] Initialise `_syncEnabled` in `OnNetworkSpawn` --- CSync/Lib/ConfigSyncBehaviour.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index 2529950..de20fee 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -28,7 +28,7 @@ public bool SyncEnabled set => _syncEnabled.Value = value; } - private readonly NetworkVariable _syncEnabled = new() { Value = true }; + private readonly NetworkVariable _syncEnabled = new(); private NetworkList _deltas = null!; [MemberNotNull(nameof(EntryContainer))] @@ -50,6 +50,8 @@ public override void OnNetworkSpawn() if (IsServer) { + _syncEnabled.Value = true; + foreach (var syncedEntryBase in EntryContainer.Values) { var currentIndex = _deltas.Count; From a83cc0ac7131020741fac2f956411f22a802bba5 Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 02:38:15 -0600 Subject: [PATCH 64/70] Actually get relative path, don't use filenme --- CSync/Lib/SyncedEntryBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/SyncedEntryBase.cs b/CSync/Lib/SyncedEntryBase.cs index 9365992..5e90ae5 100644 --- a/CSync/Lib/SyncedEntryBase.cs +++ b/CSync/Lib/SyncedEntryBase.cs @@ -23,7 +23,7 @@ public void SetSerializedValueOverride(string value) } internal SyncedEntryDelta ToDelta() => new SyncedEntryDelta( - configFileRelativePath: Path.GetFileName(BoxedEntry.ConfigFile.ConfigFilePath), + configFileRelativePath: BoxedEntry.ConfigFile.GetConfigFileRelativePath(), definition: BoxedEntry.Definition.ToSynced(), serializedValue: BoxedEntry.GetSerializedValue() ); From 3e2f1397df20811db377ea2ac5a606809d8fff6d Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:10:25 -0600 Subject: [PATCH 65/70] Add `Identifier` member --- CSync/Lib/SyncedEntryDelta.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CSync/Lib/SyncedEntryDelta.cs b/CSync/Lib/SyncedEntryDelta.cs index 5ff2551..fd121cf 100644 --- a/CSync/Lib/SyncedEntryDelta.cs +++ b/CSync/Lib/SyncedEntryDelta.cs @@ -51,4 +51,10 @@ public override int GetHashCode() { return HashCode.Combine(Definition, ConfigFileRelativePath, SerializedValue); } + + public (string ConfigFileRelativePath, SyncedConfigDefinition Definition) SyncedEntryIdentifier { + get { + return (ConfigFileRelativePath.Value, Definition); + } + } } From df598a7b7e49ea87dd19e78cc221cf091f81de7a Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:12:05 -0600 Subject: [PATCH 66/70] Use `delta.SyncedEntryIdentifier` --- CSync/Lib/ConfigSyncBehaviour.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index de20fee..d78257c 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -139,7 +139,7 @@ private void ResetOverrideValue(SyncedEntryDelta delta) { EnsureEntryContainer(); try { - var entry = EntryContainer[(delta.ConfigFileRelativePath.Value, delta.Definition)]; +EntryContainer[delta.SyncedEntryIdentifier]; entry.BoxedValueOverride = entry.BoxedEntry.DefaultValue; } catch (KeyNotFoundException) { } @@ -149,7 +149,7 @@ private void UpdateOverrideValue(SyncedEntryDelta delta) { EnsureEntryContainer(); try { - var entry = EntryContainer[(delta.ConfigFileRelativePath.Value, delta.Definition)]; + var entry = EntryContainer[delta.SyncedEntryIdentifier]; entry.SetSerializedValueOverride(delta.SerializedValue.Value); } catch (KeyNotFoundException) { From 0bf38f39035b0f930af5ddf2b26ab98faca04f43 Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:14:08 -0600 Subject: [PATCH 67/70] Fix copy-paste artefact --- CSync/Lib/ConfigSyncBehaviour.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSync/Lib/ConfigSyncBehaviour.cs b/CSync/Lib/ConfigSyncBehaviour.cs index d78257c..4b40b15 100644 --- a/CSync/Lib/ConfigSyncBehaviour.cs +++ b/CSync/Lib/ConfigSyncBehaviour.cs @@ -139,7 +139,7 @@ private void ResetOverrideValue(SyncedEntryDelta delta) { EnsureEntryContainer(); try { -EntryContainer[delta.SyncedEntryIdentifier]; + var entry = EntryContainer[delta.SyncedEntryIdentifier]; entry.BoxedValueOverride = entry.BoxedEntry.DefaultValue; } catch (KeyNotFoundException) { } From be8d0ad9e92c7791897a6b7375f6ff338306860a Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:17:59 -0600 Subject: [PATCH 68/70] Only populate all entries on host --- CSync/Patches/StartOfRoundPatch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CSync/Patches/StartOfRoundPatch.cs b/CSync/Patches/StartOfRoundPatch.cs index 2a8821b..b94e488 100644 --- a/CSync/Patches/StartOfRoundPatch.cs +++ b/CSync/Patches/StartOfRoundPatch.cs @@ -16,10 +16,10 @@ public static class StartOfRoundPatch [HarmonyPostfix] public static void OnSessionStart(StartOfRound __instance) { - ConfigManager.PopulateEntries(); - if (!__instance.IsOwner) return; + ConfigManager.PopulateEntries(); + try { var configManagerGameObject = Object.Instantiate(ConfigManager.Prefab, __instance.transform); configManagerGameObject.hideFlags = HideFlags.None; From 579fc22130fe9472a55885a3c5a1eab8b57d4dc0 Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:27:14 -0600 Subject: [PATCH 69/70] Don't populate entries at start of round --- CSync/Patches/StartOfRoundPatch.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/CSync/Patches/StartOfRoundPatch.cs b/CSync/Patches/StartOfRoundPatch.cs index b94e488..f7a4dfd 100644 --- a/CSync/Patches/StartOfRoundPatch.cs +++ b/CSync/Patches/StartOfRoundPatch.cs @@ -18,8 +18,6 @@ public static void OnSessionStart(StartOfRound __instance) { if (!__instance.IsOwner) return; - ConfigManager.PopulateEntries(); - try { var configManagerGameObject = Object.Instantiate(ConfigManager.Prefab, __instance.transform); configManagerGameObject.hideFlags = HideFlags.None; From 107fb042bb9307f44153c95c10bc782593aa294c Mon Sep 17 00:00:00 2001 From: Joe Clack <28568841+Lordfirespeed@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:27:50 -0600 Subject: [PATCH 70/70] Populate entries at GameNetworkManager Start --- CSync/Patches/GameNetworkManagerPatch.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CSync/Patches/GameNetworkManagerPatch.cs b/CSync/Patches/GameNetworkManagerPatch.cs index c9dec07..9ce59ee 100644 --- a/CSync/Patches/GameNetworkManagerPatch.cs +++ b/CSync/Patches/GameNetworkManagerPatch.cs @@ -13,9 +13,10 @@ public static class GameNetworkManagerPatch [HarmonyPostfix] public static void OnNetworkManagerStart(GameNetworkManager __instance) { + ConfigManager.PopulateEntries(); + if (NetworkManager.Singleton.NetworkConfig.Prefabs.Contains(ConfigManager.Prefab)) return; - NetworkManager.Singleton.AddNetworkPrefab(ConfigManager.Prefab); } }