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 internal test ignore v1.0.0
Matsu.MergedEnemyMod.dll
Decompiled 3 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using REPOLib.Modules; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Matsu.MergedEnemyMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Matsu.MergedEnemyMod")] [assembly: AssemblyTitle("Matsu.MergedEnemyMod")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 Matsu.MergedEnemyMod { internal static class FusionShared { private static ParticleScriptExplosion? _sharedExplosion; private static GameObject? _explosionPrefab; public static void HurtPlayersInRadius(Vector3 center, float radius, int maxDamage) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (maxDamage <= 0) { return; } PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>(); foreach (PlayerAvatar val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.playerHealth == (Object)null) { continue; } float num = Vector3.Distance(center, ((Component)val).transform.position); if (!(num > radius)) { int num2 = Mathf.RoundToInt(Mathf.Lerp((float)maxDamage, (float)maxDamage * 0.3f, num / radius)); if (num2 > 0) { val.playerHealth.HurtOther(num2, center, false, -1, false); } } } } public static bool NearestPlayerWithin(Vector3 from, float range) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>(); foreach (PlayerAvatar val in array) { if (!((Object)(object)val == (Object)null) && Vector3.Distance(from, ((Component)val).transform.position) <= range) { return true; } } return false; } public static void SpawnExplosionVfx(Vector3 pos, float size) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_sharedExplosion == (Object)null) { _sharedExplosion = Object.FindObjectOfType<ParticleScriptExplosion>(true); } if ((Object)(object)_sharedExplosion != (Object)null) { try { _sharedExplosion.Spawn(pos, size, 0, 0, 3f, true, false, 1f); return; } catch { } } if ((Object)(object)_explosionPrefab == (Object)null) { _explosionPrefab = Resources.Load<GameObject>("Effects/Part Prefab Explosion"); } if ((Object)(object)_explosionPrefab != (Object)null) { ParticlePrefabExplosion component = Object.Instantiate<GameObject>(_explosionPrefab, pos, Quaternion.identity).GetComponent<ParticlePrefabExplosion>(); if ((Object)(object)component != (Object)null) { component.onlyParticleEffect = true; } } } public static void AddAuraLight(Transform parent, float range = 6f, float intensity = 2.5f) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("FusionAura"); val.transform.SetParent(parent, false); val.transform.localPosition = Vector3.up * 0.5f; Light obj = val.AddComponent<Light>(); obj.type = (LightType)2; obj.color = new Color(1f, 0.4f, 0f); obj.range = range; obj.intensity = intensity; } } public class BoomdayBoyFusion : MonoBehaviour { private EnemyBirthdayBoy _birthday; private EnemyHealth? _health; private bool _fuseLit; private bool _deathDetonated; private float _fuseTimer; private float _explodeCooldown; private float _retintTimer; private float _proximityTimer; private void Awake() { _birthday = ((Component)this).GetComponent<EnemyBirthdayBoy>(); _health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>(); if ((Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.BoomdayHealthMultiplier.Value)); } FusionShared.AddAuraLight(((Component)this).transform); } private void Update() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || _deathDetonated || (Object)(object)_birthday == (Object)null) { return; } _retintTimer -= Time.deltaTime; if (_retintTimer <= 0f) { _retintTimer = 1f; TintBalloonsOrange(); } if (_explodeCooldown > 0f) { _explodeCooldown -= Time.deltaTime; } _proximityTimer -= Time.deltaTime; if (!_fuseLit && _explodeCooldown <= 0f && _proximityTimer <= 0f) { _proximityTimer = 0.25f; if (FusionShared.NearestPlayerWithin(((Component)this).transform.position, Plugin.BoomdayFuseRange.Value)) { _fuseLit = true; _fuseTimer = Plugin.BoomdayFuseTime.Value; Plugin.Log.LogInfo((object)"[BoomdayBoy] Fuse lit!"); } } if (_fuseLit) { _fuseTimer -= Time.deltaTime; if (_fuseTimer <= 0f) { ProximityExplode(); } } } private void ProximityExplode() { //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) Vector3 position = ((Component)this).transform.position; FusionShared.SpawnExplosionVfx(position, 1.3f); FusionShared.HurtPlayersInRadius(position, 6f, Plugin.BoomdayCoreDamage.Value); Plugin.Log.LogInfo((object)"[BoomdayBoy] BOOM (recurring)!"); _fuseLit = false; _explodeCooldown = Plugin.BoomdayExplodeCooldown.Value; } public void Detonate() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!_deathDetonated) { _deathDetonated = true; Vector3 position = ((Component)this).transform.position; FusionShared.SpawnExplosionVfx(position, 1.6f); FusionShared.HurtPlayersInRadius(position, 7f, Plugin.BoomdayCoreDamage.Value); ChainExplodeBalloons(); Plugin.Log.LogInfo((object)"[BoomdayBoy] Death blast + balloon chain reaction!"); } } private void ChainExplodeBalloons() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_birthday == (Object)null) { return; } foreach (GameObject item in new List<GameObject>(_birthday.balloons.Values)) { if (!((Object)(object)item == (Object)null)) { Vector3 position = item.transform.position; FusionShared.SpawnExplosionVfx(position, 0.7f); FusionShared.HurtPlayersInRadius(position, 3f, Plugin.BoomdayBalloonDamage.Value); if ((Object)(object)_birthday.balloonPopEffect != (Object)null) { Object.Instantiate<GameObject>(_birthday.balloonPopEffect, position, Quaternion.identity); } Object.Destroy((Object)(object)item); } } _birthday.balloons.Clear(); } private void TintBalloonsOrange() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_birthday == (Object)null) { return; } foreach (GameObject value in _birthday.balloons.Values) { if ((Object)(object)value == (Object)null) { continue; } Renderer[] componentsInChildren = value.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { MaterialPropertyBlock val2 = new MaterialPropertyBlock(); val.GetPropertyBlock(val2); val2.SetColor("_Color", new Color(1f, 0.45f, 0f)); val2.SetColor("_EmissionColor", new Color(1f, 0.35f, 0f) * 1.5f); val.SetPropertyBlock(val2); } } } } } public class JuggernautFusion : MonoBehaviour { private EnemyFloater _floater; private EnemyHealth? _health; private Enemy? _enemy; private float _stompCooldown; private void Awake() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) _floater = ((Component)this).GetComponent<EnemyFloater>(); _health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>(); _enemy = ((Component)this).GetComponentInParent<Enemy>() ?? ((Component)this).GetComponentInChildren<Enemy>(); if ((Object)(object)_health != (Object)null) { _health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.JuggernautHealthMultiplier.Value)); } if ((Object)(object)_enemy != (Object)null) { _enemy.Type = (EnemyType)4; } FusionShared.AddAuraLight(((Component)this).transform, 8f, 3f); _stompCooldown = Plugin.JuggernautStompInterval.Value; } private void Update() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { _stompCooldown -= Time.deltaTime; if (!(_stompCooldown > 0f) && FusionShared.NearestPlayerWithin(((Component)this).transform.position, Plugin.JuggernautStompRange.Value)) { _stompCooldown = Plugin.JuggernautStompInterval.Value; Stomp(); } } } private void Stomp() { //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) Vector3 position = ((Component)this).transform.position; FusionShared.SpawnExplosionVfx(position, 1.6f); FusionShared.HurtPlayersInRadius(position, Plugin.JuggernautStompRadius.Value, Plugin.JuggernautStompDamage.Value); Plugin.Log.LogInfo((object)"[Juggernaut] STOMP shockwave!"); } } [BepInPlugin("com.matsu.mergedenemymod", "Matsu Merged Enemy Mod", "0.3.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.matsu.mergedenemymod"; public const string Name = "Matsu Merged Enemy Mod"; public const string Version = "0.3.0"; public static ConfigEntry<float> MutationChancePerLevel; public static ConfigEntry<float> MutationMaxChance; public static ConfigEntry<float> BoomdayHealthMultiplier; public static ConfigEntry<float> BoomdayFuseRange; public static ConfigEntry<float> BoomdayFuseTime; public static ConfigEntry<float> BoomdayExplodeCooldown; public static ConfigEntry<int> BoomdayCoreDamage; public static ConfigEntry<int> BoomdayBalloonDamage; public static ConfigEntry<float> JuggernautHealthMultiplier; public static ConfigEntry<float> JuggernautStompInterval; public static ConfigEntry<float> JuggernautStompRange; public static ConfigEntry<float> JuggernautStompRadius; public static ConfigEntry<int> JuggernautStompDamage; public static ConfigEntry<KeyCode> DebugSpawnBoomdayKey; public static ConfigEntry<KeyCode> DebugSpawnJuggernautKey; internal static float ForceFuseUntil; private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; MutationChancePerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "ChancePerLevel", 0.01f, "Fusion (mutation) chance added per level. 0.01 = +1% per level (level 1 = 1%, level 10 = 10%)."); MutationMaxChance = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "MaxChance", 1f, "Upper cap (0..1) for the level-scaled fusion chance."); BoomdayHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "HealthMultiplier", 1.5f, "Health multiplier."); BoomdayFuseRange = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "FuseRange", 4f, "Player distance that lights the fuse."); BoomdayFuseTime = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "FuseTime", 2.5f, "Seconds from fuse lit to an explosion."); BoomdayExplodeCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "ExplodeCooldown", 4f, "Seconds before a Boomday Boy can explode again. It survives its own blasts (recurring threat)."); BoomdayCoreDamage = ((BaseUnityPlugin)this).Config.Bind<int>("BoomdayBoy", "CoreDamage", 60, "Explosion max damage."); BoomdayBalloonDamage = ((BaseUnityPlugin)this).Config.Bind<int>("BoomdayBoy", "BalloonDamage", 25, "Per-balloon explosion max damage (death chain)."); JuggernautHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Juggernaut", "HealthMultiplier", 4f, "Health multiplier (tanky)."); JuggernautStompInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Juggernaut", "StompInterval", 5f, "Seconds between stomps."); JuggernautStompRange = ((BaseUnityPlugin)this).Config.Bind<float>("Juggernaut", "StompRange", 7f, "It only stomps when a player is within this range."); JuggernautStompRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Juggernaut", "StompRadius", 6f, "Stomp shockwave damage radius."); JuggernautStompDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Juggernaut", "StompDamage", 40, "Stomp shockwave max damage."); DebugSpawnBoomdayKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnBoomdayKey", (KeyCode)290, "Press (host only) to spawn a Boomday Boy in front of your camera."); DebugSpawnJuggernautKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnJuggernautKey", (KeyCode)291, "Press (host only) to spawn a Juggernaut in front of your camera."); _harmony = new Harmony("com.matsu.mergedenemymod"); _harmony.PatchAll(); Log.LogInfo((object)string.Format("{0} {1} loaded. Mutation chance = level x {2:P0}. Debug: Boomday Boy (F9), Juggernaut (F10).", "Matsu Merged Enemy Mod", "0.3.0", MutationChancePerLevel.Value)); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(DebugSpawnBoomdayKey.Value)) { DebugSpawn("Birthday", typeof(EnemyBirthdayBoy), "Boomday Boy"); } if (Input.GetKeyDown(DebugSpawnJuggernautKey.Value)) { DebugSpawn("Floater", typeof(EnemyFloater), "Juggernaut"); } } private static void DebugSpawn(string nameContains, Type componentType, string label) { //IL_0044: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.IsMasterClientOrSingleplayer()) { Log.LogWarning((object)"[Debug] Spawn is host-only."); return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { Log.LogWarning((object)"[Debug] No main camera; are you in a level?"); return; } Vector3 val = ((Component)main).transform.position + ((Component)main).transform.forward * 3f; EnemySetup val2 = FindEnemySetup(nameContains, componentType); if ((Object)(object)val2 == (Object)null) { Log.LogWarning((object)("[Debug] " + label + " base enemy setup not found.")); return; } ForceFuseUntil = Time.time + 5f; Enemies.SpawnEnemy(val2, val, Quaternion.identity, false); Log.LogInfo((object)$"[Debug] Spawned a {label} at {val}."); } catch (Exception arg) { Log.LogError((object)$"[Debug] spawn error: {arg}"); } } private static EnemySetup? FindEnemySetup(string nameContains, Type componentType) { foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if ((Object)(object)allEnemy != (Object)null && ((Object)allEnemy).name.IndexOf(nameContains, StringComparison.OrdinalIgnoreCase) >= 0) { return allEnemy; } } foreach (EnemySetup allEnemy2 in Enemies.AllEnemies) { if (allEnemy2?.spawnObjects == null) { continue; } foreach (PrefabRef spawnObject in allEnemy2.spawnObjects) { GameObject val = ((PrefabRef<GameObject>)(object)spawnObject)?.Prefab; if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponentInChildren(componentType, true) != (Object)null) { return allEnemy2; } } } return null; } } [HarmonyPatch(typeof(EnemyParent), "Spawn")] internal static class EnemyParent_Spawn_Patch { private static void Postfix(EnemyParent __instance) { try { if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)__instance == (Object)null) { return; } float num = ((Time.time <= Plugin.ForceFuseUntil) ? 1f : GetMutationChance()); EnemyBirthdayBoy componentInChildren = ((Component)__instance).GetComponentInChildren<EnemyBirthdayBoy>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((Component)componentInChildren).GetComponent<BoomdayBoyFusion>() == (Object)null) { if (Random.value <= num) { ((Component)componentInChildren).gameObject.AddComponent<BoomdayBoyFusion>(); Plugin.Log.LogInfo((object)"[BoomdayBoy] A Birthday Boy became a Boomday Boy."); } return; } EnemyFloater componentInChildren2 = ((Component)__instance).GetComponentInChildren<EnemyFloater>(); if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)((Component)componentInChildren2).GetComponent<JuggernautFusion>() == (Object)null && Random.value <= num) { ((Component)componentInChildren2).gameObject.AddComponent<JuggernautFusion>(); Plugin.Log.LogInfo((object)"[Juggernaut] A Floater became a Juggernaut."); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[Fusion] spawn patch error: {arg}"); } } private static float GetMutationChance() { RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null) { return 0f; } return Mathf.Clamp((float)(instance.levelsCompleted + 1) * Plugin.MutationChancePerLevel.Value, 0f, Plugin.MutationMaxChance.Value); } } [HarmonyPatch(typeof(EnemyBirthdayBoy), "OnDeath")] internal static class EnemyBirthdayBoy_OnDeath_Patch { private static void Postfix(EnemyBirthdayBoy __instance) { try { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { BoomdayBoyFusion component = ((Component)__instance).GetComponent<BoomdayBoyFusion>(); if ((Object)(object)component != (Object)null) { component.Detonate(); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"[BoomdayBoy] OnDeath patch error: {arg}"); } } } }
Matsu.REPOCompatPatch.dll
Decompiled 3 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Matsu.REPOCompatPatch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.4.0")] [assembly: AssemblyInformationalVersion("1.3.4")] [assembly: AssemblyProduct("Matsu.REPOCompatPatch")] [assembly: AssemblyTitle("Matsu.REPOCompatPatch")] [assembly: AssemblyVersion("1.3.4.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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; } } } public static class GhostMeshVisualizerBridge { public static bool Show => false; } public static class PathsVisualizerBridge { public static bool Show => false; } public static class ValuablesVisualizerBridge { public static bool Show => false; } public static class InvisibleColliderVisualizerBridge { public static bool Show => false; } namespace Matsu.REPOCompatPatch { internal sealed class DeathSyncBehaviour : MonoBehaviour, IInRoomCallbacks, IOnEventCallback { internal const byte DeathSyncEventCode = 77; private static MethodInfo? isMasterOrSpMethod; private static bool isMasterResolved; private static FieldInfo? statsInstanceField; private static FieldInfo? saveFileCurrentField; private static bool statsResolved; private string? loadedSaveFile; private float pollTimer; private static string SaveDir => Path.Combine(Application.persistentDataPath, "MatsuDeathCounter"); private void OnEnable() { try { PhotonNetwork.AddCallbackTarget((object)this); } catch (Exception ex) { Plugin.TrackerErr("[DeathCounter] AddCallbackTarget failed: " + ex.Message); } } private void OnDisable() { try { PhotonNetwork.RemoveCallbackTarget((object)this); } catch { } } private void Update() { if (!IsHost()) { return; } pollTimer += Time.deltaTime; if (pollTimer < 1f) { return; } pollTimer = 0f; string saveFileCurrent = GetSaveFileCurrent(); if (!(saveFileCurrent == loadedSaveFile)) { loadedSaveFile = saveFileCurrent; Plugin.DeathCountsBySteamId.Clear(); Plugin.PlayerNamesBySteamId.Clear(); if (!string.IsNullOrEmpty(saveFileCurrent)) { LoadFromDisk(saveFileCurrent); BroadcastDeaths(); } } } public void OnEvent(EventData photonEvent) { if (photonEvent.Code != 77 || IsHost()) { return; } try { if (!(photonEvent.CustomData is object[] array) || array.Length < 3) { return; } string[] array2 = array[0] as string[]; int[] array3 = array[1] as int[]; string[] array4 = array[2] as string[]; if (array2 == null || array3 == null || array4 == null) { return; } Plugin.DeathCountsBySteamId.Clear(); Plugin.PlayerNamesBySteamId.Clear(); for (int i = 0; i < array2.Length && i < array3.Length; i++) { if (!string.IsNullOrEmpty(array2[i])) { Plugin.DeathCountsBySteamId[array2[i]] = array3[i]; if (i < array4.Length && !string.IsNullOrEmpty(array4[i])) { Plugin.PlayerNamesBySteamId[array2[i]] = array4[i]; } } } } catch (Exception ex) { Plugin.TrackerErr("[DeathCounter] apply snapshot failed: " + ex.Message); } } public void OnPlayerEnteredRoom(Player newPlayer) { if (IsHost()) { BroadcastDeaths(); } } public void OnPlayerLeftRoom(Player otherPlayer) { } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { } public void OnMasterClientSwitched(Player newMasterClient) { } internal static void OnHostDeath(string steamId, string name) { string text = ((!string.IsNullOrEmpty(steamId)) ? steamId : name); if (!string.IsNullOrEmpty(text)) { Plugin.DeathCountsBySteamId.TryGetValue(text, out var value); Plugin.DeathCountsBySteamId[text] = value + 1; if (!string.IsNullOrEmpty(name)) { Plugin.PlayerNamesBySteamId[text] = name; } Plugin.TrackerLog($"[DeathCounter] {(string.IsNullOrEmpty(name) ? text : name)} died. Total: {Plugin.DeathCountsBySteamId[text]}"); SaveToDisk(); BroadcastDeaths(); } } private static void BroadcastDeaths() { //IL_0017: 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_001e: 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) //IL_002d: Expected O, but got Unknown try { if (PhotonNetwork.InRoom && !PhotonNetwork.OfflineMode) { PhotonNetwork.RaiseEvent((byte)77, (object)Pack(), new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } } catch (Exception ex) { Plugin.TrackerErr("[DeathCounter] broadcast failed: " + ex.Message); } } private static object[] Pack() { int count = Plugin.DeathCountsBySteamId.Count; string[] array = new string[count]; int[] array2 = new int[count]; string[] array3 = new string[count]; int num = 0; foreach (KeyValuePair<string, int> item in Plugin.DeathCountsBySteamId) { array[num] = item.Key; array2[num] = item.Value; array3[num] = (Plugin.PlayerNamesBySteamId.TryGetValue(item.Key, out string value) ? value : ""); num++; } return new object[3] { array, array2, array3 }; } private static string SavePathFor(string saveFile) { return Path.Combine(SaveDir, Sanitize(saveFile) + ".tsv"); } private static string Sanitize(string s) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { s = s.Replace(oldChar, '_'); } return s; } internal static void SaveToDisk() { string saveFileCurrent = GetSaveFileCurrent(); if (string.IsNullOrEmpty(saveFileCurrent)) { return; } try { Directory.CreateDirectory(SaveDir); StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, int> item in Plugin.DeathCountsBySteamId) { string text = (Plugin.PlayerNamesBySteamId.TryGetValue(item.Key, out string value) ? value : ""); text = text.Replace('\t', ' ').Replace('\n', ' ').Replace('\r', ' '); stringBuilder.Append(item.Key).Append('\t').Append(item.Value) .Append('\t') .Append(text) .Append('\n'); } File.WriteAllText(SavePathFor(saveFileCurrent), stringBuilder.ToString()); } catch (Exception ex) { Plugin.TrackerErr("[DeathCounter] save failed: " + ex.Message); } } private static void LoadFromDisk(string saveFile) { try { string path = SavePathFor(saveFile); if (!File.Exists(path)) { return; } string[] array = File.ReadAllLines(path); foreach (string text in array) { if (string.IsNullOrWhiteSpace(text)) { continue; } string[] array2 = text.Split(new char[1] { '\t' }); if (array2.Length < 2) { continue; } string text2 = array2[0]; if (!string.IsNullOrEmpty(text2) && int.TryParse(array2[1], out var result)) { Plugin.DeathCountsBySteamId[text2] = result; if (array2.Length >= 3 && !string.IsNullOrEmpty(array2[2])) { Plugin.PlayerNamesBySteamId[text2] = array2[2]; } } } } catch (Exception ex) { Plugin.TrackerErr("[DeathCounter] load failed: " + ex.Message); } } internal static bool IsHost() { if (!isMasterResolved) { Type type = AccessTools.TypeByName("SemiFunc"); isMasterOrSpMethod = ((type == null) ? null : AccessTools.Method(type, "IsMasterClientOrSingleplayer", (Type[])null, (Type[])null)); isMasterResolved = true; } if (isMasterOrSpMethod != null) { try { return (bool)isMasterOrSpMethod.Invoke(null, null); } catch { } } try { return PhotonNetwork.OfflineMode || !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient; } catch { return true; } } private static string GetSaveFileCurrent() { if (!statsResolved) { Type type = AccessTools.TypeByName("StatsManager"); statsInstanceField = ((type == null) ? null : AccessTools.Field(type, "instance")); saveFileCurrentField = ((type == null) ? null : AccessTools.Field(type, "saveFileCurrent")); statsResolved = true; } try { object obj = statsInstanceField?.GetValue(null); if (obj == null) { return ""; } return (saveFileCurrentField?.GetValue(obj) as string) ?? ""; } catch { return ""; } } } [BepInPlugin("matsu.repo.compat_patch", "Matsu REPO Compat Patch", "1.3.4")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "matsu.repo.compat_patch"; public const string PluginName = "Matsu REPO Compat Patch"; public const string PluginVersion = "1.3.4"; private static ManualLogSource? Log; private static ConfigEntry<bool>? VerboseLogging; private static readonly HashSet<string> LoggedOnce = new HashSet<string>(); public static Dictionary<string, int> DeathCountsBySteamId = new Dictionary<string, int>(); public static Dictionary<string, string> PlayerNamesBySteamId = new Dictionary<string, string>(); private static FieldInfo? targetComponentField; private static FieldInfo? insightGeneratorField; private static FieldInfo? insightValueTextField; private static bool runManagerReflectionResolved; private static FieldInfo? runManagerInstanceField; private static FieldInfo? runManagerLevelCurrentField; private static FieldInfo? runManagerLevelLobbyField; private Harmony harmony; private ConfigEntry<bool> patchShopItemNull; private ConfigEntry<bool> patchMapNullDoorPrefab; private ConfigEntry<bool> patchEnemySetupNullPrefab; private ConfigEntry<bool> patchSoundApiNull; private ConfigEntry<bool> patchImperiumEnemyStatusNull; private ConfigEntry<bool> patchImperiumInsightsNull; private ConfigEntry<bool> verboseLogging; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("matsu.repo.compat_patch"); patchShopItemNull = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchItemAttributesShopNull", true, "Suppresses ItemAttributes.ShopInTruckLogic null-reference spam caused by modded item metadata that the current game does not fully understand."); patchMapNullDoorPrefab = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchMapNullDoorPrefab", true, "Skips map door marker creation when a modded door has no DirtFinder map prefab, preventing repeated null Instantiate errors."); patchEnemySetupNullPrefab = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchEnemySetupNullPrefab", true, "Automatically heals EnemySetup.spawnObjects if it is null, empty or contains broken prefab refs, allowing Jester and other older custom enemies to spawn."); patchSoundApiNull = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchSoundApiNull", true, "Suppresses loaforcsSoundAPI NullReferenceException loops inside ResetAudioInfoFetched when playing looped sounds."); patchImperiumEnemyStatusNull = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchImperiumEnemyStatusNull", true, "Suppresses Imperium.Visualizers.Objects.EnemyStatus NullReferenceException loops inside Update when tracking custom or uninitialized enemies."); patchImperiumInsightsNull = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "PatchImperiumInsightsNull", true, "Suppresses Imperium.Visualizers.ObjectInsights NullReferenceException loops inside RegisterDefaultInsights when tracking custom or uninitialized enemies."); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "VerboseLogging", false, "Log every skipped compatibility edge instead of one sample per issue."); VerboseLogging = verboseLogging; ((MonoBehaviour)this).StartCoroutine(InstallPatchesWhenGameTypesAreReady()); ((Component)this).gameObject.AddComponent<DeathSyncBehaviour>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Matsu REPO Compat Patch 1.3.4 loaded. Host-safe: no networked prefabs or custom content (the death counter syncs via lightweight host events only)."); } private IEnumerator InstallPatchesWhenGameTypesAreReady() { bool shopPatched = !patchShopItemNull.Value; bool mapPatched = !patchMapNullDoorPrefab.Value; bool enemySetupPatched = !patchEnemySetupNullPrefab.Value; bool soundApiPatched = !patchSoundApiNull.Value; bool imperiumPatched = !patchImperiumEnemyStatusNull.Value; bool imperiumInsightsPatched = !patchImperiumInsightsNull.Value; bool deathCounterPatched = false; for (int attempt = 0; attempt < 20; attempt++) { if (!shopPatched) { shopPatched = TryPatch("ItemAttributes", "ShopInTruckLogic", null, null, "ItemAttributesShopInTruckLogicFinalizer"); } if (!mapPatched) { mapPatched = TryPatch("Map", "AddDoor", null, "MapAddDoorPrefix"); } if (!enemySetupPatched) { bool flag = TryPatch("EnemyDirector", "Awake", null, null, null, "EnemyDirectorAwakePostfix"); Type type = AccessTools.TypeByName("REPOLib.Objects.Sdk.EnemyContent"); bool flag2 = false; if (type != null) { flag2 = TryPatch("REPOLib.Modules.Enemies", "RegisterEnemy", new Type[1] { type }, "RegisterEnemyPrefix"); } enemySetupPatched = flag && flag2; } if (!soundApiPatched) { soundApiPatched = !TypeExists("loaforcsSoundAPI.REPO.Patches.SoundPatch") || TryPatch("loaforcsSoundAPI.REPO.Patches.SoundPatch", "ResetAudioInfoFetched", null, null, "SoundApiResetAudioInfoFetchedFinalizer"); } if (!imperiumPatched) { if (!TypeExists("Imperium.Core.EventLogging.EntityEventLogger")) { imperiumPatched = true; } else { bool flag3 = TryPatch("Imperium.Visualizers.Objects.EnemyStatus", "Update", null, null, "ImperiumEnemyStatusUpdateFinalizer"); bool flag4 = TryPatch("Imperium.Core.EventLogging.EntityEventLogger", "LogEntityEvent", null, "EntityEventLoggerPrefix"); bool flag5 = TryPatch("Imperium.Core.EventLogging.EntityEventLogger", "Teleport", null, "EntityEventLoggerPrefix"); bool flag6 = TryPatch("Imperium.Core.EventLogging.EntityEventLogger", "Spawn", null, "EntityEventLoggerPrefix"); bool flag7 = TryPatch("Imperium.Core.EventLogging.EntityEventLogger", "Despawn", null, "EntityEventLoggerPrefix"); imperiumPatched = flag3 && flag4 && flag5 && flag6 && flag7; } } if (!imperiumInsightsPatched) { if (!TypeExists("Imperium.Visualizers.Objects.ObjectInsightEntry")) { imperiumInsightsPatched = true; } else { bool flag8 = TryPatch("Imperium.Visualizers.Objects.ObjectInsightEntry", "Init", null, "ObjectInsightEntryInitPrefix"); bool flag9 = TryPatch("Imperium.Visualizers.Objects.ObjectInsightEntry", "Update", null, "ObjectInsightEntryUpdatePrefix"); imperiumInsightsPatched = flag8 && flag9; } } if (!deathCounterPatched) { deathCounterPatched = TryPatch("PlayerAvatar", "PlayerDeathRPC", null, "PlayerDeathRpcPrefix"); } if (shopPatched && mapPatched && enemySetupPatched && soundApiPatched && imperiumPatched && imperiumInsightsPatched && deathCounterPatched) { yield break; } yield return (object)new WaitForSeconds(1f); } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Some compatibility targets were not patched. The game version may have renamed the target methods."); } private static bool TypeExists(string typeName) { return AccessTools.TypeByName(typeName) != null; } private bool TryPatch(string typeName, string methodName, Type[]? parameterTypes = null, string? prefix = null, string? finalizer = null, string? postfix = null, string? transpiler = null) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) Type type = AccessTools.TypeByName(typeName); MethodInfo methodInfo = null; if (type != null) { methodInfo = ((parameterTypes != null) ? AccessTools.Method(type, methodName, parameterTypes, (Type[])null) : AccessTools.Method(type, methodName, (Type[])null, (Type[])null)); } if (methodInfo == null) { return false; } HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(Plugin), prefix, (Type[])null, (Type[])null))); HarmonyMethod val2 = ((finalizer == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(Plugin), finalizer, (Type[])null, (Type[])null))); HarmonyMethod val3 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(Plugin), postfix, (Type[])null, (Type[])null))); HarmonyMethod val4 = ((transpiler == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(typeof(Plugin), transpiler, (Type[])null, (Type[])null))); try { harmony.Patch((MethodBase)methodInfo, val, val3, val4, val2, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched " + typeName + "." + methodName + " for REPO mod compatibility.")); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch " + typeName + "." + methodName + ": " + ex.GetType().Name + ": " + ex.Message)); return false; } } private void OnGUI() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) if (!runManagerReflectionResolved) { Type type = AccessTools.TypeByName("RunManager"); if (type != null) { runManagerInstanceField = AccessTools.Field(type, "instance"); runManagerLevelCurrentField = AccessTools.Field(type, "levelCurrent"); runManagerLevelLobbyField = AccessTools.Field(type, "levelLobby"); } runManagerReflectionResolved = true; } if (runManagerInstanceField == null || runManagerLevelCurrentField == null || runManagerLevelLobbyField == null) { return; } object value = runManagerInstanceField.GetValue(null); if (value == null) { return; } object value2 = runManagerLevelCurrentField.GetValue(value); object value3 = runManagerLevelLobbyField.GetValue(value); if (value2 == null || value3 == null || value2 != value3) { return; } GUILayout.BeginArea(new Rect((float)Screen.width - 400f - 20f, 20f, 400f, 600f)); GUI.color = Color.white; GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 24, fontStyle = (FontStyle)1, alignment = (TextAnchor)2 }; val.normal.textColor = Color.red; GUILayout.Label("--- Player Deaths ---", val, Array.Empty<GUILayoutOption>()); GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 20, fontStyle = (FontStyle)0, alignment = (TextAnchor)2 }; val2.normal.textColor = Color.white; if (DeathCountsBySteamId.Count == 0) { GUILayout.Label("No deaths recorded yet.", val2, Array.Empty<GUILayoutOption>()); } else { foreach (KeyValuePair<string, int> item in DeathCountsBySteamId) { string value4; string arg = ((PlayerNamesBySteamId.TryGetValue(item.Key, out value4) && !string.IsNullOrEmpty(value4)) ? value4 : item.Key); GUILayout.Label($"{arg}: {item.Value}", val2, Array.Empty<GUILayoutOption>()); } } GUILayout.EndArea(); } private static void PlayerDeathRpcPrefix(object __instance) { try { if (__instance != null && DeathSyncBehaviour.IsHost()) { Type type = __instance.GetType(); string steamId = (AccessTools.Field(type, "steamID")?.GetValue(__instance) as string) ?? ""; string name = (AccessTools.Field(type, "playerName")?.GetValue(__instance) as string) ?? ""; DeathSyncBehaviour.OnHostDeath(steamId, name); } } catch (Exception arg) { ManualLogSource? log = Log; if (log != null) { log.LogError((object)$"[DeathCounter] PlayerDeathRpcPrefix error: {arg}"); } } } internal static void TrackerLog(string message) { ManualLogSource? log = Log; if (log != null) { log.LogInfo((object)message); } } internal static void TrackerErr(string message) { ManualLogSource? log = Log; if (log != null) { log.LogError((object)message); } } private static Exception? ItemAttributesShopInTruckLogicFinalizer(Exception? __exception) { if (__exception is NullReferenceException) { LogOnce("ItemAttributes.ShopInTruckLogic.NullReference", "Suppressed ItemAttributes.ShopInTruckLogic null reference. A modded item is missing optional shop/truck metadata."); return null; } return __exception; } private static Exception? SoundApiResetAudioInfoFetchedFinalizer(Exception? __exception) { if (__exception is NullReferenceException) { LogOnce("loaforcsSoundAPI.ResetAudioInfoFetched.NullReference", "Suppressed loaforcsSoundAPI SoundPatch.ResetAudioInfoFetched null reference."); return null; } return __exception; } private static Exception? ImperiumEnemyStatusUpdateFinalizer(Exception? __exception) { if (__exception is NullReferenceException) { LogOnce("Imperium.EnemyStatus.Update.NullReference", "Suppressed Imperium EnemyStatus.Update null reference."); return null; } return __exception; } private static bool ObjectInsightEntryInitPrefix(MonoBehaviour __instance, string __0, object __1, Component __2) { if ((Object)(object)__2 == (Object)null) { if (targetComponentField == null) { targetComponentField = AccessTools.Field(((object)__instance).GetType(), "targetComponent"); } if (insightGeneratorField == null) { insightGeneratorField = AccessTools.Field(((object)__instance).GetType(), "insightGenerator"); } if (insightValueTextField == null) { insightValueTextField = AccessTools.Field(((object)__instance).GetType(), "insightValueText"); } targetComponentField?.SetValue(__instance, __2); insightGeneratorField?.SetValue(__instance, __1); object obj = insightValueTextField?.GetValue(__instance); if (obj != null) { AccessTools.Property(obj.GetType(), "text")?.SetValue(obj, "Destroyed"); } return false; } return true; } private static bool ObjectInsightEntryUpdatePrefix(MonoBehaviour __instance) { if (targetComponentField == null) { targetComponentField = AccessTools.Field(((object)__instance).GetType(), "targetComponent"); } object? obj = targetComponentField?.GetValue(__instance); if ((Object)((obj is Component) ? obj : null) == (Object)null) { if (insightValueTextField == null) { insightValueTextField = AccessTools.Field(((object)__instance).GetType(), "insightValueText"); } object obj2 = insightValueTextField?.GetValue(__instance); if (obj2 != null) { AccessTools.Property(obj2.GetType(), "text")?.SetValue(obj2, "Destroyed"); } return false; } return true; } private static bool MapAddDoorPrefix(object[] __args) { if (__args.Length < 2 || __args[1] is GameObject) { return true; } LogOnce("Map.AddDoor.NullDoorPrefab", "Skipped a DirtFinder map door marker because the modded door prefab reference is null."); return false; } private static void RegisterEnemyPrefix(object __0) { if (__0 == null) { return; } try { HealEnemyContent(__0); } catch (Exception arg) { ManualLogSource? log = Log; if (log != null) { log.LogError((object)$"Error in RegisterEnemyPrefix: {arg}"); } } } private static void HealEnemyContent(object enemyContent) { Type type = AccessTools.TypeByName("REPOLib.Objects.Sdk.EnemyContent"); if (type == null || !type.IsInstanceOfType(enemyContent)) { return; } FieldInfo field = type.GetField("_spawnObjects", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("_setup", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null || field2 == null) { return; } object value = field2.GetValue(enemyContent); IList list = field.GetValue(enemyContent) as IList; if (value == null || list == null || list.Count == 0) { return; } Type type2 = AccessTools.TypeByName("EnemySetup"); if (type2 == null) { return; } FieldInfo field3 = type2.GetField("spawnObjects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field3 == null) { return; } IList list2 = field3.GetValue(value) as IList; bool flag = false; if (list2 == null || list2.Count == 0) { flag = true; } else { foreach (object item in list2) { if (item == null) { flag = true; break; } PropertyInfo property = item.GetType().GetProperty("Prefab", BindingFlags.Instance | BindingFlags.Public); if (property == null || property.GetValue(item) == null) { flag = true; break; } } } if (!flag) { return; } ManualLogSource? log = Log; if (log != null) { log.LogInfo((object)$"Healing spawnObjects for registered enemy content: {value}"); } Type type3 = AccessTools.TypeByName("REPOLib.Modules.NetworkPrefabs"); MethodInfo methodInfo = ((type3 == null) ? null : AccessTools.Method(type3, "RegisterNetworkPrefab", new Type[2] { typeof(string), typeof(GameObject) }, (Type[])null)); if (methodInfo == null) { return; } Type type4 = field3.FieldType.GetGenericArguments()[0]; IList list3 = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type4)); foreach (object item2 in list) { if (item2 == null) { continue; } GameObject val = (GameObject)((item2 is GameObject) ? item2 : null); if (!((Object)(object)val == (Object)null)) { string text = "Enemies/" + ((Object)val).name; object obj = null; MethodInfo methodInfo2 = ((type3 == null) ? null : AccessTools.Method(type3, "HasNetworkPrefab", new Type[1] { typeof(string) }, (Type[])null)); MethodInfo methodInfo3 = ((type3 == null) ? null : AccessTools.Method(type3, "GetNetworkPrefabRef", new Type[1] { typeof(string) }, (Type[])null)); bool flag2 = false; if (methodInfo2 != null) { flag2 = (bool)methodInfo2.Invoke(null, new object[1] { text }); } obj = ((!flag2 || !(methodInfo3 != null)) ? methodInfo.Invoke(null, new object[2] { text, val }) : methodInfo3.Invoke(null, new object[1] { text })); if (obj != null) { list3.Add(obj); } } } if (list3.Count > 0) { field3.SetValue(value, list3); ManualLogSource? log2 = Log; if (log2 != null) { log2.LogInfo((object)$"Successfully healed {value} with {list3.Count} prefab refs."); } } } private static void EnemyDirectorAwakePostfix(object __instance) { try { Type type = AccessTools.TypeByName("REPOLib.Modules.Enemies"); if (type == null) { return; } PropertyInfo property = type.GetProperty("RegisteredEnemies", BindingFlags.Static | BindingFlags.Public); if (property == null || !(property.GetValue(null) is IEnumerable enumerable)) { return; } Type type2 = AccessTools.TypeByName("REPOLib.Objects.Sdk.EnemyContent"); Type type3 = AccessTools.TypeByName("EnemySetup"); if (type3 == null) { return; } foreach (object item in enumerable) { if (item == null) { continue; } if (type2 != null && type2.IsInstanceOfType(item)) { HealEnemyContent(item); } else { if (!type3.IsInstanceOfType(item)) { continue; } FieldInfo field = type3.GetField("spawnObjects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { continue; } IList list = field.GetValue(item) as IList; bool flag = list == null || list.Count == 0; if (!flag && list != null) { foreach (object item2 in list) { if (item2 == null) { flag = true; break; } PropertyInfo property2 = item2.GetType().GetProperty("Prefab", BindingFlags.Instance | BindingFlags.Public); if (property2 == null || property2.GetValue(item2) == null) { flag = true; break; } } } if (!flag) { continue; } object obj = ((item is ScriptableObject) ? item : null); if ((((obj != null) ? ((Object)obj).name : null) ?? "").Contains("Kuwako")) { ManualLogSource? log = Log; if (log != null) { log.LogInfo((object)$"Healing Kuwako setup in EnemyDirectorAwakePostfix: {item}"); } (AccessTools.TypeByName("RepoCustomEnemyMod.RepoCustomEnemyMod")?.GetMethod("EnsureSetupIsValid", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.Invoke(null, null); } } } } catch (Exception arg) { ManualLogSource? log2 = Log; if (log2 != null) { log2.LogError((object)$"Error in EnemyDirectorAwakePostfix: {arg}"); } } } private static bool EntityEventLoggerPrefix(object __0) { if ((Object)((__0 is Object) ? __0 : null) == (Object)null) { return false; } return true; } private static void LogOnce(string key, string message) { if (Log != null) { if (LoggedOnce.Add(key)) { Log.LogWarning((object)message); } else if (VerboseLogging != null && VerboseLogging.Value) { Log.LogWarning((object)message); } } } } }