Decompiled source of BypassGenerationChecksum v0.1.1

BypassGenerationChecksum.dll

Decompiled 2 months ago
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using Globals;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BypassGenerationChecksum")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BypassGenerationChecksum")]
[assembly: AssemblyTitle("BypassGenerationChecksum")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace BypassGenerationChecksum
{
	internal static class HostAllowMismatchingChecksums
	{
		[HarmonyPatch(typeof(SNet_SyncManager), "SessionCommand")]
		[HarmonyPrefix]
		private static void SNet_SyncManager__SessionCommand__Prefix(eSessionCommandType type)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_0038: 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_0043: Invalid comparison between Unknown and I4
			if (!SNet.IsMaster || (int)type != 1)
			{
				return;
			}
			Enumerator<SNet_Player> enumerator = SNet.Slots.PlayersSynchedWithGame.GetEnumerator();
			while (enumerator.MoveNext())
			{
				SNet_Player current = enumerator.Current;
				if (!current.IsBot && (int)current.Session.mode == 6)
				{
					CheckAndHandleGenerationChecksum(current);
				}
			}
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "MasterReplicationUpdate_Player")]
		[HarmonyPrefix]
		private static void SNet_SyncManager__MasterReplicationUpdate_Player__Prefix(SNet_Player player)
		{
			//IL_0009: 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_0015: Invalid comparison between Unknown and I4
			if (SNet.IsMaster && (int)player.Session.mode == 12 && !player.IsMaster && !player.IsBot)
			{
				CheckAndHandleGenerationChecksum(player);
			}
		}

		private static void CheckAndHandleGenerationChecksum(SNet_Player player)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_0100: Expected O, but got Unknown
			if (SNet.IsMaster && !player.IsBot && player.Session.generationChecksum != SNet.LocalPlayer.Session.generationChecksum)
			{
				Utils.LogInfo($"Generation checksum mismatch... Client:{player.NickName}:{player.Session.generationChecksum} != (Me)Host:{SNet.LocalPlayer.NickName}:{SNet.LocalPlayer.Session.generationChecksum}");
				Utils.LogInfo("Host action... Ignoring the mismatch.");
				if (player.HasPlayerAgent)
				{
					PlayerChatManager.WantToSentTextMessage(new PlayerAgent(((Il2CppObjectBase)player.PlayerAgent).Pointer), "<color=#F10>Warning: Generation checksum mismatch!", (PlayerAgent)null);
				}
				pPlayerData_Session session = player.Session;
				session.generationChecksum = SNet.LocalPlayer.Session.generationChecksum;
				player.Session = session;
			}
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "KickPlayer")]
		[HarmonyPrefix]
		private static void SNet_SyncManager__KickPlayer__Prefix(ref bool __runOriginal, SNet_Player player, SNet_PlayerEventReason reason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)reason == 3)
			{
				Utils.LogError("Ignoring Kick_GenerationChecksum for " + player.NickName);
				__runOriginal = false;
			}
		}
	}
	internal static class ClientSpoofChecksumToMatchHost
	{
		private enum eStatus
		{
			Inactive,
			WaitingForMasterToFinishGenerating
		}

		private static eStatus status;

		[HarmonyPatch(typeof(GS_Generating), "OnBuilderDone")]
		[HarmonyPrefix]
		private static void GS_Generating__OnBuilderDone__Prefix(ref bool __runOriginal)
		{
			if (!Global.UseStaticLevel)
			{
				__runOriginal = false;
				ulong checksum = Builder.CombinedCheckSum.Checksum;
				Debug.Log(Object.op_Implicit(">>>>>>>> GS_Generating.OnBuilderDone"));
				Debug.Log(Object.op_Implicit("Builder.CombinedCheckSum.Checksum: " + checksum));
				HandleGenerationChecksum(checksum);
			}
		}

		private static void HandleGenerationChecksum(ulong generationChecksum)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Invalid comparison between Unknown and I4
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			if (SNet.IsMaster)
			{
				SetGenerationChecksumAndSyncStatus(generationChecksum);
				return;
			}
			if ((int)SNet.Master.Load<pGameState>().gameState == 6)
			{
				Utils.LogInfo("Client action... Waiting for master to finish generating.");
				status = eStatus.WaitingForMasterToFinishGenerating;
				return;
			}
			if (generationChecksum == SNet.Master.Session.generationChecksum)
			{
				SetGenerationChecksumAndSyncStatus(generationChecksum);
				return;
			}
			Utils.LogInfo($"Generation checksum mismatch...  (Me)Client:{SNet.LocalPlayer.NickName}:{generationChecksum} != Host:{SNet.Master.NickName}:{SNet.Master.Session.generationChecksum}");
			Utils.LogInfo("Client action... Master has finished generating. Spoofing generationChecksum.");
			Utils.SendChatMessage("<color=#F10>Warning: Generation checksum mismatch!");
			if ((int)SNet.Master.Load<pGameState>().gameState == 10)
			{
				PlayerChatManager.PostChatMessageLocaly(SNet.LocalPlayer, "<color=#F10>Warning: Generation checksum mismatch!", (SNet_Player)null);
			}
			SetGenerationChecksumAndSyncStatus(SNet.Master.Session.generationChecksum);
			status = eStatus.Inactive;
		}

		[HarmonyPatch(typeof(GameStateManager), "OnPlayerGameStateChange")]
		[HarmonyPostfix]
		private static void GameStateManager__OnPlayerGameStateChange__Postfix(SNet_Player player, pGameState data)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if (status == eStatus.WaitingForMasterToFinishGenerating && player.IsMaster && (int)data.gameState == 7)
			{
				HandleGenerationChecksum(Builder.CombinedCheckSum.Checksum);
			}
		}

		private static void SetGenerationChecksumAndSyncStatus(ulong generationChecksum)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			pPlayerData_Session session = SNet.LocalPlayer.Session;
			session.generationChecksum = generationChecksum;
			SNet.LocalPlayer.Session = session;
			SNet.Sync.SendPlayerData_Session(SNet.LocalPlayer);
			SNet.Sync.SessionCommand((eSessionCommandType)5, 0);
			GameStateManager.ChangeState((eGameStateName)7);
		}

		[HarmonyPatch(typeof(GameStateManager), "ChangeState")]
		[HarmonyPostfix]
		private static void GameStateManager__ChangeState__Postfix(eGameStateName nextState)
		{
			status = eStatus.Inactive;
		}
	}
	internal static class GeneralPatches
	{
		[HarmonyPatch(typeof(SNet_SessionHub), "KickPlayer")]
		[HarmonyPostfix]
		private static void SNet_SessionHub__KickPlayer__Postfix(SNet_Player player, SNet_PlayerEventReason reason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)reason == 3)
			{
				Utils.SendLocalMessage("<color=#F10>The host kicked " + PlayerNameExtentions.GetColoredName(player, (string)null) + "!");
				Utils.SendLocalMessage("<color=#F10>Please ensure the host is running BypassGenerationChecksum.");
			}
		}
	}
	internal static class Utils
	{
		private static ManualLogSource logger = Logger.CreateLogSource("Andocas.BypassGenerationChecksum");

		public static void LogInfo(string text)
		{
			logger.LogInfo((object)text);
		}

		public static void LogError(string text)
		{
			logger.LogError((object)text);
		}

		public static void LogGenerationChecksums(params SNet_Player[] players)
		{
			LogInfo(string.Join(", ", players.Select(DescriptiveString)));
			static string DescriptiveString(SNet_Player player)
			{
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				string value = (player.IsMaster ? "Host" : "Client");
				return $"{value}:{player.NickName}:{player.Session.generationChecksum}";
			}
		}

		public static void SendChatMessage(string text, string prefix = "")
		{
			LogInfo("SendChatMessage: " + text);
			int num = 50 - prefix.Length;
			while (text.Length > num)
			{
				PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), prefix + text.Substring(0, num).Trim(), (PlayerAgent)null);
				text = text.Substring(num).Trim();
			}
			PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), prefix + text, (PlayerAgent)null);
		}

		public static void SendLocalMessage(string text)
		{
			LogInfo("SendLocalMessage: " + text);
			GuiManager.PlayerLayer.m_gameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
			CM_PageLoadout.Current.m_gameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
		}
	}
	internal static class PluginInfo
	{
		public const string GUID = "Andocas.BypassGenerationChecksum";

		public const string NAME = "BypassGenerationChecksum";

		public const string VERSION = "0.1.1";
	}
	[BepInPlugin("Andocas.BypassGenerationChecksum", "BypassGenerationChecksum", "0.1.1")]
	internal class Plugin : BasePlugin
	{
		public override void Load()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Utils.LogInfo("Andocas.BypassGenerationChecksum is loading...");
			Harmony val = new Harmony("Andocas.BypassGenerationChecksum");
			if (ConfigManager.hostAllowMismatchingChecksums.Value)
			{
				val.PatchAll(typeof(HostAllowMismatchingChecksums));
			}
			if (ConfigManager.clientEnableChecksumSpoofing.Value)
			{
				val.PatchAll(typeof(ClientSpoofChecksumToMatchHost));
			}
			val.PatchAll(typeof(GeneralPatches));
			Utils.LogInfo("Andocas.BypassGenerationChecksum is loaded");
		}
	}
	internal static class ConfigManager
	{
		public static readonly ConfigEntry<bool> hostAllowMismatchingChecksums;

		public static readonly ConfigEntry<bool> clientEnableChecksumSpoofing;

		static ConfigManager()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "Andocas.BypassGenerationChecksum.cfg"), true);
			hostAllowMismatchingChecksums = val.Bind<bool>("Host", "Ignore mismatching checksums", true, "This host-only feature allows players with mismatching generation checksums to join your lobbies (instead of kicking them).");
			clientEnableChecksumSpoofing = val.Bind<bool>("Client", "Enable checksum spoofing", true, "This client-side feature allows you to join hosts that don't have BypassGenerationChecksum installed by spoofing your generation checksum to match the host's.");
		}
	}
}