Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of EnemySpawnRange v4.0.0
EnemySpawnRange.dll
Decompiled 2 months agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("REPOJP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabuMod")] [assembly: AssemblyTitle("zabuMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 REPOJP.EnemySpawnRange { [BepInPlugin("REPOJP.EnemySpawnRange", "EnemySpawnRange", "1.1.0")] public sealed class EnemySpawnRangePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(SemiFunc), "EnemySpawn")] private static class SemiFunc_EnemySpawn_Patch { private static bool Prefix(Enemy enemy, ref bool __result) { try { if (!CanRunCustomSpawn(enemy)) { return true; } GetResolvedSpawnDistance(out var minDistance, out var maxDistance); if (TryCustomSpawn(enemy, minDistance, maxDistance, out var blockedPointEncountered)) { __result = true; return false; } bool flag = blockedPointEncountered; if (FallbackToVanillaOnFailure.Value && !IsVanillaDistance(minDistance, maxDistance)) { if (TryVanillaSpawn(enemy, 18f, 35f, out var blockedPointEncountered2)) { WriteLog($"FallbackSuccess Enemy={((object)enemy).GetType().Name}"); __result = true; return false; } flag = flag || blockedPointEncountered2; } FinalizeSpawnFailure(enemy, flag); WriteLog(string.Format("Failure Enemy={0}", ((Object)(object)enemy != (Object)null) ? ((object)enemy).GetType().Name : "null")); __result = false; return false; } catch (Exception ex) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"Failure: SemiFunc.EnemySpawn"); ((BaseUnityPlugin)Instance).Logger.LogError((object)ex); } return true; } } } public const string PluginGuid = "REPOJP.EnemySpawnRange"; public const string PluginName = "EnemySpawnRange"; public const string PluginVersion = "1.1.0"; internal static EnemySpawnRangePlugin Instance; private Harmony harmony; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<float> MinSpawnDistance; internal static ConfigEntry<float> MaxSpawnDistance; internal static ConfigEntry<bool> RespectDebugSpawnClose; internal static ConfigEntry<bool> FallbackToVanillaOnFailure; internal static ConfigEntry<bool> ExcludeArena; internal static ConfigEntry<bool> ExcludeShop; internal static ConfigEntry<bool> RequireLevelGenerated; internal static ConfigEntry<bool> LogEnabled; private static FieldInfo enemyParentFirstSpawnPointUsedField; private static FieldInfo enemyDirectorDebugSpawnCloseField; private static FieldInfo roundDirectorAllExtractionPointsCompletedField; private static FieldInfo enemyRigidbodyRbField; private void Awake() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown try { Instance = this; if ((Object)(object)((Component)this).transform.parent != (Object)null) { ((Component)this).transform.parent = null; } ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); InitializeConfig(); InitializeReflection(); harmony = new Harmony("REPOJP.EnemySpawnRange"); harmony.PatchAll(); WriteAlways("Loaded v1.1.0"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Failure: Awake"); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Failure: OnDestroy"); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void InitializeConfig() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ModEnabled", true, "Enable or disable this mod. MOD有効無効"); MinSpawnDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinSpawnDistance", 5f, new ConfigDescription("Minimum player distance allowed for enemy spawn points. 敵スポーン候補の最小距離", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999f), Array.Empty<object>())); MaxSpawnDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxSpawnDistance", 15f, new ConfigDescription("Maximum player distance allowed for enemy spawn points. 敵スポーン候補の最大距離", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999f), Array.Empty<object>())); RespectDebugSpawnClose = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "RespectDebugSpawnClose", true, "Use the game's debugSpawnClose behavior when enabled. ゲーム本体のdebugSpawnClose有効時に0-999を優先"); FallbackToVanillaOnFailure = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "FallbackToVanillaOnFailure", true, "Retry with vanilla 18-35 range if custom spawn fails. 設定距離失敗時に18-35で再試行"); ExcludeArena = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "ExcludeArena", true, "Do not override enemy spawn distance in arena levels. アリーナでは敵スポーン距離を変更しない"); ExcludeShop = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "ExcludeShop", true, "Do not override enemy spawn distance in shop levels. ショップでは敵スポーン距離を変更しない"); RequireLevelGenerated = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "RequireLevelGenerated", true, "Run only after level generation is completed. レベル生成完了後のみ実行"); LogEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogEnabled", false, "Enable detailed log output. 詳細ログ出力"); } private void InitializeReflection() { enemyParentFirstSpawnPointUsedField = AccessTools.Field(typeof(EnemyParent), "firstSpawnPointUsed"); enemyDirectorDebugSpawnCloseField = AccessTools.Field(typeof(EnemyDirector), "debugSpawnClose"); roundDirectorAllExtractionPointsCompletedField = AccessTools.Field(typeof(RoundDirector), "allExtractionPointsCompleted"); enemyRigidbodyRbField = AccessTools.Field(typeof(EnemyRigidbody), "rb"); } internal static void WriteAlways(string message) { if (!((Object)(object)Instance == (Object)null)) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[EnemySpawnRange] " + message)); } } internal static void WriteLog(string message) { if (!((Object)(object)Instance == (Object)null) && LogEnabled != null && LogEnabled.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[EnemySpawnRange] " + message)); } } internal static bool IsSafeGameplayLevel() { try { if ((Object)(object)RunManager.instance == (Object)null) { return false; } if ((Object)(object)LevelGenerator.Instance == (Object)null) { return false; } if (RequireLevelGenerated.Value && !LevelGenerator.Instance.Generated) { return false; } if (ExcludeShop.Value && SemiFunc.RunIsShop()) { return false; } if (ExcludeArena.Value && SemiFunc.RunIsArena()) { return false; } if (!SemiFunc.RunIsLevel()) { return false; } return true; } catch (Exception ex) { WriteLog("IsSafeGameplayLevel failure: " + ex.Message); return false; } } internal static bool CanRunCustomSpawn(Enemy enemy) { try { if (ModEnabled == null || !ModEnabled.Value) { return false; } if ((Object)(object)enemy == (Object)null) { return false; } if (!IsSafeGameplayLevel()) { return false; } if ((Object)(object)EnemyDirector.instance == (Object)null) { return false; } if ((Object)(object)GameDirector.instance == (Object)null) { return false; } if (GameDirector.instance.PlayerList == null) { return false; } if (GameDirector.instance.PlayerList.Count == 0) { return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } return true; } catch (Exception ex) { WriteLog("CanRunCustomSpawn failure: " + ex.Message); return false; } } internal static bool IsDebugSpawnCloseEnabled() { try { if ((Object)(object)EnemyDirector.instance == (Object)null) { return false; } if (enemyDirectorDebugSpawnCloseField == null) { return false; } object value = enemyDirectorDebugSpawnCloseField.GetValue(EnemyDirector.instance); if (value is bool) { return (bool)value; } } catch (Exception ex) { WriteLog("DebugSpawnClose read failure: " + ex.Message); } return false; } internal static bool AreAllExtractionPointsCompleted() { try { if ((Object)(object)RoundDirector.instance == (Object)null) { return false; } if (roundDirectorAllExtractionPointsCompletedField == null) { return false; } object value = roundDirectorAllExtractionPointsCompletedField.GetValue(RoundDirector.instance); if (value is bool) { return (bool)value; } } catch (Exception ex) { WriteLog("AllExtractionPointsCompleted read failure: " + ex.Message); } return false; } internal static void GetResolvedSpawnDistance(out float minDistance, out float maxDistance) { minDistance = Mathf.Max(0f, MinSpawnDistance.Value); maxDistance = Mathf.Max(0f, MaxSpawnDistance.Value); if (minDistance > maxDistance) { float num = minDistance; minDistance = maxDistance; maxDistance = num; } if (RespectDebugSpawnClose.Value && IsDebugSpawnCloseEnabled()) { minDistance = 0f; maxDistance = 999f; } } internal static bool IsVanillaDistance(float minDistance, float maxDistance) { return Mathf.Approximately(minDistance, 18f) && Mathf.Approximately(maxDistance, 35f); } internal static EnemyParent GetEnemyParent(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return null; } return ((Component)enemy).GetComponentInParent<EnemyParent>(); } internal static void SetFirstSpawnPointUsed(EnemyParent enemyParent, bool value) { try { if (!((Object)(object)enemyParent == (Object)null) && !(enemyParentFirstSpawnPointUsedField == null)) { enemyParentFirstSpawnPointUsedField.SetValue(enemyParent, value); } } catch (Exception ex) { WriteLog("SetFirstSpawnPointUsed failure: " + ex.Message); } } internal static EnemyRigidbody GetEnemyRigidbody(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return null; } return ((Component)enemy).GetComponentInChildren<EnemyRigidbody>(); } internal static Rigidbody GetUnityRigidbody(EnemyRigidbody enemyRigidbody) { try { if ((Object)(object)enemyRigidbody == (Object)null) { return null; } if (enemyRigidbodyRbField == null) { return null; } object? value = enemyRigidbodyRbField.GetValue(enemyRigidbody); return (Rigidbody)((value is Rigidbody) ? value : null); } catch (Exception ex) { WriteLog("GetUnityRigidbody failure: " + ex.Message); return null; } } internal static bool IsBlockedSpawn(Enemy enemy, Vector3 targetPosition) { //IL_002d: 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) //IL_001d: Unknown result type (might be due to invalid IL or missing references) try { EnemyRigidbody enemyRigidbody = GetEnemyRigidbody(enemy); Rigidbody unityRigidbody = GetUnityRigidbody(enemyRigidbody); if ((Object)(object)unityRigidbody != (Object)null) { return SemiFunc.EnemyPhysObjectBoundingBoxCheck(targetPosition, targetPosition, unityRigidbody, false, 1.2f); } return SemiFunc.EnemyPhysObjectSphereCheck(targetPosition, 1f); } catch (Exception ex) { WriteLog("IsBlockedSpawn failure: " + ex.Message); return true; } } internal static LevelPoint GetCustomSpawnLevelPoint(Vector3 currentPosition, float minDistance, float maxDistance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) LevelPoint val = null; if (AreAllExtractionPointsCompleted()) { val = SemiFunc.LevelPointGetPlayerDistance(currentPosition, minDistance, maxDistance, true); } if (!Object.op_Implicit((Object)(object)val)) { val = SemiFunc.LevelPointGetPlayerDistance(currentPosition, minDistance, maxDistance, false); } return val; } internal static LevelPoint GetVanillaSpawnLevelPoint(Enemy enemy, float minDistance, float maxDistance) { if ((Object)(object)enemy == (Object)null) { return null; } return enemy.TeleportToPoint(minDistance, maxDistance); } internal static bool TryCustomSpawn(Enemy enemy, float minDistance, float maxDistance, out bool blockedPointEncountered) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) blockedPointEncountered = false; EnemyParent enemyParent = GetEnemyParent(enemy); if ((Object)(object)enemyParent == (Object)null) { WriteLog("CustomSpawn enemyParent not found"); return false; } LevelPoint customSpawnLevelPoint = GetCustomSpawnLevelPoint(((Component)enemy).transform.position, minDistance, maxDistance); if (!Object.op_Implicit((Object)(object)customSpawnLevelPoint)) { WriteLog($"Custom NoPoint Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###}"); return false; } Vector3 position = ((Component)customSpawnLevelPoint).transform.position; if (IsBlockedSpawn(enemy, position)) { blockedPointEncountered = true; WriteLog($"Custom Blocked Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###} Point=({position.x:0.##}, {position.y:0.##}, {position.z:0.##})"); return false; } enemy.EnemyTeleported(position); SetFirstSpawnPointUsed(enemyParent, value: true); WriteLog($"Custom Success Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###} Point=({position.x:0.##}, {position.y:0.##}, {position.z:0.##})"); return true; } internal static bool TryVanillaSpawn(Enemy enemy, float minDistance, float maxDistance, out bool blockedPointEncountered) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) blockedPointEncountered = false; EnemyParent enemyParent = GetEnemyParent(enemy); if ((Object)(object)enemyParent == (Object)null) { WriteLog("VanillaSpawn enemyParent not found"); return false; } LevelPoint vanillaSpawnLevelPoint = GetVanillaSpawnLevelPoint(enemy, minDistance, maxDistance); if (!Object.op_Implicit((Object)(object)vanillaSpawnLevelPoint)) { WriteLog($"Vanilla NoPoint Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###}"); return false; } Vector3 position = ((Component)vanillaSpawnLevelPoint).transform.position; if (IsBlockedSpawn(enemy, position)) { blockedPointEncountered = true; WriteLog($"Vanilla Blocked Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###} Point=({position.x:0.##}, {position.y:0.##}, {position.z:0.##})"); return false; } SetFirstSpawnPointUsed(enemyParent, value: true); WriteLog($"Vanilla Success Enemy={((object)enemy).GetType().Name} Min={minDistance:0.###} Max={maxDistance:0.###} Point=({position.x:0.##}, {position.y:0.##}, {position.z:0.##})"); return true; } internal static void FinalizeSpawnFailure(Enemy enemy, bool blockedPointEncountered) { try { EnemyParent enemyParent = GetEnemyParent(enemy); if (!((Object)(object)enemyParent == (Object)null)) { if (blockedPointEncountered && (Object)(object)EnemyDirector.instance != (Object)null) { EnemyDirector.instance.FirstSpawnPointAdd(enemyParent); } enemyParent.Despawn(); enemyParent.DespawnedTimerSet(Random.Range(2f, 3f), true); } } catch (Exception ex) { WriteLog("FinalizeSpawnFailure failure: " + ex.Message); } } } }