Decompiled source of ExtraToolCustomization v1.0.0

ExtraToolCustomization.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using ExtraToolCustomization.Dependencies;
using ExtraToolCustomization.JSON;
using ExtraToolCustomization.Networking.MineDeployer;
using ExtraToolCustomization.Patches;
using ExtraToolCustomization.ToolData;
using ExtraToolCustomization.ToolData.Templates;
using ExtraToolCustomization.Utils;
using GTFO.API;
using GTFO.API.JSON.Converters;
using GTFO.API.Utilities;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using MTFO.API;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ExtraToolCustomization")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f41f1c4740501f60ae5b6f46cf97459f23460746")]
[assembly: AssemblyProduct("ExtraToolCustomization")]
[assembly: AssemblyTitle("ExtraToolCustomization")]
[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 ExtraToolCustomization
{
	[BepInPlugin("Dinorush.ExtraToolCustomization", "ExtraToolCustomization", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "ExtraToolCustomization";

		public override void Load()
		{
			//IL_0037: 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)
			((BasePlugin)this).Log.LogMessage((object)"Loading ExtraToolCustomization");
			if (MTFOWrapper.HasMTFO)
			{
				new Harmony("ExtraToolCustomization").PatchAll();
				ToolDataManager.Current.Init();
			}
			else
			{
				new Harmony("ExtraToolCustomization").PatchAll(typeof(SentryGunPatches_BurstFix));
			}
			((BasePlugin)this).Log.LogMessage((object)"Loaded ExtraToolCustomization");
		}
	}
}
namespace ExtraToolCustomization.Utils
{
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("ExtraToolCustomization");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
	internal static class GearIDRangeExtensions
	{
		public static uint GetOfflineID(this GearIDRange gearIDRange)
		{
			string playfabItemInstanceId = gearIDRange.PlayfabItemInstanceId;
			if (!playfabItemInstanceId.Contains("OfflineGear_ID_"))
			{
				DinoLogger.Error("Find PlayfabItemInstanceId without substring 'OfflineGear_ID_'! " + playfabItemInstanceId);
				return 0u;
			}
			try
			{
				return uint.Parse(playfabItemInstanceId.Substring("OfflineGear_ID_".Length));
			}
			catch
			{
				DinoLogger.Error("Caught exception while trying to parse persistentID of PlayerOfflineGearDB from GearIDRange, which means itemInstanceId could be ill-formated");
				return 0u;
			}
		}
	}
}
namespace ExtraToolCustomization.ToolData
{
	public interface IToolData
	{
		uint OfflineID { get; set; }

		uint ItemID { get; set; }

		string Name { get; set; }
	}
	public sealed class MineData : IToolData
	{
		public uint OfflineID { get; set; }

		public uint ItemID { get; set; }

		public string Name { get; set; } = string.Empty;


		public float Delay { get; set; }

		public float Radius { get; set; }

		public float DistanceMin { get; set; }

		public float DistanceMax { get; set; }

		public float DamageMin { get; set; }

		public float DamageMax { get; set; }

		public float Force { get; set; }
	}
	public sealed class SentryData : IToolData
	{
		public uint OfflineID { get; set; }

		[JsonIgnore]
		public uint ItemID { get; set; }

		public string Name { get; set; } = string.Empty;

	}
	internal class ToolDataDict<T> where T : IToolData
	{
		public static string Name = string.Empty;

		public static readonly Dictionary<string, List<T>> FileData = new Dictionary<string, List<T>>();

		public static readonly Dictionary<uint, T> OfflineData = new Dictionary<uint, T>();

		public static readonly Dictionary<uint, T> ItemData = new Dictionary<uint, T>();
	}
	public sealed class ToolDataManager
	{
		public static readonly ToolDataManager Current = new ToolDataManager();

		private readonly LiveEditListener _liveEditListener;

		private void FileChanged<T>(LiveEditEventArgs e) where T : IToolData
		{
			LiveEditEventArgs e2 = e;
			DinoLogger.Warning("LiveEdit File Changed: " + e2.FullPath);
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadFileContent<T>(e2.FullPath, content);
				PrintCustomIDs<T>();
			});
		}

		private void FileDeleted<T>(LiveEditEventArgs e) where T : IToolData
		{
			DinoLogger.Warning("LiveEdit File Removed: " + e.FullPath);
			RemoveFile<T>(e.FullPath);
			PrintCustomIDs<T>();
		}

		private void FileCreated<T>(LiveEditEventArgs e) where T : IToolData
		{
			LiveEditEventArgs e2 = e;
			DinoLogger.Warning("LiveEdit File Created: " + e2.FullPath);
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadFileContent<T>(e2.FullPath, content);
				PrintCustomIDs<T>();
			});
		}

		private void ReadFileContent<T>(string file, string content) where T : IToolData
		{
			RemoveFile<T>(file);
			List<T> list = null;
			try
			{
				list = TCJson.Deserialize<List<T>>(content);
			}
			catch (JsonException ex)
			{
				DinoLogger.Error("Error parsing " + ToolDataDict<T>.Name + " json " + file);
				DinoLogger.Error(ex.Message);
			}
			if (list != null)
			{
				AddFile(file, list);
			}
		}

		private static void RemoveFile<T>(string file) where T : IToolData
		{
			if (!ToolDataDict<T>.FileData.ContainsKey(file))
			{
				return;
			}
			foreach (T item in ToolDataDict<T>.FileData[file])
			{
				ToolDataDict<T>.OfflineData.Remove(item.OfflineID);
				ToolDataDict<T>.ItemData.Remove(item.ItemID);
			}
			ToolDataDict<T>.FileData.Remove(file);
		}

		private static void AddFile<T>(string file, List<T> dataList) where T : IToolData
		{
			ToolDataDict<T>.FileData.Add(file, dataList);
			foreach (T data in dataList)
			{
				if (data.OfflineID != 0)
				{
					if (ToolDataDict<T>.OfflineData.ContainsKey(data.OfflineID))
					{
						DinoLogger.Warning($"Duplicate {ToolDataDict<T>.Name} offline ID {data.OfflineID} detected. Previous name: {ToolDataDict<T>.OfflineData[data.OfflineID].Name}, new name: {data.Name}");
					}
					ToolDataDict<T>.OfflineData[data.OfflineID] = data;
				}
				if (data.ItemID != 0)
				{
					if (ToolDataDict<T>.ItemData.ContainsKey(data.ItemID))
					{
						DinoLogger.Warning($"Duplicate {ToolDataDict<T>.Name} item ID {data.OfflineID} detected. Previous name: {ToolDataDict<T>.OfflineData[data.OfflineID].Name}, new name: {data.Name}");
					}
					ToolDataDict<T>.ItemData[data.ItemID] = data;
				}
			}
		}

		private void PrintCustomIDs<T>() where T : IToolData
		{
			if (ToolDataDict<T>.OfflineData.Count > 0)
			{
				StringBuilder stringBuilder = new StringBuilder("Found custom blocks for " + ToolDataDict<T>.Name + " offline IDs: ");
				stringBuilder.AppendJoin(", ", ToolDataDict<T>.OfflineData.Keys.ToImmutableSortedSet());
				DinoLogger.Log(stringBuilder.ToString());
			}
			if (ToolDataDict<T>.ItemData.Count > 0)
			{
				StringBuilder stringBuilder2 = new StringBuilder("Found custom blocks for " + ToolDataDict<T>.Name + " item IDs: ");
				stringBuilder2.AppendJoin(", ", ToolDataDict<T>.ItemData.Keys.ToImmutableSortedSet());
				DinoLogger.Log(stringBuilder2.ToString());
			}
		}

		private ToolDataManager()
		{
			string text = Path.Combine(MTFOWrapper.CustomPath, "ExtraToolCustomization");
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			_liveEditListener = LiveEdit.CreateListener(text, "*.json", true);
			_liveEditListener.StopListen();
			LoadDirectory("Mine", MineTemplate.Template);
			_liveEditListener.StartListen();
		}

		private void LoadDirectory<T>(string name, params T[] defaultT) where T : IToolData
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			ToolDataDict<T>.Name = name;
			string text = Path.Combine(MTFOWrapper.CustomPath, "ExtraToolCustomization", name);
			if (!Directory.Exists(text))
			{
				DinoLogger.Log($"No {name} directory detected. Creating {text}/Template.json");
				Directory.CreateDirectory(text);
				StreamWriter streamWriter = File.CreateText(Path.Combine(text, "Template.json"));
				streamWriter.WriteLine(TCJson.Serialize(new List<T>(defaultT)));
				streamWriter.Flush();
				streamWriter.Close();
			}
			else
			{
				DinoLogger.Log(name + " directory detected. " + text);
			}
			foreach (string item in Directory.EnumerateFiles(text, "*.json", SearchOption.AllDirectories))
			{
				string content = File.ReadAllText(item);
				ReadFileContent<T>(item, content);
			}
			PrintCustomIDs<T>();
			_liveEditListener.FileCreated += new LiveEditEventHandler(FileCreated<T>);
			_liveEditListener.FileChanged += new LiveEditEventHandler(FileChanged<T>);
			_liveEditListener.FileDeleted += new LiveEditEventHandler(FileDeleted<T>);
		}

		internal void Init()
		{
		}

		public T? GetItemData<T>(uint id) where T : IToolData
		{
			return ToolDataDict<T>.ItemData.GetValueOrDefault(id);
		}

		public T? GetOfflineData<T>(uint id) where T : IToolData
		{
			return ToolDataDict<T>.OfflineData.GetValueOrDefault(id);
		}
	}
}
namespace ExtraToolCustomization.ToolData.Templates
{
	internal static class MineTemplate
	{
		public static MineData[] Template = new MineData[2]
		{
			new MineData
			{
				OfflineID = 20u,
				Name = "Mine Deployer",
				Delay = 0.25f,
				Radius = 2.5f,
				DistanceMin = 3f,
				DistanceMax = 15f,
				DamageMin = 15f,
				DamageMax = 50f,
				Force = 1000f
			},
			new MineData
			{
				ItemID = 139u,
				Name = "Consumable Mine",
				Delay = 0.25f,
				Radius = 2f,
				DistanceMin = 2.5f,
				DistanceMax = 12f,
				DamageMin = 10f,
				DamageMax = 35f,
				Force = 700f
			}
		};
	}
}
namespace ExtraToolCustomization.Patches
{
	[HarmonyPatch]
	internal static class MineDeployerPatches
	{
		[HarmonyPatch(typeof(PlayerBotActionDeployTripMine), "PlaceTripMine")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_PlaceMine(PlayerBotActionDeployTripMine __instance)
		{
			if (Object.op_Implicit((Object)(object)SNet.Master))
			{
				ItemEquippable val = ((Il2CppObjectBase)__instance.m_desc.BackpackItem.Instance).TryCast<ItemEquippable>();
				uint offlineID = val.GearIDRange?.GetOfflineID() ?? 0;
				MineDeployerManager.SendMineDeployerID(((PlayerBotActionBase)__instance).m_agent.Owner, offlineID, ((GameDataBlockBase<ItemDataBlock>)(object)((Item)val).ItemDataBlock).persistentID);
			}
		}

		[HarmonyPatch(typeof(MineDeployerFirstPerson), "PlaceMine")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_PlaceMine(MineDeployerFirstPerson __instance)
		{
			if (__instance.CheckCanPlace())
			{
				uint offlineID = ((ItemEquippable)__instance).GearIDRange?.GetOfflineID() ?? 0;
				MineDeployerManager.SendMineDeployerID(((Item)__instance).Owner.Owner, offlineID, ((GameDataBlockBase<ItemDataBlock>)(object)((Item)__instance).ItemDataBlock).persistentID);
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "OnSpawn")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_MineSpawned(MineDeployerInstance __instance, ref pItemSpawnData spawnData)
		{
			SNet_Player source = default(SNet_Player);
			if (!Object.op_Implicit((Object)(object)SNet.Master) || !((pPlayer)(ref spawnData.owner)).GetPlayer(ref source))
			{
				return;
			}
			MineDeployerInstance_Detonate_Explosive val = ((Il2CppObjectBase)__instance.m_detonation).TryCast<MineDeployerInstance_Detonate_Explosive>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (!MineDeployerManager.HasMineDeployerID(source))
			{
				MineDeployerManager.StoreMineDeployer(source, val);
				return;
			}
			MineData mineData = MineDeployerManager.GetMineData(MineDeployerManager.PopMineDeployerID(source));
			if (mineData != null)
			{
				MineDeployerManager.ApplyDataToMine(val, mineData);
			}
		}
	}
	[HarmonyPatch]
	internal static class SentryGunPatches
	{
		private static GearIDRange? _cachedRange;

		private static ArchetypeDataBlock? _cachedArchetype;

		[HarmonyPatch(typeof(CM_InventorySlotItem), "LoadData")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_LoadData(GearIDRange idRange)
		{
			CacheArchetype(idRange);
		}

		[HarmonyPatch(typeof(CM_PageExpeditionSuccess), "TryGetArchetypeName")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_GetArchetypeName(PlayerBackpack backpack, InventorySlot slot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			BackpackItem val = default(BackpackItem);
			if (backpack.TryGetBackpackItem(slot, ref val))
			{
				CacheArchetype(val.GearIDRange);
			}
		}

		[HarmonyPatch(typeof(SentryGunFirstPerson), "OnGearSpawnComplete")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_FPGearSpawn(SentryGunFirstPerson __instance)
		{
			CacheArchetype(((ItemEquippable)__instance).GearIDRange);
		}

		[HarmonyPatch(typeof(SentryGunInstance), "OnGearSpawnComplete")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void Pre_InstanceGearSpawn(SentryGunInstance __instance)
		{
			CacheArchetype(((ItemEquippable)__instance).GearIDRange);
		}

		private static void CacheArchetype(GearIDRange idRange)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected I4, but got Unknown
			if (_cachedRange == idRange)
			{
				return;
			}
			_cachedRange = idRange;
			_cachedArchetype = null;
			if (_cachedRange == null || (int)_cachedRange.GetCompID((eGearComponent)1) < 10)
			{
				return;
			}
			uint compID = _cachedRange.GetCompID((eGearComponent)2);
			if (compID == 0)
			{
				return;
			}
			GearCategoryDataBlock block = GameDataBlockBase<GearCategoryDataBlock>.GetBlock(compID);
			if (block == null)
			{
				return;
			}
			eWeaponFireMode val = (eWeaponFireMode)_cachedRange.GetCompID((eGearComponent)1);
			uint num = (val - 10) switch
			{
				0 => block.SemiArchetype, 
				1 => block.AutoArchetype, 
				2 => block.BurstArchetype, 
				3 => block.SemiArchetype, 
				_ => 0u, 
			};
			if (num != 0)
			{
				ArchetypeDataBlock block2 = GameDataBlockBase<ArchetypeDataBlock>.GetBlock(num);
				if (block2 != null)
				{
					_cachedArchetype = block2;
				}
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "GetArchetypeDataForFireMode")]
		[HarmonyPostfix]
		private static void CorrectArchetype(ref ArchetypeDataBlock __result)
		{
			if (_cachedArchetype != null)
			{
				__result = _cachedArchetype;
			}
		}
	}
	[HarmonyPatch]
	internal static class SentryGunPatches_BurstFix
	{
		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "StartFiring")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_StartFiring(SentryGunInstance_Firing_Bullets __instance)
		{
			__instance.m_burstClipCurr = __instance.m_archetypeData.BurstShotCount;
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "StopFiring")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_StopFiring(SentryGunInstance_Firing_Bullets __instance)
		{
			__instance.m_burstTimer = Clock.Time + __instance.m_archetypeData.BurstDelay;
		}
	}
	[HarmonyPatch]
	internal static class SentryGunPatches_ShotgunFix
	{
		private static Vector3? _cachedDir;

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "TriggerSingleFireAudio")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Pre_ShotgunFireBullet(SentryGunInstance_Firing_Bullets __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			if ((int)__instance.m_fireMode == 13 && __instance.m_archetypeData.Sentry_FireTowardsTargetInsteadOfForward && __instance.m_core.TryGetTargetAimPos(ref val))
			{
				_cachedDir = __instance.MuzzleAlign.forward;
				Transform muzzleAlign = __instance.MuzzleAlign;
				Vector3 val2 = val - __instance.MuzzleAlign.position;
				muzzleAlign.forward = ((Vector3)(ref val2)).normalized;
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "UpdateAmmo")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_ShotgunFireBullet(SentryGunInstance_Firing_Bullets __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_cachedDir.HasValue)
			{
				__instance.MuzzleAlign.forward = _cachedDir.Value;
				_cachedDir = null;
			}
		}
	}
}
namespace ExtraToolCustomization.Networking
{
	public abstract class SyncedEvent<T> where T : struct
	{
		public delegate void ReceiveHandler(T packet);

		private bool _isSetup;

		public abstract string GUID { get; }

		public bool IsSetup => _isSetup;

		public string EventName { get; private set; } = string.Empty;


		public event ReceiveHandler? OnReceive;

		public event ReceiveHandler? OnReceiveLocal;

		public void Setup()
		{
			if (!_isSetup)
			{
				EventName = "ETC" + GUID;
				NetworkAPI.RegisterEvent<T>(EventName, (Action<ulong, T>)ReceiveClient_Callback);
				_isSetup = true;
			}
		}

		public void Send(T packetData, SNet_Player? target = null, SNet_ChannelType priority = 4)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target != (Object)null)
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, target, priority);
			}
			else
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, priority);
			}
			ReceiveLocal_Callback(packetData);
		}

		private void ReceiveLocal_Callback(T packet)
		{
			ReceiveLocal(packet);
			this.OnReceiveLocal?.Invoke(packet);
		}

		private void ReceiveClient_Callback(ulong sender, T packet)
		{
			Receive(packet);
			this.OnReceive?.Invoke(packet);
		}

		protected virtual void ReceiveLocal(T packet)
		{
		}

		protected virtual void Receive(T packet)
		{
		}
	}
	public abstract class SyncedEventMasterOnly<T> : SyncedEvent<T> where T : struct
	{
		public void Send(T packet, SNet_ChannelType priority = 4)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!SNet.IsMaster)
			{
				Send(packet, SNet.Master, priority);
			}
			else
			{
				Receive(packet);
			}
		}
	}
}
namespace ExtraToolCustomization.Networking.MineDeployer
{
	public static class MineDeployerManager
	{
		private static readonly MineDeployerSync _sync = new MineDeployerSync();

