Decompiled source of Entwined v1.0.0

plugins/Entwined.dll

Decompiled 6 months ago
using 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.IgnoreSymbolStoreSequencePoints)]
[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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_006c: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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
		{
			get
			{
				if (PluginId == ushort.MaxValue)
				{
					return PacketId != ushort.MaxValue;
				}
				return true;
			}
		}

		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_0014: 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)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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);
			}
		}
	}
}