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 TungSahurFix v1.1.0
BepInEx/plugins/TungSahurFix/TungSahurFix.dll
Decompiled 5 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using REPOLib.Modules; using REPOLib.Objects.Sdk; 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("TungSahurFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TungSahurFix")] [assembly: AssemblyTitle("TungSahurFix")] [assembly: AssemblyVersion("1.0.0.0")] namespace TungSahurFix; [BepInPlugin("Tungs.TungSahurFix", "TungSahur Fix", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class TungSahurFixPlugin : BaseUnityPlugin { internal static TungSahurFixPlugin Instance; private static readonly object Sync = new object(); private static readonly List<EnemyContent> KnownContents = new List<EnemyContent>(); private static readonly HashSet<EnemyContent> Fixed = new HashSet<EnemyContent>(); private static GameObject FoundPrefab; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Instance = this; PluginInfo.Log = ((BaseUnityPlugin)this).Logger; new Harmony("Tungs.TungSahurFix").PatchAll(); FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyContent), "_spawnObjects"); PluginInfo.Log.LogInfo((object)("TungSahurFix loaded. _spawnObjects field resolved: " + (fieldInfo != null))); ((MonoBehaviour)this).StartCoroutine(SceneWatch()); } private static IEnumerator SceneWatch() { int tick = 0; while (tick < 1200) { yield return (object)new WaitForSeconds(2f); tick++; if ((Object)(object)FoundPrefab == (Object)null) { if (tick % 5 == 0) { PluginInfo.Log.LogInfo((object)("TungSahurFix: heartbeat tick " + tick + " (" + tick * 2 + "s), FoundPrefab=null")); } if (tick % 2 == 0) { ProbeSceneForSahur("t+" + tick * 2 + "s"); } } if ((Object)(object)FoundPrefab == (Object)null && tick % 5 == 0) { AttemptBundleResolveFallback(); } } if ((Object)(object)FoundPrefab == (Object)null) { PluginInfo.Log.LogWarning((object)"TungSahurFix: still no prefab after extended watch"); } } private static void AttemptBundleResolveFallback() { List<EnemyContent> list; lock (Sync) { list = new List<EnemyContent>(KnownContents); } foreach (EnemyContent item in list) { if ((Object)(object)item == (Object)null) { continue; } lock (Sync) { if (Fixed.Contains(item)) { continue; } } string text = SafeSetupName(item); if (text.StartsWith("Tung") || text.StartsWith("Sahur")) { GameObject val = TryResolvePrefabFromBundle(item); if ((Object)(object)val != (Object)null) { PluginInfo.Log.LogInfo((object)("TungSahurFix: bundle fallback resolved prefab '" + ((Object)val).name + "' for '" + text + "'")); AdoptPrefab(val); break; } } } } private static void ProbeSceneForSahur(string tag) { try { Stopwatch stopwatch = Stopwatch.StartNew(); GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { string name = ((Object)val).name; if (name != null && (name.IndexOf("Sahur", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Tung", StringComparison.OrdinalIgnoreCase) >= 0) && name.IndexOf("Roaster", StringComparison.OrdinalIgnoreCase) < 0 && (Object)(object)val.GetComponent("EnemyParent") != (Object)null) { stopwatch.Stop(); PluginInfo.Log.LogInfo((object)("TungSahurFix[" + tag + "]: found EnemyParent GO '" + ((Object)val).name + "' (children " + val.transform.childCount + ", active " + val.activeInHierarchy + ", scan took " + stopwatch.Elapsed.TotalMilliseconds + " ms)")); AdoptPrefab(val); return; } } } stopwatch.Stop(); PluginInfo.Log.LogInfo((object)("TungSahurFix[" + tag + "]: scan done, no Sahur prefab yet (scan took " + stopwatch.Elapsed.TotalMilliseconds + " ms)")); } catch (Exception ex) { PluginInfo.Log.LogError((object)("TungSahurFix: scene probe error: " + ex)); } } private static void AdoptPrefab(GameObject prefab) { lock (Sync) { if ((Object)(object)FoundPrefab == (Object)(object)prefab) { return; } FoundPrefab = prefab; } PluginInfo.Log.LogInfo((object)("TungSahurFix: adopting prefab '" + ((Object)prefab).name + "'")); TryInjectAll(); } private static void TryInjectAll() { List<EnemyContent> list; GameObject foundPrefab; lock (Sync) { list = new List<EnemyContent>(KnownContents); foundPrefab = FoundPrefab; } if ((Object)(object)foundPrefab == (Object)null) { return; } PluginInfo.Log.LogInfo((object)("TungSahurFix: TryInjectAll start, " + list.Count + " known content(s)")); foreach (EnemyContent item in list) { if ((Object)(object)item == (Object)null) { continue; } string text = SafeSetupName(item); if (!text.StartsWith("Tung") && !text.StartsWith("Sahur")) { continue; } lock (Sync) { if (Fixed.Contains(item)) { continue; } } List<GameObject> list2; try { list2 = item.SpawnObjects; } catch { list2 = null; } if (list2 != null && list2.Count > 0) { bool flag = false; foreach (GameObject item2 in list2) { if ((Object)(object)item2 != (Object)null) { flag = true; break; } } if (flag) { lock (Sync) { Fixed.Add(item); } PluginInfo.Log.LogInfo((object)("TungSahurFix: setup '" + text + "' already has spawn objects, skipping")); continue; } } int num = SpawnCountForSetupName(text); List<GameObject> list3 = new List<GameObject>(num); for (int i = 0; i < num; i++) { list3.Add(foundPrefab); } FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyContent), "_spawnObjects"); if (fieldInfo == null) { PluginInfo.Log.LogError((object)"TungSahurFix: _spawnObjects field not found"); return; } PluginInfo.Log.LogInfo((object)("TungSahurFix: about to set _spawnObjects(" + num + ") on '" + text + "'")); try { fieldInfo.SetValue(item, list3); } catch (Exception ex) { PluginInfo.Log.LogError((object)("TungSahurFix: field set error: " + ex)); continue; } PluginInfo.Log.LogInfo((object)("TungSahurFix: injected " + num + " spawn object(s) for '" + text + "', calling Enemies.RegisterEnemy")); try { Stopwatch stopwatch = Stopwatch.StartNew(); Enemies.RegisterEnemy(item); stopwatch.Stop(); lock (Sync) { Fixed.Add(item); } PluginInfo.Log.LogInfo((object)("TungSahurFix: RegisterEnemy call returned for '" + text + "' (took " + stopwatch.Elapsed.TotalMilliseconds + " ms)")); } catch (Exception ex2) { PluginInfo.Log.LogError((object)("TungSahurFix: RegisterEnemy threw: " + ex2)); } } PluginInfo.Log.LogInfo((object)"TungSahurFix: TryInjectAll done"); } private static string SafeSetupName(EnemyContent content) { try { EnemySetup setup = content.Setup; return ((Object)(object)setup != (Object)null) ? ((Object)setup).name : ""; } catch { return ""; } } internal static void RegisterKnown(EnemyContent content) { lock (Sync) { if (!KnownContents.Contains(content)) { KnownContents.Add(content); } } } internal static void MarkFixed(EnemyContent content, GameObject prefab, string setupName, int count) { lock (Sync) { if (!KnownContents.Contains(content)) { KnownContents.Add(content); } if (!Fixed.Contains(content)) { Fixed.Add(content); } if ((Object)(object)FoundPrefab == (Object)null || (Object)(object)FoundPrefab == (Object)null) { FoundPrefab = prefab; } } PluginInfo.Log.LogInfo((object)("TungSahurFix: injected " + count + " spawn object(s) from bundle for '" + setupName + "' (prefab '" + ((Object)prefab).name + "')")); } internal static GameObject FindMaterializedSahur() { try { GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { string name = ((Object)val).name; if (name.IndexOf("roaster", StringComparison.OrdinalIgnoreCase) < 0 && (name.IndexOf("sahur", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("tung", StringComparison.OrdinalIgnoreCase) >= 0) && (Object)(object)val.GetComponent("EnemyParent") != (Object)null) { return val; } } } } catch (Exception ex) { PluginInfo.Log.LogWarning((object)("TungSahurFix: materialized scan error: " + ex.Message)); } return null; } internal static GameObject TryLoadSahurByPath(AssetBundle bundle) { try { string[] allAssetNames = bundle.GetAllAssetNames(); if (allAssetNames == null || allAssetNames.Length == 0) { return null; } GameObject val = null; int num = int.MaxValue; string[] array = allAssetNames; foreach (string text in array) { if (string.IsNullOrEmpty(text)) { continue; } GameObject val2 = bundle.LoadAsset<GameObject>(text); if ((Object)(object)val2 == (Object)null) { continue; } string name = ((Object)val2).name; if (!string.IsNullOrEmpty(name) && name.IndexOf("roaster", StringComparison.OrdinalIgnoreCase) < 0 && (name.IndexOf("sahur", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("tung", StringComparison.OrdinalIgnoreCase) >= 0) && !((Object)(object)val2.GetComponent("EnemyParent") == (Object)null)) { int num2 = ((name.IndexOf("sahur", StringComparison.OrdinalIgnoreCase) < 0) ? 10 : 0); if (num2 < num) { num = num2; val = val2; } } } if ((Object)(object)val != (Object)null) { PluginInfo.Log.LogInfo((object)("TungSahurFix: resolved " + ((Object)val).name + " from bundle path '" + ((Object)val).name + "'")); } return val; } catch (Exception ex) { PluginInfo.Log.LogWarning((object)("TungSahurFix: name-based bundle load failed: " + ex.Message)); return null; } } internal static GameObject TryResolvePrefabFromBundle(EnemyContent content) { try { EnemySetup setup = content.Setup; if ((Object)(object)setup != (Object)null && setup.spawnObjects != null && setup.spawnObjects.Count > 0) { int num = 0; for (int i = 0; i < setup.spawnObjects.Count; i++) { PrefabRef val = setup.spawnObjects[i]; if (val == null || !((PrefabRef<GameObject>)(object)val).IsValid()) { continue; } num++; try { GameObject prefab = ((PrefabRef<GameObject>)(object)val).Prefab; if ((Object)(object)prefab != (Object)null) { return prefab; } } catch (Exception ex) { PluginInfo.Log.LogWarning((object)("TungSahurFix: prefab ref load failed: " + ex.Message)); } } if (num == 0) { PluginInfo.Log.LogInfo((object)("TungSahurFix: '" + SafeSetupName(content) + "' spawn refs are empty/invalid - using bundle lookup")); } } AssetBundle bundle = ((Content)content).Bundle; if ((Object)(object)bundle == (Object)null) { return null; } GameObject val2 = TryLoadSahurByPath(bundle); if ((Object)(object)val2 != (Object)null) { return val2; } GameObject[] array = bundle.LoadAllAssets<GameObject>(); if (array == null || array.Length == 0) { array = bundle.LoadAllAssets<GameObject>(); } if (array == null || array.Length == 0) { return FindMaterializedSahur(); } string text = SafeSetupName(content).ToLowerInvariant(); GameObject result = null; int num2 = int.MaxValue; GameObject[] array2 = array; foreach (GameObject val3 in array2) { if ((Object)(object)val3 == (Object)null || string.IsNullOrEmpty(((Object)val3).name)) { continue; } string name = ((Object)val3).name; if (name.IndexOf("roaster", StringComparison.OrdinalIgnoreCase) >= 0 || (name.IndexOf("sahur", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("tung", StringComparison.OrdinalIgnoreCase) < 0) || (Object)(object)val3.GetComponent("EnemyParent") == (Object)null) { continue; } int num3 = ((name.IndexOf("sahur", StringComparison.OrdinalIgnoreCase) < 0) ? 10 : 0); string[] array3 = text.Split(' ', '-', '_'); foreach (string text2 in array3) { if (text2.Length > 3 && name.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0) { num3 -= 2; } } if (num3 < num2) { num2 = num3; result = val3; } } return result; } catch (Exception ex2) { PluginInfo.Log.LogWarning((object)("TungSahurFix: bundle prefab resolution failed: " + ex2.Message)); return null; } } internal static int SpawnCountForSetupName(string setupName) { return setupName switch { "Sahur Gang 2" => 2, "Sahur Gang 3" => 3, "Sahur Gang 4" => 4, "Sahur Gang Cooked" => 20, _ => 1, }; } } internal static class PluginInfo { public const string GUID = "Tungs.TungSahurFix"; public const string Name = "TungSahur Fix"; public const string Version = "1.1.0"; public static ManualLogSource Log; } [HarmonyPatch(typeof(Enemies), "RegisterEnemy")] internal static class RegisterEnemyPatch { public static void Prefix(EnemyContent enemyContent) { try { if ((Object)(object)enemyContent == (Object)null) { return; } EnemySetup setup = enemyContent.Setup; string text = (((Object)(object)setup != (Object)null) ? ((Object)setup).name : ""); if (!text.StartsWith("Tung") && !text.StartsWith("Sahur")) { return; } List<GameObject> list = null; try { list = enemyContent.SpawnObjects; } catch { list = null; } bool flag = false; if (list != null && list.Count > 0) { flag = true; foreach (GameObject item in list) { if ((Object)(object)item == (Object)null) { flag = false; break; } } } if (!flag) { GameObject val = TungSahurFixPlugin.TryResolvePrefabFromBundle(enemyContent); if ((Object)(object)val != (Object)null) { int num = TungSahurFixPlugin.SpawnCountForSetupName(text); List<GameObject> list2 = new List<GameObject>(num); for (int i = 0; i < num; i++) { list2.Add(val); } FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyContent), "_spawnObjects"); if (fieldInfo == null) { PluginInfo.Log.LogError((object)"TungSahurFix: _spawnObjects field not found"); return; } fieldInfo.SetValue(enemyContent, list2); TungSahurFixPlugin.MarkFixed(enemyContent, val, text, num); } else { TungSahurFixPlugin.RegisterKnown(enemyContent); } } else { TungSahurFixPlugin.MarkFixed(enemyContent, list[0], text, list.Count); } } catch (Exception ex) { PluginInfo.Log.LogError((object)("TungSahurFix: prefix error: " + ex)); } } }