		internal static Dictionary<ulong, MineDeployerID> _storedPackets = new Dictionary<ulong, MineDeployerID>();

		internal static Dictionary<ulong, MineDeployerInstance_Detonate_Explosive> _storedMines = new Dictionary<ulong, MineDeployerInstance_Detonate_Explosive>();

		internal static void Init()
		{
			_sync.Setup();
		}

		public static void SendMineDeployerID(SNet_Player source, uint offlineID, uint itemID)
		{
			MineDeployerID packet = default(MineDeployerID);
			((pPlayer)(ref packet.source)).SetPlayer(source);
			packet.itemID = (ushort)itemID;
			packet.offlineID = (ushort)offlineID;
			_sync.Send(packet, (SNet_ChannelType)4);
		}

		public static bool HasMineDeployerID(SNet_Player source)
		{
			if (SNet.IsMaster)
			{
				return _storedPackets.ContainsKey(source.Lookup);
			}
			return false;
		}

		public static void StoreMineDeployer(SNet_Player source, MineDeployerInstance_Detonate_Explosive instance)
		{
			_storedMines[source.Lookup] = instance;
		}

		public static MineDeployerID PopMineDeployerID(SNet_Player source)
		{
			if (!HasMineDeployerID(source))
			{
				return default(MineDeployerID);
			}
			MineDeployerID result = _storedPackets[source.Lookup];
			_storedPackets.Remove(source.Lookup);
			return result;
		}

