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 ForestGammeltroll v1.0.0
plugins\ForestGammeltroll.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ForestGammeltroll")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ForestGammeltroll")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] namespace ForestGammeltroll; internal static class DamagePatches { [HarmonyPatch(typeof(Attack), "ModifyDamage")] private static class Attack_ModifyDamage { private static void Postfix(HitData hitData, Humanoid ___m_character) { if (ForestTrollCreature.IsForestTroll((Character)(object)___m_character)) { ((DamageTypes)(ref hitData.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value); } } } [HarmonyPatch(typeof(Aoe), "Setup")] private static class Aoe_Setup { private static void Postfix(Aoe __instance, Character owner, HitData hitData) { if ((hitData == null || !__instance.m_useAttackSettings) && ForestTrollCreature.IsForestTroll(owner)) { ((DamageTypes)(ref __instance.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value); } } } [HarmonyPatch(typeof(Projectile), "Setup")] private static class Projectile_Setup { private static void Postfix(Projectile __instance, Character owner, HitData hitData) { if (hitData == null && ForestTrollCreature.IsForestTroll(owner)) { ((DamageTypes)(ref __instance.m_damage)).Modify(ForestGammeltroll.DamageMultiplier.Value); } } } } [BepInPlugin("com.voxxsidus.forestgammeltroll", "ForestGammeltroll", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class ForestGammeltroll : BaseUnityPlugin { public const string PluginGUID = "com.voxxsidus.forestgammeltroll"; public const string PluginName = "ForestGammeltroll"; public const string PluginVersion = "1.0.0"; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); public static ConfigEntry<float> SpawnChance; public static ConfigEntry<bool> AllowStars; public static ConfigEntry<float> Health; public static ConfigEntry<float> DamageMultiplier; public static ConfigEntry<float> ModelScale; public static ConfigEntry<float> ViewRange; public static ConfigEntry<float> AlertRange; public static ConfigEntry<float> MaxChaseDistance; public static ConfigEntry<float> CopperOreWeight; public static ConfigEntry<Color> MossTint; public static ConfigEntry<float> SnowToMossThreshold; private ConfigEntry<bool> _dumpPrefabs; private void Awake() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown BindConfig(); CustomLocalization localization = Localization; string text = "English"; string text2 = "$enemy_forestgammeltroll"; localization.AddTranslation(ref text, ref text2, "Forest Gammeltroll"); CustomLocalization localization2 = Localization; text = "English"; text2 = "$piece_forestgammeltroll_petrified"; localization2.AddTranslation(ref text, ref text2, "Petrified Forest Gammeltroll"); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; CreatureManager.OnVanillaCreaturesAvailable += OnVanillaCreaturesAvailable; Harmony val = new Harmony("com.voxxsidus.forestgammeltroll"); val.PatchAll(); StarLevelSystemCompat.Apply(val); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new TestSpawnCommand()); Logger.LogInfo((object)"ForestGammeltroll has landed"); } private void BindConfig() { //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown SpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "SpawnChance", 25f, Synced("Percent chance that an open-world Troll spawning in the Black Forest becomes a Forest Gammeltroll instead. Troll caves and raids are never affected.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); AllowStars = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "AllowStars", true, Synced("Whether swapped-in Forest Gammeltrolls can spawn with stars, using the Troll's level-up chances (up to 2 stars).", null)); Health = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "Health", 1500f, Synced("Base health (1 star). Regular Troll: 600, vanilla Gammeltroll: 3000. Applies to newly spawned trolls.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f))); DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "DamageMultiplier", 0.75f, Synced("Multiplier on the vanilla Gammeltroll's damage, applied to every hit (punches, ground slam shockwave, thrown rocks). Vanilla Gammeltroll hits ~3x as hard as a regular Troll, so 0.75 is ~2.2-2.75x a Troll.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f))); ModelScale = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "ModelScale", 1f, Synced("Size relative to the vanilla Gammeltroll (1 = vanilla, ~4x a regular Troll; 0.5 = ~2x a Troll).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1.5f))); ViewRange = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "ViewRange", 50f, Synced("How far it can see targets. Regular Troll: 30, vanilla Gammeltroll: 300.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f))); AlertRange = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "AlertRange", 30f, Synced("Radius in which it notices nearby targets. Regular Troll: 20, vanilla Gammeltroll: 90.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f))); MaxChaseDistance = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "MaxChaseDistance", 200f, Synced("How far from its spawn point it will chase before giving up. Regular Troll: 200, vanilla Gammeltroll: 500.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 1000f))); CopperOreWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Petrify", "CopperOreWeight", 0.5f, Synced("Relative chance of Copper Ore vs Stone (weight 1) for each drop roll when mining the petrified remains. Each of the rock's chunks rolls 2-3 times. 0.5 matches the vanilla Gammeltroll's Bloodgold ratio (~1/3 of drops). Applies to remains created after the change.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f))); MossTint = ((BaseUnityPlugin)this).Config.Bind<Color>("Visual", "MossTint", new Color(0.7f, 1f, 0.55f), "Tint applied to the moss that replaces the snow on its skin, hair, statue and rock. Updates live."); SnowToMossThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "SnowToMossThreshold", 0.48f, new ConfigDescription("Brightness above which the skin texture counts as snow and becomes moss. Lower = more moss. Updates live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 0.9f), Array.Empty<object>())); MossTint.SettingChanged += delegate { ForestVisuals.RegenerateSkin(); }; SnowToMossThreshold.SettingChanged += delegate { ForestVisuals.RegenerateSkin(); }; _dumpPrefabs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpPrefabs", false, "Write ForestGammeltroll_PrefabDump.txt to the BepInEx folder when vanilla prefabs load (main menu)."); ConfigEntry<float>[] array = new ConfigEntry<float>[7] { Health, DamageMultiplier, ModelScale, ViewRange, AlertRange, MaxChaseDistance, CopperOreWeight }; for (int num = 0; num < array.Length; num++) { array[num].SettingChanged += delegate { ForestTrollCreature.ApplySettings(); }; } SynchronizationManager.OnConfigurationSynchronized += delegate { ForestTrollCreature.ApplySettings(); }; static ConfigDescription Synced(string description, AcceptableValueBase range) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } }); } } private void OnVanillaPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; if (_dumpPrefabs.Value) { PrefabDumper.DumpTrolls(); } } private void OnVanillaCreaturesAvailable() { CreatureManager.OnVanillaCreaturesAvailable -= OnVanillaCreaturesAvailable; ForestTrollCreature.Register(); } } internal static class ForestTrollCreature { public const string PrefabName = "ForestGammeltroll"; public const string NameToken = "$enemy_forestgammeltroll"; private const string BasePrefabName = "TrollFrost"; private static GameObject s_prefab; private static Vector3 s_baseScale; public static GameObject Prefab => s_prefab; public static void Register() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll", "TrollFrost"); if (!Object.op_Implicit((Object)(object)val)) { Logger.LogError((object)"Could not clone TrollFrost; ForestGammeltroll will not exist"); return; } GameObject statue = PetrifiedRemains.Register(); SetPetrifiedStatue(val.GetComponent<Character>(), statue); RemoveStarTint(val); ForestVisuals.Apply(val, statue, PetrifiedRemains.Rock); CreatureConfig val2 = new CreatureConfig { Name = "$enemy_forestgammeltroll", Faction = (Faction)2 }; CreatureManager.Instance.AddCreature(new CustomCreature(val, false, val2)); s_prefab = val; s_baseScale = val.transform.localScale; ApplySettings(); Logger.LogInfo((object)"Registered ForestGammeltroll (cloned from TrollFrost)"); } public static bool IsForestTroll(Character character) { if (Object.op_Implicit((Object)(object)character)) { return character.m_name == "$enemy_forestgammeltroll"; } return false; } public static void ApplySettings() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) PetrifiedRemains.ApplySettings(); if (!Object.op_Implicit((Object)(object)s_prefab)) { return; } float num = s_prefab.transform.localScale.x / s_baseScale.x; float num2 = ForestGammeltroll.ModelScale.Value / num; s_prefab.GetComponent<Character>().m_health = ForestGammeltroll.Health.Value; s_prefab.transform.localScale = s_baseScale * ForestGammeltroll.ModelScale.Value; ApplyAI(s_prefab.GetComponent<MonsterAI>()); foreach (Character item in Character.GetAllCharacters().Where(IsForestTroll)) { if (!Mathf.Approximately(num2, 1f)) { Transform transform = ((Component)item).transform; transform.localScale *= num2; } ApplyAI(((Component)item).GetComponent<MonsterAI>()); } } private static void ApplyAI(MonsterAI ai) { if (Object.op_Implicit((Object)(object)ai)) { ((BaseAI)ai).m_viewRange = ForestGammeltroll.ViewRange.Value; ai.m_alertRange = ForestGammeltroll.AlertRange.Value; ai.m_maxChaseDistance = ForestGammeltroll.MaxChaseDistance.Value; } } private static void RemoveStarTint(GameObject prefab) { LevelEffects[] componentsInChildren = prefab.GetComponentsInChildren<LevelEffects>(true); for (int i = 0; i < componentsInChildren.Length; i++) { foreach (LevelSetup levelSetup in componentsInChildren[i].m_levelSetups) { levelSetup.m_hue = 0f; levelSetup.m_saturation = 0f; levelSetup.m_value = 0f; levelSetup.m_setEmissiveColor = false; } } } private static void SetPetrifiedStatue(Character character, GameObject statue) { bool flag = false; List<EffectData> list = character.m_deathEffects.m_effectPrefabs.ToList(); for (int num = list.Count - 1; num >= 0; num--) { if (Object.op_Implicit((Object)(object)list[num].m_prefab) && !(((Object)list[num].m_prefab).name != "TrollFrost_Dead")) { flag = true; if (Object.op_Implicit((Object)(object)statue)) { list[num].m_prefab = statue; } else { list.RemoveAt(num); } } } character.m_deathEffects.m_effectPrefabs = list.ToArray(); if (!flag) { Logger.LogWarning((object)"TrollFrost_Dead not found in TrollFrost death effects; it will not turn to stone"); } } } internal static class ForestVisuals { private const string SkinMaterialName = "FrostTrollmat"; private const string BackTreesMaterialName = "Fir_Snow_Troll_mat"; private const string BloodgoldVeinMaterialName = "FrostTrollBloodGold_mat"; private const string GreenFirPrefabName = "FirTree_small"; private const string GreenFirMaterialName = "Pine_tree_small"; private const string CopperRockPrefabName = "rock4_copper"; private const string CopperRockMaterialName = "rock1_copper"; private const string CopperRockMossProperty = "_MossTex"; private const string NormalMapProperty = "_BumpMap"; private const string MossAlphaProperty = "_MossAlpha"; private const string MossBlendProperty = "_MossBlend"; private const string CopperFracPrefabName = "rock4_copper_frac"; private const string CopperVeinMaterialName = "rock_copper_internal"; private static readonly Dictionary<string, string> EffectReplacements = new Dictionary<string, string> { { "vfx_firetreecut_snow_FrostTrollDeath", "vfx_firetreecut" }, { "vfx_frostarrow_hit", "vfx_foresttroll_hit" } }; private static readonly Rect HairBlock = new Rect(0.58f, 0f, 0.42f, 0.36f); private const float MossTiling = 2f; private const float MossGain = 1.35f; private const float SnowFeather = 0.27f; private static Texture2D s_snowySkin; private static Texture2D s_moss; private static Material s_skinMaterial; private static Texture2D s_generatedSkin; public static void Apply(GameObject creature, GameObject statue, GameObject rock) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown List<Renderer> list = ((IEnumerable<GameObject>)(object)new GameObject[3] { creature, statue, rock }).Where((GameObject go) => Object.op_Implicit((Object)(object)go)).SelectMany((GameObject go) => go.GetComponentsInChildren<Renderer>(true)).ToList(); Dictionary<string, Material> replacements = new Dictionary<string, Material>(); Material val = FindMaterial(list, "FrostTrollmat"); Texture mossTexture = GetMossTexture(); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)mossTexture)) { s_snowySkin = ReadPixels(val.mainTexture); s_moss = ReadPixels(mossTexture); s_skinMaterial = new Material(val) { name = "ForestGammeltroll_mat" }; RegenerateSkin(); replacements["FrostTrollmat"] = s_skinMaterial; } Material val2 = FindMaterial(list, "Fir_Snow_Troll_mat"); Material materialFromPrefab = GetMaterialFromPrefab("FirTree_small", "Pine_tree_small"); if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)materialFromPrefab)) { Material val3 = new Material(val2) { name = "ForestGammeltroll_Fir_mat" }; val3.mainTexture = materialFromPrefab.mainTexture; val3.SetTexture("_BumpMap", materialFromPrefab.GetTexture("_BumpMap")); val3.SetFloat("_MossAlpha", materialFromPrefab.GetFloat("_MossAlpha")); val3.SetFloat("_MossBlend", materialFromPrefab.GetFloat("_MossBlend")); replacements["Fir_Snow_Troll_mat"] = val3; } Material materialFromPrefab2 = GetMaterialFromPrefab("rock4_copper_frac", "rock_copper_internal"); if (Object.op_Implicit((Object)(object)materialFromPrefab2)) { replacements["FrostTrollBloodGold_mat"] = materialFromPrefab2; } foreach (Renderer item in list) { item.sharedMaterials = item.sharedMaterials.Select((Material m) => (!Object.op_Implicit((Object)(object)m) || !replacements.TryGetValue(((Object)m).name, out var value)) ? m : value).ToArray(); } ReplaceEffects(creature.GetComponent<Character>()); Logger.LogInfo((object)("Forest visuals applied: " + string.Join(", ", replacements.Keys))); } public static void RegenerateSkin() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_skinMaterial)) { return; } Texture2D val = s_generatedSkin; s_generatedSkin = BuildMossySkin(s_snowySkin, s_moss, ForestGammeltroll.MossTint.Value, ForestGammeltroll.SnowToMossThreshold.Value); s_skinMaterial.mainTexture = (Texture)(object)s_generatedSkin; if (AccessTools.Field(typeof(LevelEffects), "m_materials")?.GetValue(null) is Dictionary<string, Material> source) { foreach (KeyValuePair<string, Material> item in source.Where((KeyValuePair<string, Material> e) => e.Key.StartsWith("ForestGammeltroll") && Object.op_Implicit((Object)(object)e.Value))) { item.Value.mainTexture = (Texture)(object)s_generatedSkin; } } if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } private static Texture2D BuildMossySkin(Texture2D snowy, Texture2D moss, Color tint, float threshold) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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) //IL_0095: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) int width = ((Texture)snowy).width; int height = ((Texture)snowy).height; Color[] pixels = snowy.GetPixels(); Color[] array = (Color[])(object)new Color[pixels.Length]; Color val = default(Color); ((Color)(ref val))..ctor(tint.r * 1.35f, tint.g * 1.35f, tint.b * 1.35f); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int num = i * width + j; Color val2 = pixels[num]; float num2 = ((float)j + 0.5f) / (float)width; float num3 = ((float)i + 0.5f) / (float)height; float num4 = val2.r * 0.299f + val2.g * 0.587f + val2.b * 0.114f; Color val3 = moss.GetPixelBilinear(num2 * 2f, num3 * 2f) * val; Rect hairBlock = HairBlock; Color val4; if (((Rect)(ref hairBlock)).Contains(new Vector2(num2, num3))) { val4 = val3 * (0.3f + 0.9f * num4); } else { float num5 = Mathf.Max(val2.r, Mathf.Max(val2.g, val2.b)); float num6 = Mathf.Min(val2.r, Mathf.Min(val2.g, val2.b)); float x = ((num5 > 0f) ? ((num5 - num6) / num5) : 0f); float num7 = SmoothStep(threshold, threshold + 0.27f, num4) * (1f - SmoothStep(0.18f, 0.35f, x)); float num8 = 0.55f + 0.9f * (num4 - 0.5f); val4 = Color.Lerp(val2, val3 * num8, num7); } val4.a = val2.a; array[num] = val4; } } return CreateTexture((Texture)(object)snowy, width, height, array, "ForestGammeltroll_d"); } private static void ReplaceEffects(Character character) { EffectList[] array = (EffectList[])(object)new EffectList[3] { character.m_deathEffects, character.m_hitEffects, character.m_critHitEffects }; for (int i = 0; i < array.Length; i++) { EffectData[] effectPrefabs = array[i].m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (Object.op_Implicit((Object)(object)val.m_prefab) && EffectReplacements.TryGetValue(((Object)val.m_prefab).name, out var value)) { GameObject prefab = Cache.GetPrefab<GameObject>(value); if (Object.op_Implicit((Object)(object)prefab)) { val.m_prefab = prefab; } else { Logger.LogWarning((object)("Effect " + value + " not found; keeping " + ((Object)val.m_prefab).name)); } } } } } private static Texture GetMossTexture() { Material materialFromPrefab = GetMaterialFromPrefab("rock4_copper", "rock1_copper"); Texture obj = ((Object.op_Implicit((Object)(object)materialFromPrefab) && materialFromPrefab.HasProperty("_MossTex")) ? materialFromPrefab.GetTexture("_MossTex") : null); if (!Object.op_Implicit((Object)(object)obj)) { Logger.LogWarning((object)"No _MossTex on rock1_copper; skin stays snowy"); } return obj; } private static Material GetMaterialFromPrefab(string prefabName, string materialName) { GameObject prefab = Cache.GetPrefab<GameObject>(prefabName); Material obj = (Object.op_Implicit((Object)(object)prefab) ? FindMaterial(prefab.GetComponentsInChildren<Renderer>(true), materialName) : null); if (!Object.op_Implicit((Object)(object)obj)) { Logger.LogWarning((object)("Material " + materialName + " not found on " + prefabName)); } return obj; } private static Material FindMaterial(IEnumerable<Renderer> renderers, string name) { return renderers.SelectMany((Renderer r) => r.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && ((Object)m).name == name)); } private static Texture2D ReadPixels(Texture source) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Graphics.Blit(source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0); val.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); ((Texture)val).wrapMode = (TextureWrapMode)0; return val; } private static Texture2D CreateTexture(Texture template, int w, int h, Color[] pixels, string name) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown Texture2D val = new Texture2D(w, h, (TextureFormat)4, true) { name = name, filterMode = template.filterMode, wrapMode = template.wrapMode, anisoLevel = template.anisoLevel }; val.SetPixels(pixels); val.Apply(true); return val; } private static float SmoothStep(float a, float b, float x) { float num = Mathf.Clamp01((x - a) / (b - a)); return num * num * (3f - 2f * num); } } internal static class PetrifiedRemains { public const string StatuePrefabName = "ForestGammeltroll_Dead"; public const string RockPrefabName = "ForestGammeltroll_Frac"; public const string NameToken = "$piece_forestgammeltroll_petrified"; public const string VanillaStatuePrefabName = "TrollFrost_Dead"; private const string VanillaRockPrefabName = "TrollFrost_Frac"; private const string VanillaRareOreName = "GoldOre"; private const string CopperOreName = "CopperOre"; private const string MinimumPickaxeName = "PickaxeAntler"; private static GameObject s_statue; private static GameObject s_rock; private static int s_copperDropIndex = -1; public static GameObject Rock => s_rock; public static GameObject Register() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) int minimumToolTier = GetMinimumToolTier(); if (minimumToolTier < 0) { return null; } GameObject prefab = Cache.GetPrefab<GameObject>("CopperOre"); if (!Object.op_Implicit((Object)(object)prefab)) { Logger.LogError((object)"Could not find CopperOre; it will not turn to stone"); return null; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll_Frac", "TrollFrost_Frac"); GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("ForestGammeltroll_Dead", "TrollFrost_Dead"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2)) { Logger.LogError((object)"Could not clone TrollFrost_Frac/TrollFrost_Dead; it will not turn to stone"); return null; } MineRock5 component = val.GetComponent<MineRock5>(); component.m_name = "$piece_forestgammeltroll_petrified"; component.m_minToolTier = minimumToolTier; List<DropData> drops = component.m_dropItems.m_drops; for (int i = 0; i < drops.Count; i++) { if (Object.op_Implicit((Object)(object)drops[i].m_item) && ((Object)drops[i].m_item).name == "GoldOre") { DropData value = drops[i]; value.m_item = prefab; drops[i] = value; s_copperDropIndex = i; } } if (s_copperDropIndex < 0) { Logger.LogWarning((object)"GoldOre not found in TrollFrost_Frac drops; rock will drop no copper"); } Destructible component2 = val2.GetComponent<Destructible>(); component2.m_minToolTier = minimumToolTier; component2.m_spawnWhenDestroyed = val; HoverText component3 = val2.GetComponent<HoverText>(); if (Object.op_Implicit((Object)(object)component3)) { component3.m_text = "$piece_forestgammeltroll_petrified"; } PrefabManager.Instance.AddPrefab(val); PrefabManager.Instance.AddPrefab(val2); s_rock = val; s_statue = val2; ApplySettings(); Logger.LogInfo((object)string.Format("Registered {0} and {1} (min tool tier {2}, from {3})", "ForestGammeltroll_Dead", "ForestGammeltroll_Frac", minimumToolTier, "PickaxeAntler")); return val2; } public static void ApplySettings() { //IL_0017: 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) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)s_statue)) { s_statue.transform.localScale = Vector3.one * ForestGammeltroll.ModelScale.Value; if (s_copperDropIndex >= 0) { List<DropData> drops = s_rock.GetComponent<MineRock5>().m_dropItems.m_drops; DropData value = drops[s_copperDropIndex]; value.m_weight = ForestGammeltroll.CopperOreWeight.Value; drops[s_copperDropIndex] = value; } } } private static int GetMinimumToolTier() { GameObject prefab = Cache.GetPrefab<GameObject>("PickaxeAntler"); ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val)) { Logger.LogError((object)"Could not find PickaxeAntler; it will not turn to stone"); return -1; } return val.m_itemData.m_shared.m_toolTier; } } internal static class PrefabDumper { private class DumpContext { public readonly StringBuilder Sb = new StringBuilder(); public readonly Queue<(GameObject prefab, string via, int depth)> LinkedQueue = new Queue<(GameObject, string, int)>(); public readonly HashSet<GameObject> Dumped = new HashSet<GameObject>(); public GameObject CurrentRoot; public int CurrentLinkDepth; } public const string DumpFileName = "ForestGammeltroll_PrefabDump.txt"; private const int MaxFieldDepth = 7; private const int MaxListElements = 64; private const int MaxLinkedPrefabDepth = 3; private static readonly string[] DeathChainFieldHints = new string[5] { "death", "ragdoll", "destroy", "remove", "petrif" }; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; public static void DumpTrolls() { try { DumpContext dumpContext = new DumpContext(); StringBuilder sb = dumpContext.Sb; sb.AppendLine($"ForestGammeltroll prefab dump - Valheim {GameVersionString()} - {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); sb.AppendLine(); List<GameObject> list = (from go in (from c in Cache.GetPrefabs(typeof(Character)).Values.OfType<Character>() select ((Component)c).gameObject into go where (Object)(object)go.transform.parent == (Object)null select go).Distinct().OrderBy<GameObject, string>((GameObject go) => ((Object)go).name, StringComparer.OrdinalIgnoreCase).ToList() where IsGammel(go) || ContainsCI(((Object)go).name, "troll") || ContainsCI(DisplayName(go), "troll") select go).ToList(); Section(sb, "CANDIDATE PREFABS (Character prefabs with 'gammel' or 'troll' in the prefab or display name)"); foreach (GameObject item in list) { Character component = item.GetComponent<Character>(); sb.AppendLine(" " + ((Object)item).name + " m_name=\"" + component.m_name + "\" display=\"" + DisplayName(item) + "\" [" + string.Join(", ", from c in item.GetComponents<Component>() where Object.op_Implicit((Object)(object)c) select ((object)c).GetType().Name) + "]"); } sb.AppendLine(); DumpSpawnReferences(sb); List<GameObject> list2 = list.Where(IsGammel).ToList(); GameObject val = ((IEnumerable<GameObject>)list).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => ((Object)go).name == "Troll")); if (list2.Count == 0) { sb.AppendLine("!!! No prefab containing 'gammel' was found."); } foreach (GameObject item2 in list2) { Section(sb, "FULL DUMP: " + ((Object)item2).name); DumpPrefab(dumpContext, item2, includeRenderers: true); DumpHumanoidItems(dumpContext, item2); } if (dumpContext.LinkedQueue.Count > 0) { Section(sb, "DEATH CHAIN: prefabs referenced from death/ragdoll/destroy/remove fields"); while (dumpContext.LinkedQueue.Count > 0) { var (val2, text, currentLinkDepth) = dumpContext.LinkedQueue.Dequeue(); if (!dumpContext.Dumped.Contains(val2)) { sb.AppendLine(); sb.AppendLine("----- Linked prefab: " + ((Object)val2).name + " (via " + text + ") -----"); dumpContext.CurrentLinkDepth = currentLinkDepth; DumpPrefab(dumpContext, val2, includeRenderers: true); } } } if (Object.op_Implicit((Object)(object)val)) { Section(sb, "COMPARISON: regular Troll (components and stats, no materials)"); dumpContext.CurrentLinkDepth = 3; DumpPrefab(dumpContext, val, includeRenderers: false); DumpHumanoidItems(dumpContext, val); } else { sb.AppendLine("!!! No prefab named exactly 'Troll' was found."); } string text2 = Path.Combine(Paths.BepInExRootPath, "ForestGammeltroll_PrefabDump.txt"); File.WriteAllText(text2, sb.ToString()); Logger.LogInfo((object)$"Prefab dump written to {text2} ({list2.Count} gammel prefab(s), troll found: {Object.op_Implicit((Object)(object)val)})"); } catch (Exception arg) { Logger.LogError((object)$"Prefab dump failed: {arg}"); } static bool IsGammel(GameObject go) { if (!ContainsCI(((Object)go).name, "gammel")) { return ContainsCI(DisplayName(go), "gammel"); } return true; } } private static void DumpSpawnReferences(StringBuilder sb) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) Section(sb, "SPAWN REFERENCES (loaded SpawnSystemList / CreatureSpawner entries for trolls)"); SpawnSystemList[] array = Resources.FindObjectsOfTypeAll<SpawnSystemList>(); foreach (SpawnSystemList val in array) { foreach (SpawnData spawner in val.m_spawners) { if (Object.op_Implicit((Object)(object)spawner.m_prefab) && (ContainsCI(((Object)spawner.m_prefab).name, "troll") || ContainsCI(((Object)spawner.m_prefab).name, "gammel"))) { sb.AppendLine($" SpawnSystemList '{((Object)val).name}': name='{spawner.m_name}' prefab={((Object)spawner.m_prefab).name} biome={spawner.m_biome} area={spawner.m_biomeArea} " + $"enabled={spawner.m_enabled} chance={F(spawner.m_spawnChance)} interval={F(spawner.m_spawnInterval)} maxSpawned={spawner.m_maxSpawned} " + $"group={spawner.m_groupSizeMin}-{spawner.m_groupSizeMax} night={spawner.m_spawnAtNight} day={spawner.m_spawnAtDay} " + $"levels={spawner.m_minLevel}-{spawner.m_maxLevel} globalKey='{spawner.m_requiredGlobalKey}' huntPlayer={spawner.m_huntPlayer}"); } } } CreatureSpawner[] array2 = Resources.FindObjectsOfTypeAll<CreatureSpawner>(); foreach (CreatureSpawner val2 in array2) { if (Object.op_Implicit((Object)(object)val2.m_creaturePrefab) && (ContainsCI(((Object)val2.m_creaturePrefab).name, "troll") || ContainsCI(((Object)val2.m_creaturePrefab).name, "gammel"))) { sb.AppendLine($" CreatureSpawner on '{GetPath(((Component)val2).transform)}': prefab={((Object)val2.m_creaturePrefab).name} levels={val2.m_minLevel}-{val2.m_maxLevel}"); } } sb.AppendLine(" (Location prefabs are soft-referenced and usually not loaded at the main menu, so CreatureSpawners in locations may be missing here.)"); sb.AppendLine(); } private static void DumpPrefab(DumpContext ctx, GameObject prefab, bool includeRenderers) { ctx.Dumped.Add(prefab); GameObject currentRoot = ctx.CurrentRoot; ctx.CurrentRoot = prefab; DumpGameObject(ctx, prefab.transform, 0, includeRenderers); ctx.CurrentRoot = currentRoot; } private static void DumpGameObject(DumpContext ctx, Transform t, int indent, bool includeRenderers) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown StringBuilder sb = ctx.Sb; string text = new string(' ', indent * 2); GameObject gameObject = ((Component)t).gameObject; sb.AppendLine($"{text}+ {((Object)gameObject).name} (activeSelf={gameObject.activeSelf}, layer={LayerMask.LayerToName(gameObject.layer)}({gameObject.layer}), tag={gameObject.tag})"); sb.AppendLine(text + " localPos=" + V(t.localPosition) + " localRot=" + V(t.localEulerAngles) + " localScale=" + V(t.localScale)); Component[] components = gameObject.GetComponents<Component>(); foreach (Component val in components) { if (!Object.op_Implicit((Object)(object)val)) { sb.AppendLine(text + " * <missing script>"); } else if (!(val is Transform)) { sb.AppendLine(text + " * " + ((object)val).GetType().FullName); string pad = text + " "; DumpBuiltinComponent(ctx, val, pad, includeRenderers); if (val is MonoBehaviour) { DumpFields(ctx, val, ((object)val).GetType(), pad, 0, follow: false, ""); } } } foreach (Transform item in t) { Transform t2 = item; DumpGameObject(ctx, t2, indent + 1, includeRenderers); } } private static void DumpBuiltinComponent(DumpContext ctx, Component c, string pad, bool includeRenderers) { //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) StringBuilder sb = ctx.Sb; SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((c is SkinnedMeshRenderer) ? c : null); if (val == null) { MeshRenderer val2 = (MeshRenderer)(object)((c is MeshRenderer) ? c : null); if (val2 == null) { Renderer val3 = (Renderer)(object)((c is Renderer) ? c : null); if (val3 == null) { MeshFilter val4 = (MeshFilter)(object)((c is MeshFilter) ? c : null); if (val4 == null) { CapsuleCollider val5 = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null); if (val5 == null) { SphereCollider val6 = (SphereCollider)(object)((c is SphereCollider) ? c : null); if (val6 == null) { BoxCollider val7 = (BoxCollider)(object)((c is BoxCollider) ? c : null); if (val7 == null) { MeshCollider val8 = (MeshCollider)(object)((c is MeshCollider) ? c : null); if (val8 == null) { Rigidbody val9 = (Rigidbody)(object)((c is Rigidbody) ? c : null); if (val9 == null) { Animator val10 = (Animator)(object)((c is Animator) ? c : null); if (val10 == null) { LODGroup val11 = (LODGroup)(object)((c is LODGroup) ? c : null); if (val11 == null) { ParticleSystem val12 = (ParticleSystem)(object)((c is ParticleSystem) ? c : null); if (val12 != null) { MainModule main = val12.main; object arg = ((MainModule)(ref main)).playOnAwake; main = val12.main; sb.AppendLine($"{pad}playOnAwake={arg} loop={((MainModule)(ref main)).loop}"); } return; } LOD[] lODs = val11.GetLODs(); for (int i = 0; i < lODs.Length; i++) { sb.AppendLine(string.Format("{0}LOD{1}: screenHeight={2} renderers=[{3}]", pad, i, F(lODs[i].screenRelativeTransitionHeight), string.Join(", ", lODs[i].renderers.Select(Name)))); } } else { sb.AppendLine($"{pad}controller={Name((Object)(object)val10.runtimeAnimatorController)} avatar={Name((Object)(object)val10.avatar)} applyRootMotion={val10.applyRootMotion}"); } } else { sb.AppendLine($"{pad}mass={F(val9.mass)} kinematic={val9.isKinematic} gravity={val9.useGravity}"); } } else { sb.AppendLine($"{pad}trigger={((Collider)val8).isTrigger} convex={val8.convex} mesh={Name((Object)(object)val8.sharedMesh)}"); } } else { sb.AppendLine($"{pad}trigger={((Collider)val7).isTrigger} center={V(val7.center)} size={V(val7.size)}"); } } else { sb.AppendLine($"{pad}trigger={((Collider)val6).isTrigger} center={V(val6.center)} radius={F(val6.radius)}"); } } else { sb.AppendLine($"{pad}trigger={((Collider)val5).isTrigger} center={V(val5.center)} radius={F(val5.radius)} height={F(val5.height)} dir={val5.direction}"); } } else { sb.AppendLine($"{pad}mesh={Name((Object)(object)val4.sharedMesh)} verts={(Object.op_Implicit((Object)(object)val4.sharedMesh) ? val4.sharedMesh.vertexCount : 0)}"); } } else { sb.AppendLine($"{pad}enabled={val3.enabled}"); if (includeRenderers) { DumpMaterials(sb, val3, pad); } } } else { sb.AppendLine($"{pad}enabled={((Renderer)val2).enabled} shadowCasting={((Renderer)val2).shadowCastingMode}"); if (includeRenderers) { DumpMaterials(sb, (Renderer)(object)val2, pad); } } } else { string text = $"{pad}enabled={((Renderer)val).enabled} mesh={Name((Object)(object)val.sharedMesh)} verts={(Object.op_Implicit((Object)(object)val.sharedMesh) ? val.sharedMesh.vertexCount : 0)} "; object arg2 = (Object.op_Implicit((Object)(object)val.sharedMesh) ? val.sharedMesh.subMeshCount : 0); string arg3 = Name((Object)(object)val.rootBone); Transform[] bones = val.bones; sb.AppendLine(text + $"subMeshes={arg2} rootBone={arg3} bones={((bones != null) ? bones.Length : 0)}"); if (includeRenderers) { DumpMaterials(sb, (Renderer)(object)val, pad); } } } private static void DumpMaterials(StringBuilder sb, Renderer r, string pad) { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected I4, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) Material[] sharedMaterials = r.sharedMaterials; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if (!Object.op_Implicit((Object)(object)val)) { sb.AppendLine($"{pad}material[{i}] = null"); continue; } Shader shader = val.shader; sb.AppendLine(string.Format("{0}material[{1}] = '{2}' shader='{3}' renderQueue={4}", pad, i, ((Object)val).name, Object.op_Implicit((Object)(object)shader) ? ((Object)shader).name : "null", val.renderQueue)); sb.AppendLine(pad + " keywords=[" + string.Join(", ", val.shaderKeywords) + "]"); if (!Object.op_Implicit((Object)(object)shader)) { continue; } int propertyCount = shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { string propertyName = shader.GetPropertyName(j); int propertyNameId = shader.GetPropertyNameId(j); ShaderPropertyType propertyType = shader.GetPropertyType(j); string text; switch ((int)propertyType) { case 0: text = ((object)val.GetColor(propertyNameId)/*cast due to .constrained prefix*/).ToString(); break; case 1: text = ((object)val.GetVector(propertyNameId)/*cast due to .constrained prefix*/).ToString(); break; case 4: { Texture texture = val.GetTexture(propertyNameId); text = (Object.op_Implicit((Object)(object)texture) ? $"'{((Object)texture).name}' ({texture.width}x{texture.height}) scale={val.GetTextureScale(propertyNameId)} offset={val.GetTextureOffset(propertyNameId)}" : "null"); break; } case 5: text = val.GetInteger(propertyNameId).ToString(Inv); break; default: text = F(val.GetFloat(propertyNameId)); break; } sb.AppendLine($"{pad} {propertyName} ({propertyType}, \"{shader.GetPropertyDescription(j)}\") = {text}"); } } } private static void DumpHumanoidItems(DumpContext ctx, GameObject go) { Humanoid component = go.GetComponent<Humanoid>(); if (!Object.op_Implicit((Object)(object)component)) { return; } List<(string field, GameObject item)> items = new List<(string, GameObject)>(); Add("m_defaultItems", component.m_defaultItems); Add("m_randomWeapon", component.m_randomWeapon); Add("m_randomArmor", component.m_randomArmor); Add("m_randomShield", component.m_randomShield); if (component.m_randomSets != null) { for (int i = 0; i < component.m_randomSets.Length; i++) { Add($"m_randomSets[{i}]", component.m_randomSets[i]?.m_items); } } ctx.Sb.AppendLine(); ctx.Sb.AppendLine("----- Humanoid items of " + ((Object)go).name + " (attacks/damage live here) -----"); foreach (var (text, val) in items) { ctx.Sb.AppendLine(" [" + text + "] " + ((Object)val).name); ItemDrop component2 = val.GetComponent<ItemDrop>(); if (Object.op_Implicit((Object)(object)component2)) { DumpFields(ctx, component2, ((object)component2).GetType(), " ", 0, follow: false, ""); } } void Add(string field, IEnumerable<GameObject> list) { if (list != null) { items.AddRange(from item in list where Object.op_Implicit((Object)(object)item) select (field: field, i: item)); } } } private static void DumpFields(DumpContext ctx, object obj, Type type, string pad, int depth, bool follow, string path) { foreach (FieldInfo field in GetSerializedFields(type)) { object value; try { value = field.GetValue(obj); } catch (Exception ex) { ctx.Sb.AppendLine(pad + field.Name + " = <error " + ex.GetType().Name + ">"); continue; } bool follow2 = follow || DeathChainFieldHints.Any((string h) => ContainsCI(field.Name, h)); DumpValue(ctx, field.Name, value, field.FieldType, pad, depth, follow2, path + "." + field.Name); } } private static void DumpValue(DumpContext ctx, string label, object value, Type declaredType, string pad, int depth, bool follow, string path) { StringBuilder sb = ctx.Sb; if (value == null) { sb.AppendLine(pad + label + " = null"); return; } Object val = (Object)((value is Object) ? value : null); if (val != null) { if (!Object.op_Implicit(val)) { sb.AppendLine(pad + label + " = null"); return; } sb.AppendLine(pad + label + " = " + Name(val) + " (" + ((object)val).GetType().Name + ")"); if (follow) { EnqueueLinked(ctx, val, path); } return; } Type type = value.GetType(); if (type.IsPrimitive || type.IsEnum || value is string || value is decimal) { sb.AppendLine(pad + label + " = " + FormatScalar(value)); } else if (type.Namespace == "UnityEngine") { sb.AppendLine($"{pad}{label} = {value}"); } else if (value is IList list) { sb.AppendLine($"{pad}{label} = [{list.Count}]"); if (depth < 7) { for (int i = 0; i < list.Count && i < 64; i++) { DumpValue(ctx, $"[{i}]", list[i], null, pad + " ", depth + 1, follow, $"{path}[{i}]"); } if (list.Count > 64) { sb.AppendLine($"{pad} ... {list.Count - 64} more"); } } } else if (depth >= 7) { sb.AppendLine(pad + label + " = " + type.Name + " {...}"); } else { sb.AppendLine(pad + label + " = " + type.Name); DumpFields(ctx, value, type, pad + " ", depth + 1, follow, path); } } private static void EnqueueLinked(DumpContext ctx, Object uo, string path) { object obj = ((uo is GameObject) ? uo : null); if (obj == null) { Object obj2 = ((uo is Component) ? uo : null); obj = ((obj2 != null) ? ((Component)obj2).gameObject : null); } GameObject val = (GameObject)obj; if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val.transform.parent != (Object)null) && !((Object)(object)val == (Object)(object)ctx.CurrentRoot) && !ctx.Dumped.Contains(val) && ctx.CurrentLinkDepth < 3) { ctx.LinkedQueue.Enqueue((val, ((Object)ctx.CurrentRoot).name + path, ctx.CurrentLinkDepth + 1)); } } private static IEnumerable<FieldInfo> GetSerializedFields(Type type) { List<Type> list = new List<Type>(); Type type2 = type; while (type2 != null && type2 != typeof(MonoBehaviour) && type2 != typeof(object)) { list.Add(type2); type2 = type2.BaseType; } list.Reverse(); foreach (Type item in list) { FieldInfo[] fields = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsDefined(typeof(NonSerializedAttribute), inherit: false) && !fieldInfo.Name.Contains("<") && (fieldInfo.IsPublic || fieldInfo.IsDefined(typeof(SerializeField), inherit: false))) { yield return fieldInfo; } } } } private static void Section(StringBuilder sb, string title) { sb.AppendLine(new string('=', 100)); sb.AppendLine(title); sb.AppendLine(new string('=', 100)); } private static string GetPath(Transform t) { List<string> list = new List<string>(); while (Object.op_Implicit((Object)(object)t)) { list.Add(((Object)t).name); t = t.parent; } list.Reverse(); return string.Join("/", list); } private static string GameVersionString() { return Version.GetVersionString(false); } private static string DisplayName(GameObject go) { Character component = go.GetComponent<Character>(); if (!Object.op_Implicit((Object)(object)component) || Localization.instance == null) { return ""; } return Localization.instance.Localize(component.m_name); } private static bool ContainsCI(string s, string sub) { if (s != null) { return s.IndexOf(sub, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static string Name(Object o) { if (!Object.op_Implicit(o)) { return "null"; } return "'" + o.name + "'"; } private static string F(float f) { return f.ToString("0.####", Inv); } private static string V(Vector3 v) { //IL_0010: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) return "(" + F(v.x) + ", " + F(v.y) + ", " + F(v.z) + ")"; } private static string FormatScalar(object value) { if (!(value is float f)) { if (!(value is string text)) { return Convert.ToString(value, Inv); } return "\"" + text + "\""; } return F(f); } } internal static class SpawnPatches { [HarmonyPatch(typeof(SpawnSystem), "Spawn")] private static class SpawnSystem_Spawn { private static void Prefix(ref SpawnData critter, Vector3 spawnPoint, bool eventSpawner) { //IL_0030: 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_0037: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) LastSpawnSwapped = false; if (eventSpawner || !Object.op_Implicit((Object)(object)critter.m_prefab) || ((Object)critter.m_prefab).name != "Troll" || (int)Heightmap.FindBiome(spawnPoint) != 8) { return; } GameObject prefab = ForestTrollCreature.Prefab; if (Object.op_Implicit((Object)(object)prefab) && !(Random.Range(0f, 100f) >= ForestGammeltroll.SpawnChance.Value)) { SpawnData val = critter.Clone(); val.m_prefab = prefab; if (!ForestGammeltroll.AllowStars.Value) { val.m_maxLevel = 1; } critter = val; LastSpawnSwapped = true; Logger.LogInfo((object)($"Spawn swap: Troll -> {((Object)prefab).name} at {spawnPoint:F0} " + $"(zone {ZoneSystem.GetZone(spawnPoint)}, chance {ForestGammeltroll.SpawnChance.Value}%)")); } } } private const string TrollPrefabName = "Troll"; public static bool LastSpawnSwapped { get; private set; } } internal static class StarLevelSystemCompat { public const string PluginGUID = "MidnightsFX.StarLevelSystem"; private const string ColorizeMethod = "StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects"; public static void Apply(Harmony harmony) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (Chainloader.PluginInfos.ContainsKey("MidnightsFX.StarLevelSystem")) { MethodInfo methodInfo = AccessTools.Method("StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects", (Type[])null, (Type[])null); if (methodInfo == null) { Logger.LogWarning((object)"Star Level System is installed but StarLevelSystem.modules.Colorization:ApplyColorizationWithoutLevelEffects was not found; starred Forest Gammeltrolls may be recoloured"); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(StarLevelSystemCompat), "SkipForestTroll", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"Star Level System detected: starred Forest Gammeltrolls keep their normal colours"); } } private static bool SkipForestTroll(GameObject cgo) { if (Object.op_Implicit((Object)(object)cgo)) { return !ForestTrollCreature.IsForestTroll(cgo.GetComponent<Character>()); } return true; } } internal class TestSpawnCommand : ConsoleCommand { private const int MaxCount = 50; public override string Name => "fgt_testspawn"; public override string Help => $"[count] Spawn Trolls through the Black Forest open-world spawn path (max {50}); each rolls the swap chance"; public override bool IsCheat => true; public override void Run(string[] args, Terminal context) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Invalid comparison between Unknown and I4 Player player = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)player)) { return; } int result; int num = ((args.Length == 0 || !int.TryParse(args[0], out result)) ? 1 : Mathf.Clamp(result, 1, 50)); SpawnSystem val = (from s in (AccessTools.Field(typeof(SpawnSystem), "m_instances")?.GetValue(null) as List<SpawnSystem>)?.Where((SpawnSystem s) => Object.op_Implicit((Object)(object)s)) orderby Vector3.Distance(((Component)s).transform.position, ((Component)player).transform.position) select s).FirstOrDefault(); SpawnData val2 = val?.m_spawnLists.SelectMany((SpawnSystemList l) => l.m_spawners).FirstOrDefault((Func<SpawnData, bool>)((SpawnData s) => Object.op_Implicit((Object)(object)s.m_prefab) && ((Object)s.m_prefab).name == "Troll")); if (val2 == null) { if (context != null) { context.AddString("No SpawnSystem with a Troll entry found near you"); } return; } MethodInfo methodInfo = AccessTools.Method(typeof(SpawnSystem), "Spawn", (Type[])null, (Type[])null); int num2 = 0; for (int num3 = 0; num3 < num; num3++) { Vector2 val3 = Random.insideUnitCircle * 10f; Vector3 val4 = ((Component)player).transform.position + ((Component)player).transform.forward * 30f + new Vector3(val3.x, 0f, val3.y); val4.y = ZoneSystem.instance.GetGroundHeight(val4) + 0.5f; methodInfo.Invoke(val, new object[3] { val2, val4, false }); Biome val5 = Heightmap.FindBiome(val4); if (SpawnPatches.LastSpawnSwapped) { num2++; } if (context != null) { context.AddString($" #{num3 + 1} at {val4:F0} in {val5}: " + (SpawnPatches.LastSpawnSwapped ? "Forest Gammeltroll" : "Troll") + (((int)val5 != 8) ? " (not Black Forest, never swapped)" : "")); } } if (context != null) { context.AddString($"Ran {num} Troll spawn(s) through SpawnSystem.Spawn: {num2} swapped " + $"(SpawnChance {ForestGammeltroll.SpawnChance.Value}%)"); } } }