diff --git a/astealz-SmartSpawnController/BepInEx/plugins/astealz.SmartSpawn.dll b/astealz-SmartSpawnController/BepInEx/plugins/astealz.SmartSpawn.dll index cf657da..4a5814b 100644 Binary files a/astealz-SmartSpawnController/BepInEx/plugins/astealz.SmartSpawn.dll and b/astealz-SmartSpawnController/BepInEx/plugins/astealz.SmartSpawn.dll differ diff --git a/src/Patches/BotSpawnerPatches.BotSpawnerOnStartPatch.cs b/src/Patches/BotSpawnerPatches.BotSpawnerOnStartPatch.cs index 7ec25e0..da99cfe 100644 --- a/src/Patches/BotSpawnerPatches.BotSpawnerOnStartPatch.cs +++ b/src/Patches/BotSpawnerPatches.BotSpawnerOnStartPatch.cs @@ -16,7 +16,8 @@ namespace astealz.SmartSpawnController.Patches protected override MethodBase GetTargetMethod() { - return botSpawnerType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + return botSpawnerType + .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Single(); } diff --git a/src/Patches/BotSpawnerPatches.MaxBotsAliveOnMapPatch.cs b/src/Patches/BotSpawnerPatches.MaxBotsAliveOnMapPatch.cs index 157675a..db12748 100644 --- a/src/Patches/BotSpawnerPatches.MaxBotsAliveOnMapPatch.cs +++ b/src/Patches/BotSpawnerPatches.MaxBotsAliveOnMapPatch.cs @@ -8,7 +8,7 @@ namespace astealz.SmartSpawnController.Patches { class MaxBotsAliveOnMapPatch : GenericPatch { - private static string[] targetTypePublicProperties = new string[] { "BotsCountWithDelyaed", "AllTypes", "IsEnable" }; + private static string[] targetTypePublicProperties = new string[] { "BotsCountWithDelayed", "AllTypes", "IsEnable" }; public MaxBotsAliveOnMapPatch() : base(prefix: nameof(PatchPrefix)) { @@ -17,9 +17,7 @@ namespace astealz.SmartSpawnController.Patches protected override MethodBase GetTargetMethod() { // searching type with properties: BotsCountWithDelyaed, AllTypes, AiTaskManager - return typeof(EFT.GameWorld).Assembly.GetTypes() - .Single(type => targetTypePublicProperties.All(p => type.GetProperties(allFlags).Any(tp => tp.Name == p))) - .GetMethod("SetSettings"); + return typeof(BotControllerClass).GetMethod("SetSettings"); } private static void PatchPrefix(ref int maxCount) diff --git a/src/Patches/BotSpawnerPatches.cs b/src/Patches/BotSpawnerPatches.cs index 2f392ea..557e282 100644 --- a/src/Patches/BotSpawnerPatches.cs +++ b/src/Patches/BotSpawnerPatches.cs @@ -1,12 +1,14 @@ -using System; +using BepInEx.Logging; +using System; using System.Linq; using System.Reflection; namespace astealz.SmartSpawnController.Patches { - partial class BotSpawnerPatches + static partial class BotSpawnerPatches { const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + const BindingFlags publicInstanceDeclared = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; private static readonly Type scavWaveDataType; private static readonly Type botSpawnerType; @@ -18,6 +20,8 @@ namespace astealz.SmartSpawnController.Patches // ctor static BotSpawnerPatches() { + var logSource = Logger.CreateLogSource("test"); + var scavWaveDataTypeFieldNames = new[] { "ChanceGroup", @@ -31,32 +35,72 @@ namespace astealz.SmartSpawnController.Patches }; var types = typeof(EFT.GameWorld).Assembly.GetTypes(); + var botControllerClass = types.Single(x => x.Name == "BotControllerClass"); - scavWaveDataType = types - .Where(type => type != typeof(EFT.WildSpawnWave)) - .Where(type => type.GetFields(BindingFlags.Public | BindingFlags.Instance) - .Select(x => x.Name) - .DefaultIfEmpty("") - .All(scavWaveDataTypeFieldNames.Contains)) - .Single(); + if (botControllerClass is null) + { + logSource.LogInfo($"botcontroller null"); + } - botSpawnerType = types - .Where(type => type.GetMethod("SpawnZones", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) != null - && type.GetMethod("ActivateBotsByWave", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, new[] { scavWaveDataType }, null) != null) - .SingleOrDefault(); + var activateBotsByWaveMethod = botControllerClass.GetMethods().Single(x => x.Name == "ActivateBotsByWave" && x.GetParameters()[0].ParameterType != typeof(BossLocationSpawn)); + var firstParam = activateBotsByWaveMethod.GetParameters()[0]; + scavWaveDataType = firstParam.ParameterType; + botSpawnerType = types.Single(x => x.Name == "GClass1243"); + + if (botSpawnerType is null) + { + logSource.LogInfo($"botSpawnerType is null"); + } + + + //var dataTypes = types + // .Where(type => type != typeof(EFT.WildSpawnWave) && type.GetFields(BindingFlags.Public | BindingFlags.Instance) + // .Select(x => x.Name) + // .DefaultIfEmpty("") + // .All(scavWaveDataTypeFieldNames.Contains)); + + //var typesFound = dataTypes.Where(type => type.GetMethod("SpawnZones", publicInstanceDeclared) != null + // && type.GetMethod("ActivateBotsByWave", publicInstanceDeclared, null, new[] { scavWaveDataType }, null) != null); + + //foreach (var item in typesFound) + //{ + // logSource.LogInfo($"WOW found: {item.Name}"); + //} + + //scavWaveDataType = dataTypes.Single(); + + //if (scavWaveDataType is null) + //{ + // logSource.LogError("scavWaveDataType is null"); + //} + + //botSpawnerType = types.Single(type => type.GetMethod("SpawnZones", publicInstanceDeclared) != null + // && type.GetMethod("ActivateBotsByWave", publicInstanceDeclared, null, new[] { scavWaveDataType }, null) != null); + + //if (botSpawnerType is null) + //{ + // logSource.LogError("botSpawnerType is null"); + //} } /// /// Apply patches /// - public static bool Apply() + public static bool ApplyAllPatches(BepInEx.Logging.ManualLogSource logger) { + logger.LogInfo($"MaxBotsAliveOnMapPatch"); new MaxBotsAliveOnMapPatch().Apply(); + logger.LogInfo($"BotSpawnerOnStartPatch"); new BotSpawnerOnStartPatch().Apply(); + logger.LogInfo($"BotSpawnerOnActivateBotsByScavWavePatch"); new BotSpawnerOnActivateBotsByScavWavePatch().Apply(); + logger.LogInfo($"BotSpawnerOnActivateBotsByBossWavePatch"); new BotSpawnerOnActivateBotsByBossWavePatch().Apply(); + logger.LogInfo($"BotSpawnerOnStopPatch"); new BotSpawnerOnStopPatch().Apply(); + logger.LogInfo($"BotSpawnerDelayPatch"); new BotSpawnerDelayPatch().Apply(); + logger.LogInfo($"BotSpawnerOnBossActivationPatch"); new BotSpawnerOnBossActivationPatch().Apply(); return true; } diff --git a/src/SmartSpawnPlugin.cs b/src/SmartSpawnPlugin.cs index 437b897..86c1edd 100644 --- a/src/SmartSpawnPlugin.cs +++ b/src/SmartSpawnPlugin.cs @@ -1,4 +1,5 @@ -using BepInEx; +using astealz.SmartSpawnController.Patches; +using BepInEx; using Newtonsoft.Json; using System; @@ -21,16 +22,20 @@ namespace astealz.SmartSpawnController // get config from server var json = Aki.SinglePlayer.Utils.RequestHandler.GetJson($"/mods/{Name.ToLower()}/config"); - var config = JsonConvert.DeserializeObject(json); - - Globals.Config = config; + Globals.Config = JsonConvert.DeserializeObject(json); // apply patches - isApplyPatchesSuccess = Patches.BotSpawnerPatches.Apply(); + Logger.LogInfo("appying patches"); + + if (!isApplyPatchesSuccess) + { + isApplyPatchesSuccess = BotSpawnerPatches.ApplyAllPatches(Logger); + } } catch (Exception ex) { - Logger.LogError(ex.ToString()); + Logger.LogError($"Start failed: {ex.Message}"); + Logger.LogError($"Start failed: {ex.StackTrace}"); } } diff --git a/src/Utils/GenericPatch`.cs b/src/Utils/GenericPatch`.cs index d3e19d1..e12b955 100644 --- a/src/Utils/GenericPatch`.cs +++ b/src/Utils/GenericPatch`.cs @@ -6,11 +6,11 @@ namespace astealz.SmartSpawnController.Utils { public abstract class GenericPatch where T : GenericPatch { - private Harmony _harmony; - private HarmonyMethod _prefix; - private HarmonyMethod _postfix; - private HarmonyMethod _transpiler; - private HarmonyMethod _finalizer; + private readonly Harmony _harmony; + private readonly HarmonyMethod _prefix; + private readonly HarmonyMethod _postfix; + private readonly HarmonyMethod _transpiler; + private readonly HarmonyMethod _finalizer; public GenericPatch(string name = null, string prefix = null, string postfix = null, string transpiler = null, string finalizer = null) { @@ -52,7 +52,17 @@ namespace astealz.SmartSpawnController.Utils /// public void Apply() { - var targetMethod = GetTargetMethod(); + MethodBase targetMethod; + try + { + targetMethod = GetTargetMethod(); + } + catch (Exception ex) + { + + throw new Exception($"targetMethod bad: {typeof(T).Name}:", ex); + } + if (targetMethod == null) { @@ -65,7 +75,7 @@ namespace astealz.SmartSpawnController.Utils } catch (Exception ex) { - throw new Exception($"{_harmony.Id}:", ex); + throw new Exception($"{typeof(T).Name}:{_harmony.Id}:", ex); } }