		internal static void Internal_ReceiveMineDeployerPacket(ulong lookup, MineDeployerID packet)
		{
			if (!_storedMines.ContainsKey(lookup))
			{
				_storedPackets[lookup] = packet;
				return;
			}
			MineData mineData = GetMineData(packet);
			MineDeployerInstance_Detonate_Explosive explosive = _storedMines[lookup];
			_storedMines.Remove(lookup);
			if (mineData != null)
			{
				ApplyDataToMine(explosive, mineData);
			}
		}

		public static MineData? GetMineData(MineDeployerID deployerID)
		{
			MineData mineData = null;
			if (deployerID.offlineID != 0)
			{
				mineData = ToolDataManager.Current.GetOfflineData<MineData>(deployerID.offlineID);
			}
			if (mineData == null && deployerID.itemID != 0)
			{
				mineData = ToolDataManager.Current.GetItemData<MineData>(deployerID.itemID);
			}
			return mineData;
		}

		public static void ApplyDataToMine(MineDeployerInstance_Detonate_Explosive explosive, MineData data)
		{
			explosive.m_explosionDelay = data.Delay;
			explosive.m_radius = data.Radius;
			explosive.m_distanceMin = data.DistanceMin;
			explosive.m_distanceMax = data.DistanceMax;
			explosive.m_damageMin = data.DamageMin;
			explosive.m_damageMax = data.DamageMax - data.DamageMin;
			explosive.m_explosionForce = data.Force;
		}
	}
	public struct MineDeployerID
	{
		public pPlayer source;

