using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Bloodstone.API;
using Bloodstone.Hooks;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using ProjectM.UI;
using Stunlock.Network;
using Unity.Collections;
using Unity.Entities;
using XPShared.BloodstoneExtensions;
using XPShared.Transport;
using XPShared.Transport.Messages;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("XPRising.XPShared")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Framework for transport between server and client for XPRising ClientUI")]
[assembly: AssemblyFileVersion("0.3.9.0")]
[assembly: AssemblyInformationalVersion("0.3.9+1.Branch.main.Sha.0b23557f1154d098dffabfc4cf7d77266c87cc7a.0b23557f1154d098dffabfc4cf7d77266c87cc7a")]
[assembly: AssemblyProduct("XPRising.XPShared")]
[assembly: AssemblyTitle("XPRising.XPShared")]
[assembly: AssemblyVersion("0.3.9.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 XPShared
{
public class FrameTimer
{
private bool _enabled;
private bool _isRunning;
private bool _runOnce;
private DateTime _executeAfter = DateTime.MinValue;
private DateTime _lastExecution = DateTime.MinValue;
private TimeSpan _delay;
private Action _action;
private Func<TimeSpan> _delayGenerator;
public TimeSpan TimeSinceLastRun => DateTime.Now - _lastExecution;
public bool Enabled => _enabled;
public FrameTimer Initialise(Action action, TimeSpan delay, bool runOnce = true)
{
_delayGenerator = null;
_delay = delay;
_executeAfter = DateTime.Now + delay;
_action = action;
_runOnce = runOnce;
return this;
}
public FrameTimer Initialise(Action action, Func<TimeSpan> delayGenerator, bool runOnce = true)
{
_delayGenerator = delayGenerator;
_delay = _delayGenerator();
_executeAfter = DateTime.Now + _delay;
_action = action;
_runOnce = runOnce;
return this;
}
public void Start()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
Refresh();
if (!_enabled)
{
_lastExecution = DateTime.MinValue;
GameFrame.OnUpdate += new GameFrameUpdateEventHandler(GameFrame_OnUpdate);
_enabled = true;
}
}
public void Stop()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
if (_enabled)
{
GameFrame.OnUpdate -= new GameFrameUpdateEventHandler(GameFrame_OnUpdate);
_enabled = false;
}
}
private void Refresh()
{
if (_delayGenerator != null)
{
_delay = _delayGenerator();
}
_executeAfter = DateTime.Now + _delay;
}
private void GameFrame_OnUpdate()
{
Update();
}
private void Update()
{
if (!_enabled || _isRunning || _executeAfter >= DateTime.Now)
{
return;
}
_isRunning = true;
try
{
_action();
_lastExecution = DateTime.Now;
}
catch (Exception ex)
{
Plugin.Log((LogLevel)2, "Timer failed " + ex.Message + "\n" + ex.StackTrace);
_runOnce = true;
Stop();
}
finally
{
if (_runOnce)
{
Stop();
}
else
{
Refresh();
}
_isRunning = false;
}
}
}
[BepInPlugin("XPRising.XPShared", "XPRising.XPShared", "0.3.9")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
private static ManualLogSource _logger;
public static bool IsDebug { get; private set; }
public override void Load()
{
_logger = ((BasePlugin)this).Log;
if (VWorld.IsClient)
{
ClientChat.Initialize();
}
MessageHandler.RegisterClientAction();
MessageUtils.RegisterClientInitialisationType();
IsDebug = typeof(Plugin).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration == "Debug";
MessageUtils.OnClientConnectionEvent += delegate(User character)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
MessageHandler.ServerReceiveFromClient(character, new ClientAction(ClientAction.ActionType.Connect, ""));
};
Log((LogLevel)16, "Plugin is loaded [version: 0.3.9]");
}
public override bool Unload()
{
if (VWorld.IsClient)
{
ClientChat.Uninitialize();
}
MessageHandler.UnregisterClientAction();
MessageUtils.UnregisterClientInitialisationType();
return true;
}
public static void Log(LogLevel level, string message)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: 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_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: 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_0022: Expected O, but got Unknown
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Invalid comparison between Unknown and I4
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
if (IsDebug || (int)level <= 16)
{
ManualLogSource logger = _logger;
bool flag = default(bool);
BepInExLogInterpolatedStringHandler val = new BepInExLogInterpolatedStringHandler(13, 2, level, ref flag);
if (flag)
{
val.AppendFormatted<DateTime>(DateTime.Now, "u");
val.AppendLiteral(": [XPShared] ");
val.AppendFormatted<string>(message);
}
logger.Log(level, val);
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "XPRising.XPShared";
public const string PLUGIN_NAME = "XPRising.XPShared";
public const string PLUGIN_VERSION = "0.3.9";
}
}
namespace XPShared.Transport
{
public delegate void ServerMessageHandler(User fromCharacter, ClientAction msg);
public class MessageHandler
{
public static event ServerMessageHandler OnServerMessageEvent;
public static void RegisterClientAction()
{
Plugin.Log((LogLevel)4, "Registering ClientAction");
VNetworkRegistry.RegisterServerbound<ClientAction>((Action<FromCharacter, ClientAction>)delegate(FromCharacter fromCharacter, ClientAction msg)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
EntityManager entityManager = VWorld.Server.EntityManager;
ServerReceiveFromClient(((EntityManager)(ref entityManager)).GetComponentData<User>(fromCharacter.User), msg);
});
}
public static void UnregisterClientAction()
{
Plugin.Log((LogLevel)32, "Unregistering ClientAction");
VNetworkRegistry.Unregister<ClientAction>();
}
public static void ClientSendToServer(ClientAction message)
{
Plugin.Log((LogLevel)32, $"[CLIENT] [SEND] ClientAction: [{message.Action}] [{message.Value}]");
VNetwork.SendToServer((VNetworkMessage)(object)message);
}
public static void ServerSendToClient<T>(User toCharacter, T msg) where T : VNetworkChatMessage
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
Plugin.Log((LogLevel)32, $"[SERVER] [SEND] {msg.GetType()}");
MessageUtils.SendToClient(toCharacter, msg);
}
internal static void ServerReceiveFromClient(User fromCharacter, ClientAction msg)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
Plugin.Log((LogLevel)32, $"[SERVER] [RECEIVED] ClientAction {msg.Action} {msg.Value}");
MessageHandler.OnServerMessageEvent?.Invoke(fromCharacter, msg);
}
}
public static class Utils
{
public static void ServerSetBarData(User playerCharacter, string barGroup, string bar, string header, float progressPercentage, string tooltip, ProgressSerialisedMessage.ActiveState activeState, string colour, string change = "")
{
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
ProgressSerialisedMessage msg = new ProgressSerialisedMessage
{
Group = barGroup,
Label = bar,
ProgressPercentage = progressPercentage,
Header = header,
Tooltip = tooltip,
Active = activeState,
Colour = colour,
Change = change,
Flash = (change != "")
};
MessageHandler.ServerSendToClient(playerCharacter, msg);
}
public static void ServerSetAction(User playerCharacter, string group, string id, string label, string colour = "#808080")
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
ActionSerialisedMessage msg = new ActionSerialisedMessage
{
Group = group,
ID = id,
Label = label,
Colour = colour
};
MessageHandler.ServerSendToClient(playerCharacter, msg);
}
public static void ServerSendNotification(User playerCharacter, string id, string message, LogLevel severity, string colourOverride = "")
{
//IL_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references)
NotificationMessage msg = new NotificationMessage
{
ID = id,
Message = message,
Severity = severity,
Colour = colourOverride
};
MessageHandler.ServerSendToClient(playerCharacter, msg);
}
public static void SendClientInitialisation()
{
MessageUtils.InitialiseClient();
}
}
}
namespace XPShared.Transport.Messages
{
public class ActionSerialisedMessage : VNetworkChatMessage
{
public string Group = "";
public string ID = "";
public string Label = "";
public string Colour = "#808080";
public bool Enabled = true;
public void Serialize(BinaryWriter writer)
{
writer.Write(Group);
writer.Write(ID);
writer.Write(Label);
writer.Write(Colour);
writer.Write(Enabled);
}
public void Deserialize(BinaryReader reader)
{
Group = reader.ReadString();
ID = reader.ReadString();
Label = reader.ReadString();
Colour = reader.ReadString();
Enabled = reader.ReadBoolean();
}
}
public class ClientAction : VNetworkMessage
{
public enum ActionType
{
Connect,
Disconnect,
ButtonClick
}
public ActionType Action { get; private set; }
public string Value { get; private set; }
public ClientAction()
{
Value = "";
}
public ClientAction(ActionType actionType, string value)
{
Action = actionType;
Value = value;
}
public void Deserialize(NetBufferIn reader)
{
Action = Enum.Parse<ActionType>(((NetBufferIn)(ref reader)).ReadString((Allocator)2));
Value = ((NetBufferIn)(ref reader)).ReadString((Allocator)2);
}
public void Serialize(ref NetBufferOut writer)
{
((NetBufferOut)(ref writer)).Write(Enum.GetName(Action), (Allocator)2);
((NetBufferOut)(ref writer)).Write(Value, (Allocator)2);
}
}
public class ConnectedMessage : VNetworkChatMessage
{
public void Serialize(BinaryWriter writer)
{
}
public void Deserialize(BinaryReader reader)
{
}
}
public class NotificationMessage : VNetworkChatMessage
{
public string ID = "";
public string Message = "";
public LogLevel Severity = (LogLevel)8;
public string Colour = "";
public void Serialize(BinaryWriter writer)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected I4, but got Unknown
writer.Write(ID);
writer.Write(Message);
writer.Write((int)Severity);
writer.Write(Colour);
}
public void Deserialize(BinaryReader reader)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
ID = reader.ReadString();
Message = reader.ReadString();
Severity = (LogLevel)reader.ReadInt32();
Colour = reader.ReadString();
}
}
public class ProgressSerialisedMessage : VNetworkChatMessage
{
public enum ActiveState
{
Unchanged,
NotActive,
Active,
OnlyActive
}
public string Group = "";
public string Label = "";
public string Header = "";
public float ProgressPercentage;
public string Tooltip = "";
public ActiveState Active;
public string Change = "";
public string Colour = "";
public bool Flash;
public void Serialize(BinaryWriter writer)
{
writer.Write(Group);
writer.Write(Label);
writer.Write(Header);
writer.Write(ProgressPercentage);
writer.Write(Tooltip);
writer.Write((int)Active);
writer.Write(Change);
writer.Write(Colour);
writer.Write(Flash);
}
public void Deserialize(BinaryReader reader)
{
Group = reader.ReadString();
Label = reader.ReadString();
Header = reader.ReadString();
ProgressPercentage = reader.ReadSingle();
Tooltip = reader.ReadString();
Active = (ActiveState)reader.ReadInt32();
Change = reader.ReadString();
Colour = reader.ReadString();
Flash = reader.ReadBoolean();
}
}
}
namespace XPShared.BloodstoneExtensions
{
public static class ClientChat
{
private static Harmony? _harmony;
public static void Initialize()
{
if (_harmony != null)
{
throw new Exception("Detour already initialized. You don't need to call this. The Bloodstone plugin will do it for you.");
}
_harmony = Harmony.CreateAndPatchAll(typeof(ClientChat), "XPRising.XPShared");
}
public static void Uninitialize()
{
if (_harmony == null)
{
throw new Exception("Detour wasn't initialized. Are you trying to unload Bloodstone twice?");
}
_harmony.UnpatchSelf();
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ClientChatSystem), "OnUpdate")]
private static void OnUpdatePrefix(ClientChatSystem __instance)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: 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_0017: 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_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: 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_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: 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_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: 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)
//IL_0041: Invalid comparison between Unknown and I4
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: 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)
EntityQuery receiveChatMessagesQuery = __instance._ReceiveChatMessagesQuery;
Enumerator<Entity> enumerator = ((EntityQuery)(ref receiveChatMessagesQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)).GetEnumerator();
while (enumerator.MoveNext())
{
Entity current = enumerator.Current;
EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
ChatMessageServerEvent componentData = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageServerEvent>(current);
if ((int)componentData.MessageType == 6 && MessageUtils.DeserialiseMessage(((object)(FixedString512Bytes)(ref componentData.MessageText)).ToString()))
{
entityManager = ((ComponentSystemBase)__instance).EntityManager;
((EntityManager)(ref entityManager)).DestroyEntity(current);
}
}
}
}
internal class MessageChatRegistry
{
internal static Dictionary<string, RegisteredChatEventHandler> _eventHandlers = new Dictionary<string, RegisteredChatEventHandler>();
internal static void Register<T>(RegisteredChatEventHandler handler)
{
string text = MessageUtils.DeriveKey(typeof(T));
if (_eventHandlers.ContainsKey(text))
{
throw new Exception("Network event " + text + " is already registered");
}
_eventHandlers.Add(text, handler);
}
internal static void Unregister<T>()
{
string key = MessageUtils.DeriveKey(typeof(T));
_eventHandlers.Remove(key);
}
}
internal class RegisteredChatEventHandler
{
internal Action<BinaryReader> OnReceiveFromServer { get; init; }
}
public delegate void ClientConnectionMessageHandler(User fromCharacter);
public static class MessageUtils
{
private struct ClientRegister
{
public int clientNonce;
}
private static readonly int ClientNonce = Random.Shared.Next();
private static readonly Dictionary<ulong, int> SupportedUsers = new Dictionary<ulong, int>();
public static event ClientConnectionMessageHandler? OnClientConnectionEvent;
internal static string DeriveKey(Type name)
{
return name.ToString();
}
public static void InitialiseClient()
{
if (VWorld.IsServer)
{
throw new Exception("InitialiseClient can only be called on the client.");
}
ClientRegister clientRegister = default(ClientRegister);
clientRegister.clientNonce = ClientNonce;
VNetwork.SendToServerStruct<ClientRegister>(clientRegister);
}
public static void SendToClient<T>(User toCharacter, T msg) where T : VNetworkChatMessage
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: 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)
Plugin.Log((LogLevel)32, "[SERVER] [SEND] VNetworkChatMessage");
if (SupportedUsers.TryGetValue(toCharacter.PlatformId, out var value))
{
ServerChatUtils.SendSystemMessageToClient(VWorld.Server.EntityManager, toCharacter, SerialiseMessage(msg, value) ?? "");
}
else
{
Plugin.Log((LogLevel)32, "user nonce not present in supportedUsers");
}
}
internal static void RegisterClientInitialisationType()
{
VNetworkRegistry.RegisterServerboundStruct<ClientRegister>((Action<FromCharacter, ClientRegister>)delegate(FromCharacter from, ClientRegister register)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
EntityManager entityManager = VWorld.Server.EntityManager;
User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(from.User);
SupportedUsers[componentData.PlatformId] = register.clientNonce;
MessageUtils.OnClientConnectionEvent?.Invoke(componentData);
});
}
internal static void UnregisterClientInitialisationType()
{
VNetworkRegistry.UnregisterStruct<ClientRegister>();
}
public static void RegisterType<T>(Action<T> onServerMessageEvent) where T : VNetworkChatMessage, new()
{
Action<T> onServerMessageEvent2 = onServerMessageEvent;
MessageChatRegistry.Register<T>(new RegisteredChatEventHandler
{
OnReceiveFromServer = delegate(BinaryReader br)
{
T obj = new T();
obj.Deserialize(br);
onServerMessageEvent2(obj);
}
});
}
private static string SerialiseMessage<T>(T msg, int clientNonce) where T : VNetworkChatMessage
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter writer = new BinaryWriter(memoryStream);
VNetworkChatMessage.WriteHeader(writer, DeriveKey(msg.GetType()), clientNonce);
msg.Serialize(writer);
return Convert.ToBase64String(memoryStream.ToArray());
}
internal static bool DeserialiseMessage(string message)
{
string type = "";
try
{
using MemoryStream input = new MemoryStream(Convert.FromBase64String(message));
using BinaryReader binaryReader = new BinaryReader(input);
if (!VNetworkChatMessage.ReadHeader(binaryReader, out var clientNonce, out type))
{
return false;
}
if (clientNonce != ClientNonce)
{
Plugin.Log((LogLevel)4, $"ClientNonce did not match: [actual: {clientNonce}, expected: {ClientNonce}]");
return true;
}
if (MessageChatRegistry._eventHandlers.TryGetValue(type, out var value))
{
value.OnReceiveFromServer(binaryReader);
}
return true;
}
catch (FormatException)
{
Plugin.Log((LogLevel)32, "Invalid base64");
return false;
}
catch (Exception ex2)
{
Plugin.Log((LogLevel)2, "Error handling incoming network event " + type + ":");
Plugin.Log((LogLevel)2, ex2.ToString());
return false;
}
}
}
public interface VNetworkChatMessage
{
internal const int CHAT_NETWORK_EVENT_ID = 218160557;
internal static void WriteHeader(BinaryWriter writer, string type, int clientNonce)
{
writer.Write(218160557);
writer.Write(clientNonce);
writer.Write(type);
}
internal static bool ReadHeader(BinaryReader reader, out int clientNonce, out string type)
{
type = "";
clientNonce = 0;
try
{
int num = reader.ReadInt32();
clientNonce = reader.ReadInt32();
type = reader.ReadString();
return num == 218160557;
}
catch (Exception ex)
{
Plugin.Log((LogLevel)32, "Failed to read chat message header: " + ex.Message);
return false;
}
}
void Serialize(BinaryWriter writer);
void Deserialize(BinaryReader reader);
}
}