using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
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.Bootstrap;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ProtoBuf;
using ProtoBuf.Meta;
using SlopCrew.API;
using UnityEngine;
using cspotcode.SlopCrewClient.Patches;
using cspotcode.SlopCrewClient.SlopCrewAPI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("SlopCrewClient")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.0.2.0")]
[assembly: AssemblyInformationalVersion("0.0.2+59363cfb92c4b4440dd00a35b6fa9fff5f36ac75")]
[assembly: AssemblyProduct("SlopCrewClient")]
[assembly: AssemblyTitle("SlopCrewClient")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.2.0")]
[module: UnverifiableCode]
[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 cspotcode.SlopCrewClient
{
public class Client<T>
{
public delegate void PacketReceivedHandler(uint playerId, T packet, bool local);
public const uint LocalPlayerId = 4294967294u;
private readonly string modName;
private bool enabled;
public float MaxAllowedClockDrift = 1f;
public float MaxClockScaling = 0.05f;
private bool firstTickReceived;
private float tickTimeAccumulator;
private float smoothedTickTimeAccumulator;
private bool receivedTickRateFromRealServer;
private ISlopCrewAPI api => APIManager.API;
public ISlopCrewAPI SlopCrewAPI => APIManager.API;
public ulong CurrentTickSmoothed { get; private set; }
public ulong CurrentTick { get; private set; }
public float TickDuration { get; private set; } = 0.1f;
public bool Enabled => enabled;
public bool ApiAvailable => api != null;
public event PacketReceivedHandler OnPacketReceived;
static Client()
{
RuntimeTypeModel.Default.Add(typeof(Vector3), true, (CompatibilityLevel)0).SetSurrogate(typeof(Vector3Surrogate));
RuntimeTypeModel.Default.Add(typeof(Vector2), true, (CompatibilityLevel)0).SetSurrogate(typeof(Vector2Surrogate));
}
public Client(string modName)
{
this.modName = modName;
APIManager.OnAPIRegistered += onSlopCrewAPIRegistered;
UpdateEmitter.EnsureInstance().OnUpdate += Update;
}
public void Enable()
{
if (!enabled)
{
enabled = true;
if (api != null)
{
AddListeners();
}
}
}
public void Disable()
{
if (enabled)
{
enabled = false;
if (api != null)
{
RemoveListeners();
}
}
}
public void Send(T packet, bool receiveLocally)
{
byte[] data = SerializePacket(packet);
api?.SendCustomPacket(modName, data);
if (receiveLocally)
{
this.OnPacketReceived?.Invoke(4294967294u, packet, local: true);
}
}
private void AddListeners()
{
RemoveListeners();
api.OnCustomPacketReceived += onSlopCrewCustomPacketReceived;
api.OnServerTickReceived += onSlopCrewServerTickReceived;
}
private void RemoveListeners()
{
api.OnCustomPacketReceived -= onSlopCrewCustomPacketReceived;
api.OnServerTickReceived -= onSlopCrewServerTickReceived;
}
private void onSlopCrewAPIRegistered(ISlopCrewAPI _)
{
if (enabled)
{
AddListeners();
}
}
private void onSlopCrewCustomPacketReceived(uint playerId, string packetName, byte[] data)
{
if (packetName == modName)
{
T packet = DeserializePacket(data);
this.OnPacketReceived?.Invoke(playerId, packet, local: false);
}
}
private void onSlopCrewServerTickReceived(ulong tick)
{
CurrentTick = tick;
firstTickReceived = true;
}
private static T DeserializePacket(byte[] data)
{
using MemoryStream memoryStream = new MemoryStream(data);
return Serializer.Deserialize<T>((Stream)memoryStream);
}
private static byte[] SerializePacket(T packet)
{
using MemoryStream memoryStream = new MemoryStream();
Serializer.Serialize<T>((Stream)memoryStream, packet);
return memoryStream.ToArray();
}
private void Update()
{
if (!receivedTickRateFromRealServer && api != null && api.Connected && api.TickRate > 0)
{
receivedTickRateFromRealServer = true;
TickDuration = 1f / (float)api.TickRate;
}
float num = 1f;
bool flag = CurrentTick > CurrentTickSmoothed;
bool flag2 = CurrentTickSmoothed > CurrentTick;
ulong num2 = (flag ? (CurrentTick - CurrentTickSmoothed) : (CurrentTickSmoothed - CurrentTick));
if (TickDuration * (float)num2 > MaxAllowedClockDrift)
{
CurrentTickSmoothed = CurrentTick;
}
else
{
if (flag)
{
num = 1f + MaxClockScaling;
}
if (flag2)
{
num = 1f - MaxClockScaling;
}
}
tickTimeAccumulator += Time.deltaTime;
while (tickTimeAccumulator > TickDuration)
{
tickTimeAccumulator -= TickDuration;
CurrentTick++;
}
smoothedTickTimeAccumulator += Time.deltaTime * num;
while (smoothedTickTimeAccumulator > TickDuration)
{
smoothedTickTimeAccumulator -= TickDuration;
CurrentTickSmoothed++;
}
}
}
[BepInPlugin("SlopCrewClient", "SlopCrewClient", "0.0.2")]
public class Plugin : BaseUnityPlugin
{
public static Plugin Instance;
public Plugin()
{
((BaseUnityPlugin)this).Logger.LogInfo((object)(((BaseUnityPlugin)this).Info.Metadata.Name + " plugin loaded"));
}
private void Awake()
{
Instance = this;
CustomAppAPIPatch.AttemptPatch();
APIManager.Init();
}
}
[ProtoContract]
public class Vector3Surrogate
{
[ProtoMember(1)]
public readonly float X;
[ProtoMember(2)]
public readonly float Y;
[ProtoMember(3)]
public readonly float Z;
public Vector3Surrogate(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
public static implicit operator Vector3Surrogate(Vector3 v)
{
//IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references)
return new Vector3Surrogate(v.x, v.y, v.z);
}
public static implicit operator Vector3(Vector3Surrogate v)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(v.X, v.Y, v.Z);
}
}
[ProtoContract]
public class Vector2Surrogate
{
[ProtoMember(1)]
public readonly float X;
[ProtoMember(2)]
public readonly float Y;
public Vector2Surrogate(float x, float y)
{
X = x;
Y = y;
}
public static implicit operator Vector2Surrogate(Vector2 v)
{
//IL_0000: 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)
return new Vector2Surrogate(v.x, v.y);
}
public static implicit operator Vector2(Vector2Surrogate v)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
return new Vector2(v.X, v.Y);
}
}
internal class UpdateEmitter : MonoBehaviour
{
internal static UpdateEmitter Instance { get; private set; }
public event Action OnUpdate;
public event Action OnLateUpdate;
internal static UpdateEmitter EnsureInstance()
{
//IL_0012: 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_001d: Expected O, but got Unknown
if ((Object)(object)Instance == (Object)null)
{
GameObject val = new GameObject("SlopCrewClient");
Object.DontDestroyOnLoad((Object)val);
Instance = val.AddComponent<UpdateEmitter>();
}
return Instance;
}
private void Update()
{
this.OnUpdate?.Invoke();
}
private void LateUpdate()
{
this.OnLateUpdate?.Invoke();
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "SlopCrewClient";
public const string PLUGIN_NAME = "SlopCrewClient";
public const string PLUGIN_VERSION = "0.0.2";
}
}
namespace cspotcode.SlopCrewClient.SlopCrewAPI
{
public class APIManager
{
private const string SlopCrewGUID = "SlopCrew.Plugin";
private static bool _CheckedIfSlopCrewInstalled;
private static bool _IsSlopCrewInstalled;
public static bool IsSlopCrewInstalled
{
get
{
if (!_CheckedIfSlopCrewInstalled)
{
throw new Exception("SlopCrewClient not initialized yet");
}
return _IsSlopCrewInstalled;
}
}
public static ISlopCrewAPI? API { get; private set; }
public static event Action<ISlopCrewAPI>? OnAPIRegistered;
internal static void Init()
{
_IsSlopCrewInstalled = Chainloader.PluginInfos.Keys.Contains("SlopCrew.Plugin");
_CheckedIfSlopCrewInstalled = true;
if (IsSlopCrewInstalled)
{
SlopCrew_Init();
}
}
private static void SlopCrew_Init()
{
APIManager.OnAPIRegistered += delegate(ISlopCrewAPI api)
{
if (API != null)
{
throw new Exception("SlopCrew API unexpectedly registered multiple times.");
}
API = new SlopCrewAPI(api);
APIManager.OnAPIRegistered?.Invoke(API);
};
if (APIManager.API != null)
{
API = new SlopCrewAPI(APIManager.API);
APIManager.OnAPIRegistered?.Invoke(API);
}
}
}
public interface ISlopCrewAPI
{
string ServerAddress { get; }
int PlayerCount { get; }
bool Connected { get; }
ulong Latency { get; }
int TickRate { get; }
int? StageOverride { get; set; }
uint? PlayerId { get; }
string? PlayerName { get; }
ReadOnlyCollection<uint>? Players { get; }
event Action<int> OnPlayerCountChanged;
event Action OnConnected;
event Action OnDisconnected;
event Action<uint, string, byte[]> OnCustomPacketReceived;
event Action<uint, string, byte[]> OnCustomCharacterInfoReceived;
event Action<ulong> OnServerTickReceived;
string? GetGameObjectPathForPlayerID(uint playerId);
uint? GetPlayerIDForGameObjectPath(string gameObjectPath);
bool? PlayerIDExists(uint playerId);
string? GetPlayerName(uint playerId);
void SendCustomPacket(string id, byte[] data);
void SetCustomCharacterInfo(string id, byte[]? data);
}
public class SlopCrewAPI : ISlopCrewAPI
{
private ISlopCrewAPI api;
public string ServerAddress => api.ServerAddress;
public int PlayerCount => api.PlayerCount;
public bool Connected => api.Connected;
public ulong Latency => api.Latency;
public int TickRate => api.TickRate;
public int? StageOverride
{
get
{
return api.StageOverride;
}
set
{
api.StageOverride = value;
}
}
public uint? PlayerId => api.PlayerId;
public string? PlayerName => api.PlayerName;
public ReadOnlyCollection<uint>? Players => api.Players;
public event Action<int> OnPlayerCountChanged
{
add
{
api.OnPlayerCountChanged += value;
}
remove
{
api.OnPlayerCountChanged -= value;
}
}
public event Action OnConnected
{
add
{
api.OnConnected += value;
}
remove
{
api.OnConnected -= value;
}
}
public event Action OnDisconnected
{
add
{
api.OnDisconnected += value;
}
remove
{
api.OnDisconnected -= value;
}
}
public event Action<uint, string, byte[]> OnCustomPacketReceived
{
add
{
api.OnCustomPacketReceived += value;
}
remove
{
api.OnCustomPacketReceived -= value;
}
}
public event Action<uint, string, byte[]> OnCustomCharacterInfoReceived
{
add
{
api.OnCustomCharacterInfoReceived += value;
}
remove
{
api.OnCustomCharacterInfoReceived -= value;
}
}
public event Action<ulong> OnServerTickReceived
{
add
{
api.OnServerTickReceived += value;
}
remove
{
api.OnServerTickReceived -= value;
}
}
internal SlopCrewAPI(ISlopCrewAPI api)
{
this.api = api;
}
public string? GetGameObjectPathForPlayerID(uint playerId)
{
return api.GetGameObjectPathForPlayerID(playerId);
}
public uint? GetPlayerIDForGameObjectPath(string gameObjectPath)
{
return api.GetPlayerIDForGameObjectPath(gameObjectPath);
}
public bool? PlayerIDExists(uint playerId)
{
return api.PlayerIDExists(playerId);
}
public string? GetPlayerName(uint playerId)
{
return api.GetPlayerName(playerId);
}
public void SendCustomPacket(string id, byte[] data)
{
api.SendCustomPacket(id, data);
}
public void SetCustomCharacterInfo(string id, byte[]? data)
{
api.SetCustomCharacterInfo(id, data);
}
}
}
namespace cspotcode.SlopCrewClient.Patches
{
[HarmonyPatch]
internal class CustomAppAPIPatch
{
internal static void AttemptPatch()
{
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Expected O, but got Unknown
Assembly assembly = (from a in AppDomain.CurrentDomain.GetAssemblies()
where a.GetName().Name == "CustomAppAPI"
select a).FirstOrDefault();
if (assembly == null)
{
return;
}
Type type = (from t in assembly.GetTypes()
where t.Name == "CustomAppMod"
select t).FirstOrDefault();
if (!(type == null))
{
MethodInfo method = type.GetMethod("FindDerivedTypes", BindingFlags.Static | BindingFlags.NonPublic);
if (!(method == null))
{
MethodInfo method2 = typeof(CustomAppAPIPatch).GetMethod("FindDerivedTypes_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
new Harmony("SlopCrewClient").Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
private static bool FindDerivedTypes_Prefix(Assembly assembly, Type baseType, ref IEnumerable<Type> __result)
{
Type baseType2 = baseType;
__result = assembly.GetTypes().Where(delegate(Type t)
{
try
{
return baseType2.IsAssignableFrom(t) && t != baseType2;
}
catch (TypeLoadException)
{
return false;
}
});
return false;
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}