		public ushort offlineID;

		public ushort itemID;
	}
	internal class MineDeployerSync : SyncedEventMasterOnly<MineDeployerID>
	{
		public override string GUID => "MineID";

		protected override void Receive(MineDeployerID packet)
		{
			SNet_Player val = default(SNet_Player);
			if (((pPlayer)(ref packet.source)).GetPlayer(ref val))
			{
				MineDeployerManager.Internal_ReceiveMineDeployerPacket(val.Lookup, packet);
			}
		}
	}
}
namespace ExtraToolCustomization.JSON
{
	public static class TCJson
	{
		private static readonly JsonSerializerOptions _setting;

		static TCJson()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			_setting = new JsonSerializerOptions
			{
				ReadCommentHandling = JsonCommentHandling.Skip,
				IncludeFields = true,
				PropertyNameCaseInsensitive = true,
				WriteIndented = true,
				IgnoreReadOnlyProperties = true
			};
			_setting.Converters.Add(new JsonStringEnumConverter());
			_setting.Converters.Add((JsonConverter)new LocalizedTextConverter());
		}

		public static T? Deserialize<T>(string json)
		{
			return JsonSerializer.Deserialize<T>(json, _setting);
		}

		public static object? Deserialize(Type type, string json)
		{
			return JsonSerializer.Deserialize(json, type, _setting);
		}

		public static string Serialize<T>(T value)
		{
			return JsonSerializer.Serialize(value, _setting);
		}
	}
}
namespace ExtraToolCustomization.Dependencies
{
	internal static class MTFOWrapper
	{
		public const string GUID = "com.dak.MTFO";

		public static string GameDataPath => MTFOPathAPI.RundownPath;

		public static string CustomPath => MTFOPathAPI.CustomPath;

		public static bool HasCustomContent => MTFOPathAPI.HasCustomPath;

		public static bool HasMTFO { get; private set; }

		static MTFOWrapper()
		{
			HasMTFO = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("com.dak.MTFO");
		}
	}
}