Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of EntwinedFixed v1.0.0
plugins/Entwined.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using BoplFixedMath; using HarmonyLib; using Steamworks; using Steamworks.Data; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Entwined")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Entwined")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace Entwined { public interface IEntwiner<T> { T Detwine(byte[] data); byte[] Entwine(T obj); } public class GenericEntwiner<T> : IEntwiner<T> { private readonly Func<T, byte[]> EntwinerFunc; private readonly Func<byte[], T> DetwinerFunc; public GenericEntwiner(Func<T, byte[]> entwiner, Func<byte[], T> detwiner) { EntwinerFunc = entwiner; DetwinerFunc = detwiner; } public byte[] Entwine(T obj) { return EntwinerFunc(obj); } public T Detwine(byte[] data) { return DetwinerFunc(data); } } public class StringEntwiner : IEntwiner<string> { public string Detwine(byte[] data) { return Encoding.Unicode.GetString(data); } public byte[] Entwine(string obj) { return Encoding.Unicode.GetBytes(obj); } } public class IntEntwiner : IEntwiner<int> { public int Detwine(byte[] data) { return BitConverter.ToInt32(data, 0); } public byte[] Entwine(int obj) { return BitConverter.GetBytes(obj); } } public class FloatEntwiner : IEntwiner<float> { public float Detwine(byte[] data) { return BitConverter.ToSingle(data, 0); } public byte[] Entwine(float obj) { return BitConverter.GetBytes(obj); } } public class DoubleEntwiner : IEntwiner<double> { public double Detwine(byte[] data) { return BitConverter.ToDouble(data, 0); } public byte[] Entwine(double obj) { return BitConverter.GetBytes(obj); } } public class BoolEntwiner : IEntwiner<bool> { public bool Detwine(byte[] data) { return BitConverter.ToBoolean(data, 0); } public byte[] Entwine(bool obj) { return BitConverter.GetBytes(obj); } } public class FixEntwiner : IEntwiner<Fix> { public Fix Detwine(byte[] data) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Fix.FromRaw(BitConverter.ToInt64(data, 0)); } public byte[] Entwine(Fix obj) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return BitConverter.GetBytes(obj.m_rawValue); } } [BepInPlugin("com.entwinedteam.entwined", "Entwined", "1.0.0")] [BepInProcess("BoplBattle.exe")] public class Entwined : BaseUnityPlugin { internal class DeconstructedPacket { public byte[] Payload { get; set; } public PacketIdentifier PacketIdentifier { get; set; } public static DeconstructedPacket DeconstructPacket(byte[] packet) { return new DeconstructedPacket { PacketIdentifier = IdentifierRegister.GetPacketIdentifier(packet.Skip(signature.Length).Take(PacketIdentifier.EncodedSize).ToArray()), Payload = packet.Skip(signature.Length + PacketIdentifier.EncodedSize).ToArray() }; } } internal static Harmony harmony; internal static Entwined instance; internal static readonly byte[] signature = new byte[4] { 238, 155, 146, 108 }; internal static ManualLogSource StaticLogger => ((BaseUnityPlugin)instance).Logger; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown instance = this; harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); harmony.PatchAll(Assembly.GetExecutingAssembly()); MethodInfo methodInfo = AccessTools.Method(typeof(SteamManager), "Awake", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EntwinedUtilities), "SteamManager_Awake", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); methodInfo = AccessTools.Method(typeof(SteamSocket), "OnMessage", (Type[])null, (Type[])null); methodInfo2 = AccessTools.Method(typeof(Entwined), "SteamSocket_OnMessage", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); EntwinedUtilities.SteamManagerLoaded += SteamManagerLoaded; } private void SteamManagerLoaded() { StaticLogger.LogInfo((object)"Generating PacketIdentifierIDs!"); IdentifierRegister.GeneratePacketIdentifierIDs(); } private static bool SteamSocket_OnMessage(SteamSocket __instance, Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[size]; Marshal.Copy(data, array, 0, size); if (!IsCustomPacket(array)) { return true; } SteamId steamId = ((NetIdentity)(ref identity)).SteamId; if (!((SteamId)(ref steamId)).IsValid) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)"Received message from invalid SteamId!"); return false; } Friend friend = default(Friend); ((Friend)(ref friend))..ctor(((NetIdentity)(ref identity)).SteamId); if (!((Friend)(ref friend)).IsIn(((Lobby)(ref SteamManager.instance.currentLobby)).Id)) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"{((Friend)(ref friend)).Name} ({((NetIdentity)(ref identity)).SteamId}) sent a custom packet from outside of the current lobby!"); return false; } DeconstructedPacket deconstructedPacket = DeconstructedPacket.DeconstructPacket(array); if (deconstructedPacket.PacketIdentifier == null) { StaticLogger.LogInfo((object)"Received invalid packet identifier!"); return true; } PacketSourceInfo sourceInfo = new PacketSourceInfo(identity, connection, __instance, friend); deconstructedPacket.PacketIdentifier.PacketType.ReceiveMessage(deconstructedPacket.Payload, sourceInfo); return false; } internal static bool IsCustomPacket(byte[] packet) { if (packet.Length < signature.Length + PacketIdentifier.EncodedSize) { return false; } byte[] first = packet.Take(signature.Length).ToArray(); if (first.SequenceEqual(signature)) { return true; } return false; } internal static void SendMessage(PacketIdentifier identifier, byte[] payload) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[signature.Length + PacketIdentifier.EncodedSize + payload.Length]; signature.CopyTo(array, 0); identifier.Encode().CopyTo(array, signature.Length); payload.CopyTo(array, signature.Length + PacketIdentifier.EncodedSize); foreach (SteamConnection connectedPlayer in SteamManager.instance.connectedPlayers) { ((Connection)(ref ((ConnectionManager)connectedPlayer).Connection)).SendMessage(array, (SendType)8); } } } public struct PacketSourceInfo { public NetIdentity Identity; public Connection Connection; public SteamSocket Socket; public Friend Friend; public string SenderSteamName; public SteamId SenderSteamId; public Player Player; internal PacketSourceInfo(NetIdentity identity, Connection connection, SteamSocket socket, Friend friend) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Identity = identity; Connection = connection; Socket = socket; Friend = friend; SenderSteamId = ((NetIdentity)(ref identity)).SteamId; Player = PlayerHandler.Get().PlayerList().Find((Player x) => SteamId.op_Implicit(x.steamId) == SteamId.op_Implicit(((NetIdentity)(ref identity)).SteamId)); SenderSteamName = ((Friend)(ref Friend)).Name; } } public delegate void SteamManagerLoadEvent(); public static class EntwinedUtilities { internal static bool loaded; public static event SteamManagerLoadEvent SteamManagerLoaded; internal static void SteamManager_Awake() { if (!loaded) { loaded = true; EntwinedUtilities.SteamManagerLoaded(); } } public static string ToFormattedString<T>(this IEnumerable<T> enumerable) { return "{ " + string.Join(", ", enumerable) + " }"; } } internal class PacketIdentifier { public ushort PluginId { get; set; } = ushort.MaxValue; public ushort PacketId { get; set; } = ushort.MaxValue; public bool IsLoaded => PluginId != ushort.MaxValue || PacketId != ushort.MaxValue; public PacketChannel PacketType { get; set; } public static int EncodedSize => 4; public byte[] Encode() { byte[] bytes = BitConverter.GetBytes(PluginId); byte[] bytes2 = BitConverter.GetBytes(PacketId); return new byte[4] { bytes[0], bytes[1], bytes2[0], bytes2[1] }; } public static PacketIdentifier Decode(byte[] bytes) { return new PacketIdentifier { PluginId = BitConverter.ToUInt16(bytes, 0), PacketId = BitConverter.ToUInt16(bytes, 2) }; } public bool Matches(byte[] bytes) { return Encode().SequenceEqual(bytes); } public override string ToString() { return $"{PluginId};{PacketId}"; } } internal class PluginSorter : IComparer<BaseUnityPlugin> { public int Compare(BaseUnityPlugin x, BaseUnityPlugin y) { return x.Info.Metadata.GUID.CompareTo(y.Info.Metadata.GUID); } } internal static class IdentifierRegister { internal static SortedList<BaseUnityPlugin, List<PacketIdentifier>> PluginPacketPairs = new SortedList<BaseUnityPlugin, List<PacketIdentifier>>(new PluginSorter()); internal static List<PacketIdentifier> packetIdentifiers = new List<PacketIdentifier>(); internal static PacketIdentifier GenerateNewPacketIdentifier(BaseUnityPlugin plugin) { Entwined.StaticLogger.LogInfo((object)("Generating new PacketIdentifier for " + plugin.Info.Metadata.GUID + "!")); PacketIdentifier packetIdentifier = new PacketIdentifier(); if (!PluginPacketPairs.ContainsKey(plugin)) { PluginPacketPairs.Add(plugin, new List<PacketIdentifier>()); } PluginPacketPairs[plugin].Add(packetIdentifier); return packetIdentifier; } internal static void GeneratePacketIdentifierIDs() { ushort num = 0; foreach (KeyValuePair<BaseUnityPlugin, List<PacketIdentifier>> pluginPacketPair in PluginPacketPairs) { BaseUnityPlugin key = pluginPacketPair.Key; List<PacketIdentifier> value = pluginPacketPair.Value; Entwined.StaticLogger.LogInfo((object)$"Found plugin {key.Info.Metadata.GUID} with {value.Count} packet(s)!"); for (ushort num2 = 0; num2 < value.Count; num2++) { PacketIdentifier packetIdentifier = value[num2]; packetIdentifier.PluginId = num; packetIdentifier.PacketId = num2; Entwined.StaticLogger.LogInfo((object)$"Generating ID set {num};{num2}!"); packetIdentifiers.Add(packetIdentifier); } num++; } } internal static PacketIdentifier GetPacketIdentifier(byte[] data) { return packetIdentifiers.Find((PacketIdentifier id) => id.Matches(data)); } } public delegate void PacketReceiveEvent<T>(T payload, PacketSourceInfo sourceInfo); public class PacketChannel { internal PacketIdentifier packetIdentifier; public event PacketReceiveEvent<byte[]> OnMessage; public PacketChannel(BaseUnityPlugin plugin) { packetIdentifier = IdentifierRegister.GenerateNewPacketIdentifier(plugin); packetIdentifier.PacketType = this; } internal void ReceiveMessage(byte[] payload, PacketSourceInfo sourceInfo) { this.OnMessage(payload, sourceInfo); } public void SendMessage(byte[] payload) { Entwined.SendMessage(packetIdentifier, payload); } } public class EntwinedPacketChannel<T> { public PacketChannel PacketChannel { get; private set; } public IEntwiner<T> Entwiner { get; private set; } public event PacketReceiveEvent<T> OnMessage; public EntwinedPacketChannel(PacketChannel packetChannel, IEntwiner<T> entwiner) { Init(packetChannel, entwiner); } public EntwinedPacketChannel(BaseUnityPlugin plugin, IEntwiner<T> entwiner) { Init(new PacketChannel(plugin), entwiner); } private void Init(PacketChannel packetChannel, IEntwiner<T> entwiner) { PacketChannel = packetChannel; Entwiner = entwiner; PacketChannel.OnMessage += ReceiveMessage; } internal void ReceiveMessage(byte[] payload, PacketSourceInfo sourceInfo) { this.OnMessage(Entwiner.Detwine(payload), sourceInfo); } public void SendMessage(T payload) { PacketChannel.SendMessage(Entwiner.Entwine(payload)); } } public class SyncedVariable<T> { private T internalValue; public IEntwiner<T> Entwiner { get; private set; } public PacketChannel PacketChannel { get; private set; } public T Value { get { lock ((object)internalValue) { return internalValue; } } set { lock ((object)internalValue) { internalValue = value; PacketChannel.SendMessage(Entwiner.Entwine(value)); } } } public SyncedVariable(PacketChannel channel, IEntwiner<T> entwiner, T initialValue = default(T)) { Entwiner = entwiner; PacketChannel = channel; PacketChannel.OnMessage += OnMessage; internalValue = initialValue; } public SyncedVariable(BaseUnityPlugin plugin, IEntwiner<T> entwiner, T initialValue = default(T)) { Entwiner = entwiner; PacketChannel = new PacketChannel(plugin); PacketChannel.OnMessage += OnMessage; internalValue = initialValue; } private void OnMessage(byte[] payload, PacketSourceInfo sourceInfo) { lock ((object)internalValue) { internalValue = Entwiner.Detwine(payload); } } } } namespace Entwined.Tests { internal class MainTest : MonoBehaviour { private static EntwinedPacketChannel<string> helloWorldChannel; private static string msg = "Hello World!"; private static List<string> messages = new List<string>(); private SyncedVariable<int> syncedVariable; private void Awake() { helloWorldChannel = new EntwinedPacketChannel<string>((BaseUnityPlugin)(object)Entwined.instance, new StringEntwiner()); syncedVariable = new SyncedVariable<int>((BaseUnityPlugin)(object)Entwined.instance, new IntEntwiner(), 0); helloWorldChannel.OnMessage += OnMessage; } private void OnGUI() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) msg = GUI.TextField(new Rect(15f, 120f, 220f, 35f), msg); if (GUI.Button(new Rect(15f, 170f, 100f, 40f), "Send Message")) { helloWorldChannel.SendMessage(msg); AddMessage(msg, SteamClient.Name); Entwined.StaticLogger.LogInfo((object)"Sent message!"); } GUI.contentColor = Color.black; GUI.Label(new Rect(15f, 225f, 35f, 35f), syncedVariable.Value.ToString()); GUI.contentColor = Color.white; if (GUI.Button(new Rect(15f, 275f, 100f, 40f), "Increment")) { syncedVariable.Value++; } if (GUI.Button(new Rect(15f, 330f, 100f, 40f), "Decrement")) { syncedVariable.Value--; } GUI.contentColor = Color.black; GUI.Label(new Rect(15f, 385f, 1600f, 1600f), string.Join("\n", messages)); GUI.contentColor = Color.white; } private static void OnMessage(string payload, PacketSourceInfo sourceInfo) { AddMessage(payload, sourceInfo.SenderSteamName); } private static void AddMessage(string msg, string user) { messages.Insert(0, "[" + user + "] " + msg); if (messages.Count > 24) { messages.RemoveAt(messages.Count - 1); } } } }