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 Localization;
using MTFO.API;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using TMPro;
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+3eb3a5da0e6c2ca0808008b64f1ed875e27dd668")]
[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.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal sealed class EntryPoint : BasePlugin
{
public const string MODNAME = "ExtraToolCustomization";
public override void Load()
{
//IL_0043: 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)
((BasePlugin)this).Log.LogMessage((object)"Loading ExtraToolCustomization");
if (MTFOWrapper.HasMTFO && MTFOWrapper.HasCustomContent)
{
new Harmony("ExtraToolCustomization").PatchAll();
ToolDataManager.Current.Init();
MineDeployerManager.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; }
uint ArchetypeID { get; set; }
string Name { get; set; }
}
public sealed class MineData : IToolData
{
public uint OfflineID { get; set; }
public uint ItemID { get; set; }
[JsonIgnore]
public uint ArchetypeID { 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 float PlacementTime { get; set; } = 0.5f;
public float PlacementCooldown { get; set; } = 2f;
public float PickupTime { get; set; } = 0.5f;
}
public sealed class SentryData : IToolData
{
[JsonIgnore]
public uint OfflineID { get; set; }
[JsonIgnore]
public uint ItemID { get; set; }
public uint ArchetypeID { get; set; }
public string Name { get; set; } = string.Empty;
public bool BackDamage { get; set; }
}
internal static 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 static readonly Dictionary<uint, T> ArchData = 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>.ArchData.Remove(item.ArchetypeID);
}
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.ItemID} detected. Previous name: {ToolDataDict<T>.ItemData[data.ItemID].Name}, new name: {data.Name}");
}
ToolDataDict<T>.ItemData[data.ItemID] = data;
}
if (data.ArchetypeID != 0)
{
if (ToolDataDict<T>.ItemData.ContainsKey(data.ArchetypeID))
{
DinoLogger.Warning($"Duplicate {ToolDataDict<T>.Name} item ID {data.ArchetypeID} detected. Previous name: {ToolDataDict<T>.ArchData[data.ArchetypeID].Name}, new name: {data.Name}");
}
ToolDataDict<T>.ArchData[data.ArchetypeID] = 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());
}
if (ToolDataDict<T>.ArchData.Count > 0)
{
StringBuilder stringBuilder3 = new StringBuilder("Found custom blocks for " + ToolDataDict<T>.Name + " archetype IDs: ");
stringBuilder3.AppendJoin(", ", ToolDataDict<T>.ArchData.Keys.ToImmutableSortedSet());
DinoLogger.Log(stringBuilder3.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);
LoadDirectory("Sentry", SentryTemplate.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 static T? GetItemData<T>(uint id) where T : IToolData
{
return ToolDataDict<T>.ItemData.GetValueOrDefault(id);
}
public static T? GetOfflineData<T>(uint id) where T : IToolData
{
return ToolDataDict<T>.OfflineData.GetValueOrDefault(id);
}
public static T? GetArchData<T>(uint id) where T : IToolData
{
return ToolDataDict<T>.OfflineData.GetValueOrDefault(id);
}
public static T? GetData<T>(uint offlineID, uint itemID, uint archID) where T : IToolData
{
T val = default(T);
if (offlineID != 0)
{
val = GetOfflineData<T>(offlineID);
}
if (val == null && itemID != 0)
{
val = GetItemData<T>(itemID);
}
if (val == null && archID != 0)
{
val = GetArchData<T>(archID);
}
return val;
}
}
}
namespace ExtraToolCustomization.ToolData.Templates
{
internal static class MineTemplate
{
public static MineData[] Template = new MineData[2]
{
new MineData
{
Name = "Mine Deployer",
Delay = 0.25f,
Radius = 2.5f,
DistanceMin = 3f,
DistanceMax = 15f,
DamageMin = 15f,
DamageMax = 50f,
Force = 1000f
},
new MineData
{
Name = "Consumable Mine",
Delay = 0.25f,
Radius = 2f,
DistanceMin = 2.5f,
DistanceMax = 12f,
DamageMin = 10f,
DamageMax = 35f,
Force = 700f
}
};
}
internal static class SentryTemplate
{
public static SentryData[] Template = new SentryData[1]
{
new SentryData
{
OfflineID = 0u,
Name = "Sentry Gun",
BackDamage = false
}
};
}
}
namespace ExtraToolCustomization.Patches
{
[HarmonyPatch]
internal static class MineDeployerPatches
{
[HarmonyPatch(typeof(MineDeployerFirstPerson), "OnGearSpawnComplete")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void Post_Setup(MineDeployerFirstPerson __instance)
{
MineData data = ToolDataManager.GetData<MineData>(((ItemEquippable)__instance).GearIDRange?.GetOfflineID() ?? 0, ((GameDataBlockBase<ItemDataBlock>)(object)((Item)__instance).ItemDataBlock).persistentID, 0u);
if (data != null)
{
((Interact_Timed)__instance.m_interactPlaceItem).InteractDuration = data.PlacementTime;
__instance.m_timeBetweenPlacements = data.PlacementCooldown;
}
}
[HarmonyPatch(typeof(PlayerBotActionDeployTripMine), "PlaceTripMine")]
[HarmonyWrapSafe]
[HarmonyPrefix]
private static void Pre_PlaceMineBot(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(typeof(MineDeployerFirstPerson), "OnStickyMineSpawned")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void Post_DeployedMine(MineDeployerFirstPerson __instance, ISyncedItem item)
{
if (__instance.m_isConsumable)
{
return;
}
MineData data = ToolDataManager.GetData<MineData>(((ItemEquippable)__instance).GearIDRange?.GetOfflineID() ?? 0, ((GameDataBlockBase<ItemDataBlock>)(object)((Item)__instance).ItemDataBlock).persistentID, 0u);
if (data != null)
{
MineDeployerInstance val = ((Il2CppObjectBase)item.GetItem()).TryCast<MineDeployerInstance>();
if ((Object)(object)val != (Object)null)
{
((Il2CppObjectBase)((Item)val).PickupInteraction).Cast<Interact_Timed>().InteractDuration = data.PickupTime;
}
}
}
}
[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_InventorySlotItem), "LoadData")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void Post_LoadData(CM_InventorySlotItem __instance)
{
if (_cachedArchetype != null)
{
__instance.GearDescription = LocalizedText.op_Implicit(_cachedArchetype.Description);
__instance.GearArchetypeName = LocalizedText.op_Implicit(_cachedArchetype.PublicName);
((TMP_Text)((CM_LobbyScrollItem)__instance).m_subTitleText).text = __instance.m_archetypePrefix + __instance.GearArchetypeName;
TMP_UpdateManager.RegisterTextElementForGraphicRebuild((TMP_Text)(object)((CM_LobbyScrollItem)__instance).m_subTitleText);
}
}
[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_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: 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_0085: Expected I4, but got Unknown
if (_cachedRange != null && ((Il2CppObjectBase)_cachedRange).Pointer == ((Il2CppObjectBase)idRange).Pointer)
{
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(typeof(BulletWeapon), "BulletHit")]
[HarmonyPriority(200)]
[HarmonyPrefix]
private static void SetBackDamage(ref WeaponHitData weaponRayData, ref bool allowDirectionalBonus)
{
PlayerBackpack val = default(PlayerBackpack);
BackpackItem val2 = default(BackpackItem);
if ((!allowDirectionalBonus || weaponRayData.vfxBulletHit != null) && PlayerBackpackManager.TryGetBackpack(weaponRayData.owner.Owner, ref val) && val.TryGetBackpackItem((InventorySlot)3, ref val2))
{
SentryData archData = ToolDataManager.GetArchData<SentryData>(((Il2CppObjectBase)val2.Instance).Cast<ItemEquippable>().ArchetypeID);
if (archData != null)
{
allowDirectionalBonus = archData.BackDamage;
}
}
}
}
[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)
{
return ToolDataManager.GetData<MineData>(deployerID.offlineID, deployerID.itemID, 0u);
}
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");
}
}
}