Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PerClientSync v1.0.0
PerClientSync.dll
Decompiled 18 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PerClientSync")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+949f42a9f9d3432f3cbd1d90776cc3016e95b22e")] [assembly: AssemblyProduct("PerClientSync")] [assembly: AssemblyTitle("PerClientSync")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PerClientSync { public abstract class ClientView : MonoBehaviour { internal NetworkIdentity identity; internal readonly Dictionary<NetworkConnection, uint> pendingBits = new Dictionary<NetworkConnection, uint>(); public abstract NetworkBehaviour Target { get; } public virtual uint PrivateBits => 0u; public virtual uint LeadingBits => 0u; protected internal abstract void Apply(NetworkConnection client); protected internal abstract void Restore(); public void SetDirty(NetworkConnection client, uint dirtyBits) { if (client != null && dirtyBits != 0 && !PerClient.IsLocal(client)) { pendingBits.TryGetValue(client, out var value); pendingBits[client] = value | dirtyBits; } } public void SetDirtyForAll(uint dirtyBits) { List<NetworkConnection> list = (Object.op_Implicit((Object)(object)identity) ? identity.m_Observers : null); if (list == null) { return; } foreach (NetworkConnection item in list) { SetDirty(item, dirtyBits); } } protected internal virtual void OnPlayerLinked(NetworkConnection client) { SetDirty(client, uint.MaxValue); } protected virtual void OnEnable() { Replication.Add(this); } protected virtual void OnDisable() { Replication.Remove(this); pendingBits.Clear(); } } public abstract class ClientView<T> : ClientView where T : NetworkBehaviour { private T component; public T Component { get { if (!Object.op_Implicit((Object)(object)component)) { return component = ((Component)this).GetComponent<T>(); } return component; } } public override NetworkBehaviour Target => (NetworkBehaviour)(object)Component; } public static class PerClient { public static NetworkConnection GetConnection(PlayerCharacterMasterController player) { if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.networkUser)) { return null; } return ((NetworkBehaviour)player.networkUser).connectionToClient; } public static NetworkConnection GetConnection(NetworkUser user) { if (!Object.op_Implicit((Object)(object)user)) { return null; } return ((NetworkBehaviour)user).connectionToClient; } public static PlayerCharacterMasterController GetPlayer(NetworkConnection client) { if (client == null) { return null; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance.networkUser) && ((NetworkBehaviour)instance.networkUser).connectionToClient == client) { return instance; } } return null; } public static bool IsLocal(NetworkConnection client) { if (client != null) { return Util.ConnectionIsLocal(client); } return false; } public static void Hide(NetworkIdentity identity, NetworkConnection client) { Replication.Hide(identity, client); } public static void Show(NetworkIdentity identity, NetworkConnection client) { Replication.Show(identity, client); } public static bool IsHidden(NetworkIdentity identity, NetworkConnection client) { if (Object.op_Implicit((Object)(object)identity)) { return Replication.IsHidden(identity, client); } return false; } public static byte[] BuildUpdate(NetworkConnection client, NetworkBehaviour component, uint dirtyBits) { return Replication.BuildUpdate(client, component, dirtyBits); } public static bool SendUpdate(NetworkConnection client, NetworkBehaviour component, uint dirtyBits) { if (client == null || !client.isReady || IsLocal(client)) { return false; } byte[] array = BuildUpdate(client, component, dirtyBits); return client.SendBytes(array, array.Length, component.GetNetworkChannel()); } } [BepInPlugin("Def.PerClientSync", "PerClientSync", "1.0.0")] public class PerClientSyncPlugin : BaseUnityPlugin { public const string PluginGUID = "Def.PerClientSync"; public const string PluginAuthor = "Def"; public const string PluginName = "PerClientSync"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Replication.Hook(); } } internal static class Replication { private static readonly Dictionary<NetworkIdentity, List<ClientView>> views = new Dictionary<NetworkIdentity, List<ClientView>>(); private static readonly Dictionary<NetworkIdentity, HashSet<NetworkConnection>> hidden = new Dictionary<NetworkIdentity, HashSet<NetworkConnection>>(); private static readonly List<Hook> hooks = new List<Hook>(); private static readonly NetworkWriter update = new NetworkWriter(); private static readonly NetworkWriter part = new NetworkWriter(); private static NetworkIdentity spawning; private static NetworkConnection spawningFor; internal static void Hook() { Detour(typeof(NetworkIdentity), "UNetUpdate", Type.EmptyTypes, "NetworkIdentity_UNetUpdate"); Detour(typeof(NetworkIdentity), "UNetSerializeAllVars", new Type[1] { typeof(NetworkWriter) }, "NetworkIdentity_UNetSerializeAllVars"); Detour(typeof(NetworkIdentity), "AddObserver", new Type[1] { typeof(NetworkConnection) }, "NetworkIdentity_AddObserver"); Detour(typeof(NetworkServer), "SendSpawnMessage", new Type[2] { typeof(NetworkIdentity), typeof(NetworkConnection) }, "NetworkServer_SendSpawnMessage"); PlayerCharacterMasterController.onLinkedToNetworkUserServerGlobal += OnPlayerLinked; } private static void Detour(Type type, string method, Type[] parameters, string handler) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown MethodInfo method2 = type.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); MethodInfo method3 = typeof(Replication).GetMethod(handler, BindingFlags.Static | BindingFlags.NonPublic); hooks.Add(new Hook((MethodBase)method2, method3)); } internal static void Add(ClientView view) { NetworkIdentity component = ((Component)view).GetComponent<NetworkIdentity>(); NetworkBehaviour target = view.Target; if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)target)) { PerClientSyncPlugin.Log.LogError((object)(((object)view).GetType().Name + " on " + ((Object)view).name + " needs a NetworkIdentity and the component it shows.")); return; } if (!views.TryGetValue(component, out var value)) { value = new List<ClientView>(); views[component] = value; } if (value.Any((ClientView other) => (Object)(object)other.Target == (Object)(object)target)) { PerClientSyncPlugin.Log.LogError((object)(((object)view).GetType().Name + " on " + ((Object)view).name + ": its " + ((object)target).GetType().Name + " already has a view.")); } else { view.identity = component; value.Add(view); } } internal static void Remove(ClientView view) { if (view.identity != null && views.TryGetValue(view.identity, out var value)) { value.Remove(view); if (value.Count == 0) { views.Remove(view.identity); } } view.identity = null; } private static ClientView FindView(List<ClientView> objectViews, NetworkBehaviour behaviour) { foreach (ClientView objectView in objectViews) { if ((Object)(object)objectView.Target == (Object)(object)behaviour) { return objectView; } } return null; } private static void NetworkIdentity_UNetUpdate(Action<NetworkIdentity> orig, NetworkIdentity self) { if (views.Count == 0 || self.m_NetworkBehaviours == null || !views.TryGetValue(self, out var value)) { orig(self); return; } try { Update(self, value); } catch (Exception arg) { PerClientSyncPlugin.Log.LogError((object)$"Could not update {((Object)self).name} for each client, so its views are removed: {arg}"); foreach (ClientView item in value.ToList()) { ((Behaviour)item).enabled = false; } } } private static void Update(NetworkIdentity identity, List<ClientView> objectViews) { uint num = 0u; NetworkBehaviour[] networkBehaviours = identity.m_NetworkBehaviours; for (int i = 0; i < networkBehaviours.Length; i++) { int dirtyChannel = networkBehaviours[i].GetDirtyChannel(); if (dirtyChannel != -1) { num |= (uint)(1 << (dirtyChannel & 0x1F)); } } foreach (ClientView objectView in objectViews) { if (objectView.pendingBits.Count > 0) { num |= (uint)(1 << (objectView.Target.GetNetworkChannel() & 0x1F)); } } if (num == 0) { return; } for (int j = 0; j < NetworkServer.numChannels; j++) { if ((num & (uint)(1 << j)) != 0) { UpdateChannel(identity, objectViews, j); } } } private static void UpdateChannel(NetworkIdentity identity, List<ClientView> objectViews, int channel) { NetworkBehaviour[] behavioursOfSameChannel = identity.GetBehavioursOfSameChannel(channel, false); int num = behavioursOfSameChannel.Length; ClientView[] array = new ClientView[num]; uint[] array2 = new uint[num]; byte[][] array3 = new byte[num][]; bool flag = false; for (int i = 0; i < num; i++) { NetworkBehaviour val = behavioursOfSameChannel[i]; array[i] = FindView(objectViews, val); array2[i] = val.m_SyncVarDirtyBits; if ((Object)(object)array[i] == (Object)null) { part.SeekZero(); if (val.OnSerialize(part, false)) { val.ClearAllDirtyBits(); flag = true; } array3[i] = part.ToArray(); } } byte[][] array4 = null; List<NetworkConnection> observers = identity.m_Observers; if (observers != null) { uint[] array5 = new uint[num]; uint[] array6 = new uint[num]; uint[] array7 = new uint[num]; NetworkConnection[] array8 = observers.ToArray(); foreach (NetworkConnection val2 in array8) { if (val2 == null || !val2.isReady || PerClient.IsLocal(val2)) { continue; } bool flag2 = flag; bool flag3 = false; for (int k = 0; k < num; k++) { ClientView clientView = array[k]; if (!((Object)(object)clientView == (Object)null)) { clientView.pendingBits.TryGetValue(val2, out var value); array5[k] = (array2[k] & ~clientView.PrivateBits) | value; array6[k] = array5[k] & clientView.LeadingBits; array7[k] = array5[k] & ~clientView.LeadingBits; flag2 |= array5[k] != 0; flag3 |= array6[k] != 0; } } if (!flag2) { continue; } bool flag4 = true; if (flag3) { array4 = array4 ?? WriteEmptyParts(behavioursOfSameChannel, array); flag4 = !WriteUpdate(identity, val2, behavioursOfSameChannel, array, array6, array4, partsWrote: false) || val2.SendWriter(update, channel); } if (flag4) { flag4 = !WriteUpdate(identity, val2, behavioursOfSameChannel, array, array7, array3, flag) || val2.SendWriter(update, channel); } for (int l = 0; l < num; l++) { ClientView clientView2 = array[l]; if (!((Object)(object)clientView2 == (Object)null)) { if (flag4) { clientView2.pendingBits.Remove(val2); } else if (array5[l] != 0) { clientView2.pendingBits[val2] = array5[l]; } } } } } for (int m = 0; m < num; m++) { ClientView clientView3 = array[m]; if ((Object)(object)clientView3 == (Object)null) { continue; } if (array2[m] != 0) { behavioursOfSameChannel[m].ClearAllDirtyBits(); } if (clientView3.pendingBits.Count <= 0) { continue; } foreach (NetworkConnection item in clientView3.pendingBits.Keys.Where((NetworkConnection client) => observers == null || !observers.Contains(client)).ToList()) { clientView3.pendingBits.Remove(item); } } } private static byte[][] WriteEmptyParts(NetworkBehaviour[] behaviours, ClientView[] channelViews) { byte[][] array = new byte[behaviours.Length][]; for (int i = 0; i < behaviours.Length; i++) { if ((Object)(object)channelViews[i] == (Object)null) { part.SeekZero(); WriteWithBits(part, behaviours[i], 0u); array[i] = part.ToArray(); } } return array; } private static bool WriteUpdate(NetworkIdentity identity, NetworkConnection client, NetworkBehaviour[] behaviours, ClientView[] channelViews, uint[] viewBits, byte[][] parts, bool partsWrote) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) update.StartMessage((short)8); update.Write(identity.netId); bool flag = partsWrote; for (int i = 0; i < behaviours.Length; i++) { short position = update.Position; if ((Object)(object)channelViews[i] == (Object)null) { update.Write(parts[i], parts[i].Length); } else { flag |= WriteForClient(update, behaviours[i], channelViews[i], client, viewBits[i], initialState: false); } if (NetworkIdentity.m_CheckSerializeSizes) { update.Write((byte)(update.Position - position)); } } update.FinishMessage(); return flag; } private static bool WriteForClient(NetworkWriter writer, NetworkBehaviour behaviour, ClientView view, NetworkConnection client, uint dirtyBits, bool initialState) { uint syncVarDirtyBits = behaviour.m_SyncVarDirtyBits; behaviour.m_SyncVarDirtyBits = dirtyBits; try { view.Apply(client); return behaviour.OnSerialize(writer, initialState); } finally { view.Restore(); behaviour.m_SyncVarDirtyBits = syncVarDirtyBits; } } private static bool WriteWithBits(NetworkWriter writer, NetworkBehaviour behaviour, uint dirtyBits) { uint syncVarDirtyBits = behaviour.m_SyncVarDirtyBits; behaviour.m_SyncVarDirtyBits = dirtyBits; try { return behaviour.OnSerialize(writer, false); } finally { behaviour.m_SyncVarDirtyBits = syncVarDirtyBits; } } internal static byte[] BuildUpdate(NetworkConnection client, NetworkBehaviour component, uint dirtyBits) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) NetworkIdentity component2 = ((Component)component).GetComponent<NetworkIdentity>(); List<ClientView> value; List<ClientView> list = ((client != null && !PerClient.IsLocal(client) && views.TryGetValue(component2, out value)) ? value : null); NetworkWriter val = new NetworkWriter(); val.StartMessage((short)8); val.Write(component2.netId); NetworkBehaviour[] behavioursOfSameChannel = component2.GetBehavioursOfSameChannel(component.GetNetworkChannel(), false); foreach (NetworkBehaviour val2 in behavioursOfSameChannel) { short position = val.Position; uint dirtyBits2 = (((Object)(object)val2 == (Object)(object)component) ? dirtyBits : 0u); ClientView clientView = ((list != null) ? FindView(list, val2) : null); if ((Object)(object)clientView != (Object)null) { WriteForClient(val, val2, clientView, client, dirtyBits2, initialState: false); } else { WriteWithBits(val, val2, dirtyBits2); } if (NetworkIdentity.m_CheckSerializeSizes) { val.Write((byte)(val.Position - position)); } } val.FinishMessage(); return val.ToArray(); } private static void NetworkServer_SendSpawnMessage(Action<NetworkServer, NetworkIdentity, NetworkConnection> orig, NetworkServer self, NetworkIdentity identity, NetworkConnection client) { if (client != null && IsHidden(identity, client)) { return; } if (client == null || PerClient.IsLocal(client) || !views.TryGetValue(identity, out var value)) { orig(self, identity, client); return; } NetworkIdentity val = spawning; NetworkConnection val2 = spawningFor; spawning = identity; spawningFor = client; try { orig(self, identity, client); } finally { spawning = val; spawningFor = val2; } foreach (ClientView item in value) { item.pendingBits.Remove(client); } } private static void NetworkIdentity_UNetSerializeAllVars(Action<NetworkIdentity, NetworkWriter> orig, NetworkIdentity self, NetworkWriter writer) { if (self != spawning || !views.TryGetValue(self, out var value)) { orig(self, writer); return; } NetworkBehaviour[] networkBehaviours = self.m_NetworkBehaviours; foreach (NetworkBehaviour val in networkBehaviours) { ClientView clientView = FindView(value, val); if ((Object)(object)clientView != (Object)null) { WriteForClient(writer, val, clientView, spawningFor, val.m_SyncVarDirtyBits, initialState: true); } else { val.OnSerialize(writer, true); } } } private static void NetworkIdentity_AddObserver(Action<NetworkIdentity, NetworkConnection> orig, NetworkIdentity self, NetworkConnection client) { if (client == null || !IsHidden(self, client)) { orig(self, client); } } private static void OnPlayerLinked(PlayerCharacterMasterController player) { NetworkConnection connection = PerClient.GetConnection(player); if (connection == null || PerClient.IsLocal(connection) || views.Count == 0) { return; } foreach (ClientView item in views.Values.SelectMany((List<ClientView> objectViews) => objectViews).ToList()) { try { item.OnPlayerLinked(connection); } catch (Exception arg) { PerClientSyncPlugin.Log.LogError((object)$"{((object)item).GetType().Name} on {((Object)item).name} could not handle a linked player: {arg}"); } } } internal static bool IsHidden(NetworkIdentity identity, NetworkConnection client) { if (hidden.Count > 0 && client != null && hidden.TryGetValue(identity, out var value)) { return value.Contains(client); } return false; } internal static void Hide(NetworkIdentity identity, NetworkConnection client) { if (NetworkServer.active && Object.op_Implicit((Object)(object)identity) && client != null && !PerClient.IsLocal(client)) { ForgetDestroyedObjects(); if (!hidden.TryGetValue(identity, out var value)) { value = new HashSet<NetworkConnection>(); hidden[identity] = value; } if (value.Add(client) && identity.m_Observers != null && identity.m_Observers.Contains(client)) { identity.RemoveObserver(client); } } } internal static void Show(NetworkIdentity identity, NetworkConnection client) { if (NetworkServer.active && Object.op_Implicit((Object)(object)identity) && client != null && hidden.TryGetValue(identity, out var value) && value.Remove(client)) { if (value.Count == 0) { hidden.Remove(identity); } if (identity.m_Observers != null && client.isReady && !identity.m_Observers.Contains(client) && identity.OnCheckObserver(client)) { identity.AddObserver(client); } } } private static void ForgetDestroyedObjects() { foreach (NetworkIdentity item in hidden.Keys.Where((NetworkIdentity identity) => !Object.op_Implicit((Object)(object)identity)).ToList()) { hidden.Remove(item); } } } }