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);
}
}
}
}