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 ChaosPolymorph v1.3.0
plugins/ChaosPolymorph.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; 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.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 ChaosPolymorph { internal static class Access { public static readonly FieldRef<Character, HitData> LastHit = AccessTools.FieldRefAccess<Character, HitData>("m_lastHit"); public static readonly FieldRef<ZNetScene, Dictionary<ZDO, ZNetView>> Instances = AccessTools.FieldRefAccess<ZNetScene, Dictionary<ZDO, ZNetView>>("m_instances"); public static ZNetView NView(Character c) { if (!((Object)(object)c != (Object)null)) { return null; } return ((Component)c).GetComponent<ZNetView>(); } } public enum EitrCostMode { PercentOfMax, Flat } public enum HealthCarryMode { Pool, Borrowed, Percent } internal static class Cfg { public static ConfigEntry<string> BaseStaff; public static ConfigEntry<string> CraftingStation; public static ConfigEntry<int> StationLevel; public static ConfigEntry<string> Recipe; public static ConfigEntry<int> MaxQuality; public static ConfigEntry<float> BaseSeconds; public static ConfigEntry<float> QualityFalloff; public static ConfigEntry<float> MinSecondsPerLevel; public static ConfigEntry<float> ImpactDamage; public static ConfigEntry<EitrCostMode> EitrMode; public static ConfigEntry<float> EitrPercentOfMax; public static ConfigEntry<float> EitrMinimum; public static ConfigEntry<float> EitrFlat; public static ConfigEntry<float> CooldownSeconds; public static ConfigEntry<float> BlastRadius; public static ConfigEntry<int> MaxBounces; public static ConfigEntry<float> BouncePower; public static ConfigEntry<float> Gravity; public static ConfigEntry<float> FuseSeconds; public static ConfigEntry<float> Velocity; public static ConfigEntry<string> TierWeights; public static ConfigEntry<float> HigherTierMultiplier; public static ConfigEntry<int> UnknownTier; public static ConfigEntry<string> TierOverrides; public static ConfigEntry<string> ExcludedTargets; public static ConfigEntry<string> ExcludedForms; public static ConfigEntry<bool> ExcludeFlyingForms; public static ConfigEntry<bool> ExcludeWaterCreatures; public static ConfigEntry<bool> KnownTrophiesCountAsKills; public static ConfigEntry<string> VariantSuffixes; public static ConfigEntry<bool> AggroOnTransform; public static ConfigEntry<bool> AggroOnRevert; public static ConfigEntry<bool> DeathBreaksPolymorph; public static ConfigEntry<HealthCarryMode> HealthMode; public static ConfigEntry<bool> LetThemKeepTheirWeapons; public static ConfigEntry<bool> ShowMessages; public static ConfigEntry<string> TransformEffects; public static ConfigEntry<bool> Verbose; public static ConfigEntry<bool> HenEnabled; public static ConfigEntry<string> HenBaseStaff; public static ConfigEntry<string> HenCraftingStation; public static ConfigEntry<string> HenRecipe; public static ConfigEntry<int> HenStationLevel; public static ConfigEntry<int> HenMaxQuality; public static ConfigEntry<float> HenSeconds; public static ConfigEntry<float> HenCooldown; public static ConfigEntry<float> HenBaseRadius; public static ConfigEntry<float> HenRadiusPerLevel; public static ConfigEntry<float> HenRadiusFalloff; public static ConfigEntry<float> HenMinRadiusPerLevel; public static ConfigEntry<EitrCostMode> HenEitrMode; public static ConfigEntry<string> HenCastFrom; public static ConfigEntry<string> HenDefaultForm; public static ConfigEntry<string> HenEggItems; public static ConfigEntry<string> HenExcludedForms; public static ConfigEntry<float> HenMaxFormHeight; public static ConfigEntry<float> HenShaftThickness; public static ConfigEntry<bool> HenPlaySound; public static ConfigEntry<bool> HenPanic; public static ConfigEntry<bool> HenCastEffect; public static ConfigEntry<string> HenCastEffectFrom; public static ConfigEntry<string> HenParticleSources; public static ConfigEntry<float> HenCastEffectScale; public static ConfigEntry<float> HenEitrPercent; public static ConfigEntry<float> HenEitrMinimum; public static ConfigEntry<float> HenEitrFlat; public static ConfigEntry<bool> HenTrimHead; public static ConfigEntry<bool> HenAnimated; public static ConfigEntry<bool> HenLight; public static ConfigEntry<bool> HenHideOriginalEffects; public static ConfigEntry<bool> HenRenderIcon; public static ConfigEntry<float> HenTrimFraction; public static ConfigEntry<float> HenSize; public static ConfigEntry<float> HenHeightOffset; public static ConfigEntry<float> HenTwist; public static ConfigEntry<float> HenGlow; public static ConfigEntry<float> HenIconSpin; public static ConfigEntry<float> HenIconShaftShown; public static ConfigEntry<bool> MaskEnabled; public static ConfigEntry<bool> MaskSameKind; public static ConfigEntry<bool> MaskEndOnHit; public static ConfigEntry<bool> MaskAllowBosses; public static ConfigEntry<bool> MaskExcludeFlyers; public static ConfigEntry<bool> MaskPlaySound; public static ConfigEntry<bool> MaskCastEffect; public static ConfigEntry<string> MaskBaseStaff; public static ConfigEntry<string> MaskCraftingStation; public static ConfigEntry<string> MaskRecipe; public static ConfigEntry<string> MaskCastFrom; public static ConfigEntry<string> MaskDefaultForm; public static ConfigEntry<string> MaskEggItems; public static ConfigEntry<string> MaskExcludedForms; public static ConfigEntry<int> MaskStationLevel; public static ConfigEntry<int> MaskMaxQuality; public static ConfigEntry<float> MaskCastEitr; public static ConfigEntry<float> MaskDrain; public static ConfigEntry<float> MaskTickSeconds; public static ConfigEntry<float> MaskTickPerLevel; public static ConfigEntry<float> MaskTickFalloff; public static ConfigEntry<float> MaskMinTickPerLevel; public static ConfigEntry<float> MaskMaxHeight; public static ConfigEntry<float> MaskMaxLength; public static ConfigEntry<float> MaskToggleCooldown; public static ConfigEntry<float> MaskAttackLockout; public static ConfigEntry<float> MaskRevealRadius; public static ConfigEntry<float> MaskTopperSize; public static ConfigEntry<float> MaskGlow; public static ConfigEntry<bool> MaskLight; public static ConfigEntry<string> ModelFile; public static ConfigEntry<float> ModelScale; public static ConfigEntry<float> ModelTwist; public static ConfigEntry<string> ModelRotation; public static ConfigEntry<string> ModelOffset; public static ConfigEntry<bool> FlipModel; public static ConfigEntry<bool> ModelOutline; public static ConfigEntry<float> GlowStrength; public static ConfigEntry<bool> HideOriginalParts; public static ConfigEntry<bool> HideOriginalEffects; public static ConfigEntry<bool> RenderIcon; public static ConfigEntry<float> IconLean; public static ConfigEntry<float> IconShaftShown; public static ConfigEntry<float> IconSpin; public const string DefaultExcluded = "Serpent,Leviathan,BonemawSerpent,TrainingDummy,Skeleton_Hildir,Fenring_Cultist_Hildir,GoblinBrute_Hildir,GoblinShaman_Hildir,Skeleton_Hildir_nochest,Fenring_Cultist_Hildir_nochest,GoblinBruteBros_nochest,GoblinShaman_Hildir_nochest,Charred_Melee_Dyrnwyn"; private static Dictionary<int, float> _tierWeights; private static Dictionary<string, int> _tierOverrides; private static HashSet<string> _excludedTargets; private static HashSet<string> _excludedForms; private static HashSet<string> _effects; private static HashSet<string> _variantSuffixes; public static readonly string[] AlwaysExcluded = new string[10] { "TrollFrost", "*_Summoned", "Summoned*", "*_Fader", "Aspect_*", "*_spiritcaller", "DvergerTest", "piece_TrainingDummy", "TrainingDummy", "BogWitchKvastur" }; private static readonly string[] MaskAlwaysExcluded = new string[7] { "*_Summoned", "Summoned*", "*_Fader", "*_spiritcaller", "DvergerTest", "piece_TrainingDummy", "TrainingDummy" }; public static HashSet<string> VariantSuffixSet => _variantSuffixes ?? (_variantSuffixes = ToSet(VariantSuffixes.Value)); public static IEnumerable<string> Effects => _effects ?? (_effects = ToSet(TransformEffects.Value)); public static void Bind(ConfigFile f) { //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Expected O, but got Unknown //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Expected O, but got Unknown BaseStaff = B(f, "1 - Staff", "BaseStaff", "StaffGreenRoots", "Vanilla staff whose attack and projectile are cloned. StaffGreenRoots = Staff of the Wild (lobbed orb, roots removed). StaffClusterbomb = Staff of Fracturing. Restart required."); CraftingStation = B(f, "1 - Staff", "CraftingStation", "forge", "Crafting station prefab name (forge, piece_workbench, ...). Restart required."); StationLevel = B(f, "1 - Staff", "StationLevel", 1, "Minimum station level. Restart required."); Recipe = B(f, "1 - Staff", "Recipe", "RoundLog:10:5,Bronze:4:2,SurtlingCore:2:1,AncientSeed:1:1", "Comma list of Item:Amount:AmountPerUpgradeLevel. Default is all Black Forest materials. Restart required."); MaxQuality = B(f, "1 - Staff", "MaxQuality", 4, "Maximum upgrade level. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10)); BaseSeconds = B(f, "1 - Staff", "BaseSeconds", 5f, "Transformation length at quality 1."); QualityFalloff = B(f, "1 - Staff", "QualityFalloff", 0.85f, "Each quality level above 1 adds this share of the previous level's bonus (diminishing returns). Defaults: Q2 9.25s, Q3 12.9s, Q4 15.9s, Q5 18.5s. 1 = no falloff.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); MinSecondsPerLevel = B(f, "1 - Staff", "MinSecondsPerLevel", 2f, "Floor for what each extra quality level adds, so very high qualities (Forge of Potential) still grow slowly."); ImpactDamage = B(f, "1 - Staff", "ImpactDamage", 0f, "Blunt damage dealt by the blast. 0 = pure utility, no damage."); EitrMode = B(f, "2 - Eitr", "CostMode", EitrCostMode.PercentOfMax, "PercentOfMax: cost is a share of the caster's max eitr (never below Minimum), so it is always castable once you have ANY eitr food from Wizardry/PoV, but it eats most of your pool. Flat: fixed cost."); EitrPercentOfMax = B(f, "2 - Eitr", "PercentOfMax", 0.6f, "Share of max eitr used per cast in PercentOfMax mode.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); EitrMinimum = B(f, "2 - Eitr", "Minimum", 20f, "Lowest possible cost in PercentOfMax mode. Keep this at or below what ONE Black Forest eitr food gives."); EitrFlat = B(f, "2 - Eitr", "FlatCost", 40f, "Cost per cast in Flat mode. Use chaospoly_eitr in the console to see your current max eitr."); CooldownSeconds = B(f, "2 - Eitr", "CooldownSeconds", 0f, "Optional cooldown between casts. 0 = off."); BlastRadius = B(f, "3 - Projectile v2", "BlastRadius", 4f, "Radius of the polymorph burst in metres."); MaxBounces = B(f, "3 - Projectile v2", "MaxBounces", 0, "0 = burst on the first thing it touches (recommended). Above 0 = bounce that many times off terrain first."); BouncePower = B(f, "3 - Projectile v2", "BouncePower", 0.5f, "Velocity kept on each bounce (0-1). Only used when MaxBounces > 0."); Gravity = B(f, "3 - Projectile v2", "Gravity", 0f, "Projectile gravity. 0 = keep the base staff's arc."); FuseSeconds = B(f, "3 - Projectile v2", "FuseSeconds", 0f, "Burst after this many seconds even if it hasn't hit anything. 0 = burst when the projectile's normal lifetime runs out."); Velocity = B(f, "3 - Projectile v2", "Velocity", 0f, "Launch speed. 0 = keep the base staff's value."); TierWeights = B(f, "4 - Forms", "TierWeights", "1:12,2:8,3:5,4:3,5:2,6:1.5,7:1,8:1", "Biome tier:weight. Tiers: 1 Meadows, 2 Black Forest, 3 Swamp, 4 Mountain, 5 Plains, 6 Mistlands, 7 Ashlands, 8 Deep North. Higher weight = more likely."); HigherTierMultiplier = B(f, "4 - Forms", "HigherTierMultiplier", 0.35f, "Extra multiplier for forms from a HIGHER tier than the target. 0 = never upgrade a mob."); UnknownTier = B(f, "4 - Forms", "UnknownTier", 3, "Tier used for modded creatures the mod can't place."); TierOverrides = B(f, "4 - Forms", "TierOverrides", "", "Prefab:Tier overrides for any creature, e.g. 'Troll:3,SomeMonstrumMob:4'."); ExcludedTargets = B(f, "4 - Forms", "ExcludedTargets", "Serpent,Leviathan,BonemawSerpent,TrainingDummy,Skeleton_Hildir,Fenring_Cultist_Hildir,GoblinBrute_Hildir,GoblinShaman_Hildir,Skeleton_Hildir_nochest,Fenring_Cultist_Hildir_nochest,GoblinBruteBros_nochest,GoblinShaman_Hildir_nochest,Charred_Melee_Dyrnwyn", "Extra prefabs that can never be polymorphed; * is a wildcard. Bosses, tamed creatures, summons, Gammeltroll and boss aspects are always immune."); ExcludedForms = B(f, "4 - Forms", "ExcludedForms", "Serpent,Leviathan,BonemawSerpent,TrainingDummy,Skeleton_Hildir,Fenring_Cultist_Hildir,GoblinBrute_Hildir,GoblinShaman_Hildir,Skeleton_Hildir_nochest,Fenring_Cultist_Hildir_nochest,GoblinBruteBros_nochest,GoblinShaman_Hildir_nochest,Charred_Melee_Dyrnwyn", "Extra prefabs never picked as a new form; * is a wildcard."); ExcludeFlyingForms = B(f, "4 - Forms", "ExcludeFlyingForms", def: true, "Never turn something into a flyer (Deathsquito, Drake, Bat, Gjall, Volture...)."); ExcludeWaterCreatures = B(f, "4 - Forms", "ExcludeWaterCreatures", def: true, "Water-only creatures can't be targets or forms."); KnownTrophiesCountAsKills = B(f, "4 - Forms", "KnownTrophiesCountAsKills", def: true, "Creatures whose trophy you have discovered count as killed, so existing characters start with a pool."); VariantSuffixes = B(f, "4 - Forms", "VariantSuffixes", "sleeping,nonsleeping,noarcher,nochest,frozen,meadows,swamps,mountains,deepnorth,aspect", "Name parts that mark a variant of the same creature (Skeleton_Meadows_noarcher = Skeleton). Variants count as one shape, and a creature never turns into its own kind, original or current."); AggroOnTransform = B(f, "5 - Behaviour", "AggroOnTransform", def: true, "Transformed creature targets the caster."); AggroOnRevert = B(f, "5 - Behaviour", "AggroOnRevert", def: true, "Creature targets the caster again when it changes back."); HealthMode = B(f, "5 - Behaviour", "HealthModel", HealthCarryMode.Pool, "Pool: the creature keeps its own health in any body (a 600 HP Troll becomes a 600 HP Skeleton, with the Skeleton's attacks, speed and weaknesses); damage carries 1:1. Borrowed: it gets the borrowed body's health (scaled by %), and damage taken comes off its real health. Weak: killing a Skeleton-Troll only costs the Troll ~40 HP. Percent: health % carries both ways, so killing the borrowed body kills the original. Very strong."); DeathBreaksPolymorph = B(f, "5 - Behaviour", "DeathBreaksPolymorph", def: true, "A killing blow on a polymorphed creature turns it back, then the same hit kills the ORIGINAL creature. Other mods (Path of Valheiman XP, Monstrum, CLLC) see a normal kill of the real creature."); LetThemKeepTheirWeapons = f.Bind<bool>("5 - Behaviour", "LetThemKeepTheirWeapons", false, new ConfigDescription("Polymorphed creatures keep holding whatever the original was carrying, if the new body doesn't replace it. Skeletons with Troll logs. You're welcome.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, Browsable = false } })); ShowMessages = B(f, "5 - Behaviour", "ShowMessages", def: true, "Show top-left messages to the caster.", null, synced: false); TransformEffects = B(f, "5 - Behaviour", "TransformEffects", "vfx_odin_despawn", "Comma list of effect prefabs played on transform/revert."); Verbose = B(f, "5 - Behaviour", "VerboseLogging", def: false, "Detailed log output for troubleshooting: every burst (who was caught, skipped and why), the creature catalog, projectile settings and model fitting. Warnings are always logged.", null, synced: false); HenEnabled = B(f, "7 - Hen Staff", "Enabled", def: true, "Add the Staff of the Ember Hen. Restart required."); HenBaseStaff = B(f, "7 - Hen Staff", "BaseStaff", "StaffShield", "Vanilla staff cloned for the cast animation and shaft (StaffShield = Staff of Protection). Restart required."); HenCraftingStation = B(f, "7 - Hen Staff", "CraftingStation", "forge", "Crafting station. Restart required."); HenStationLevel = B(f, "7 - Hen Staff", "StationLevel", 1, "Minimum station level. Restart required."); HenRecipe = B(f, "7 - Hen Staff", "Recipe", "BlackMetal:8:4,LinenThread:6:3,Feathers:10:5", "Item:Amount:AmountPerLevel list (Plains materials by default). Restart required."); HenMaxQuality = B(f, "7 - Hen Staff", "MaxQuality", 4, "Maximum upgrade level. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10)); HenSeconds = B(f, "7 - Hen Staff", "HenSeconds", 4f, "How long creatures stay Hens. Fixed: quality doesn't change it."); HenCooldown = B(f, "7 - Hen Staff", "CooldownSeconds", 45f, "Time between casts. Fixed: quality doesn't change it."); HenBaseRadius = B(f, "7 - Hen Staff", "BaseRadius", 4f, "Radius around the caster at quality 1, in metres."); HenRadiusPerLevel = B(f, "7 - Hen Staff", "RadiusPerLevel", 1.4f, "Extra radius at quality 2; later levels add less (falloff). Defaults: Q2 5.4m, Q3 6.6m, Q4 7.6m."); HenRadiusFalloff = B(f, "7 - Hen Staff", "RadiusFalloff", 0.85f, "Each further level adds this share of the previous level's extra radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); HenMinRadiusPerLevel = B(f, "7 - Hen Staff", "MinRadiusPerLevel", 0.25f, "Floor for what each extra level adds (Forge of Potential qualities)."); HenCastFrom = B(f, "7 - Hen Staff", "CastAnimationFrom", "StaffFireball", "Staff whose (quicker) cast animation is borrowed. StaffFireball = Staff of Embers. Restart required."); HenDefaultForm = B(f, "7 - Hen Staff", "DefaultForm", "Hen", "Creature a staff uses before any trophy is slotted."); HenEggItems = B(f, "7 - Hen Staff", "EggItems", "ChickenEgg", "Items that slot the default form (eggs) when dragged onto the staff."); HenMaxFormHeight = B(f, "7 - Hen Staff", "MaxSlotHeight", 3f, "Creatures taller than this (metres, from their body capsule) can't be slotted. Keeps Trolls, Lox and similar out automatically; the refusal message shows a creature's height."); HenExcludedForms = B(f, "7 - Hen Staff", "ExcludedForms", "", "Extra creatures that can't be slotted (* wildcards). Bosses, flyers, water creatures, babies and summons are always excluded."); HenPlaySound = B(f, "7 - Hen Staff", "PlayCreatureSound", def: true, "Play the slotted creature's sound on cast."); HenPanic = B(f, "7 - Hen Staff", "Panic", def: true, "Emberized creatures run around like headless chickens, away from where you cast. Off = they just stand around."); HenCastEffect = B(f, "7 - Hen Staff", "CastEffect", def: true, "Show a burst on cast and a puff where each creature changes.", null, synced: false); HenCastEffectFrom = B(f, "7 - Hen Staff", "CastEffectFrom", "StaffFireball", "Staff whose projectile explosion is used as the cast burst.", null, synced: false); HenCastEffectScale = B(f, "7 - Hen Staff", "CastEffectScale", 1f, "Size multiplier for the cast burst.", null, synced: false); HenParticleSources = B(f, "7 - Hen Staff", "ParticleMaterialFrom", "vfx_odin_despawn,vfx_FireAddFuel,vfx_fireball_staff_explosion,fx_Torch_Carried", "Effects (first found wins) whose particle material the ember bursts borrow. Restart required.", null, synced: false); HenEitrMode = B(f, "7 - Hen Staff", "EitrCostMode", EitrCostMode.PercentOfMax, "PercentOfMax or Flat, like the Chaos staff."); HenEitrPercent = B(f, "7 - Hen Staff", "EitrPercentOfMax", 0.5f, "Share of max eitr per cast in PercentOfMax mode.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); HenEitrMinimum = B(f, "7 - Hen Staff", "EitrMinimum", 25f, "Lowest cost in PercentOfMax mode."); HenEitrFlat = B(f, "7 - Hen Staff", "EitrFlatCost", 50f, "Cost per cast in Flat mode."); HenTrimHead = B(f, "8 - Hen Staff Model", "TrimOriginalHead", def: true, "Remove Staff of Protection's head so only the shaft remains (only if the game's mesh allows it; otherwise the hen perches on top). Restart required.", null, synced: false); HenTrimFraction = B(f, "8 - Hen Staff Model", "TrimFraction", 0.22f, "Share of the staff's length trimmed off the head end.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.6f), synced: false); HenShaftThickness = B(f, "8 - Hen Staff Model", "PlainShaftThickness", 0.018f, "Radius of the fallback plain shaft, as a share of the staff's length.", null, synced: false); HenSize = B(f, "8 - Hen Staff Model", "HenSize", 0.22f, "Hen size as a share of the staff's length.", null, synced: false); HenHeightOffset = B(f, "8 - Hen Staff Model", "HeightOffset", 0f, "Nudge the hen along the staff, as a share of its length (negative = lower).", null, synced: false); HenTwist = B(f, "8 - Hen Staff Model", "Twist", 0f, "Degrees to turn the hen around the staff.", null, synced: false); HenAnimated = B(f, "8 - Hen Staff Model", "Animated", def: true, "Let the hen idle-animate on the staff.", null, synced: false); HenGlow = B(f, "8 - Hen Staff Model", "GlowStrength", 1.5f, "Ember glow brightness. 0 = off.", null, synced: false); HenLight = B(f, "8 - Hen Staff Model", "EmberLight", def: true, "Small warm light from the hen.", null, synced: false); HenHideOriginalEffects = B(f, "8 - Hen Staff Model", "HideOriginalEffects", def: true, "Hide Staff of Protection's own particles and lights.", null, synced: false); HenRenderIcon = B(f, "8 - Hen Staff Model", "RenderIcon", def: true, "Render a new inventory icon.", null, synced: false); HenIconSpin = B(f, "8 - Hen Staff Model", "IconSpin", 0f, "Icon: spin around the staff, in degrees (180 shows the creature's other side).", null, synced: false); HenIconShaftShown = B(f, "8 - Hen Staff Model", "IconShaftShare", 0.15f, "Icon: share of the shaft shown below the creature. Lower = more zoomed in on the creature.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 1f), synced: false); MaskEnabled = B(f, "9 - Masquerade Staff", "Enabled", def: true, "Add the Staff of the Masquerade (Meadows): turns YOU into the creature it holds. Restart required."); MaskBaseStaff = B(f, "9 - Masquerade Staff", "BaseStaff", "StaffShield", "Vanilla staff cloned for the shaft. Restart required."); MaskCraftingStation = B(f, "9 - Masquerade Staff", "CraftingStation", "piece_workbench", "Crafting station. Restart required."); MaskStationLevel = B(f, "9 - Masquerade Staff", "StationLevel", 1, "Minimum station level. Restart required."); MaskRecipe = B(f, "9 - Masquerade Staff", "Recipe", "Wood:10:5,Flint:6:3,LeatherScraps:6:3,Dandelion:4:2", "Item:Amount:AmountPerLevel list (Meadows materials by default). Restart required."); MaskMaxQuality = B(f, "9 - Masquerade Staff", "MaxQuality", 4, "Maximum upgrade level. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10)); MaskCastFrom = B(f, "9 - Masquerade Staff", "CastAnimationFrom", "StaffFireball", "Staff whose (quick) cast animation is borrowed. Restart required."); MaskDefaultForm = B(f, "9 - Masquerade Staff", "DefaultForm", "Hen", "Creature a staff holds before any trophy is slotted."); MaskEggItems = B(f, "9 - Masquerade Staff", "EggItems", "ChickenEgg", "Items that slot the default form when dragged onto the staff."); MaskCastEitr = B(f, "9 - Masquerade Staff", "CastEitr", 10f, "Eitr spent to put the disguise on."); MaskDrain = B(f, "9 - Masquerade Staff", "DrainPerTick", 1f, "Eitr drained each tick while disguised. Eitr doesn't regenerate while disguised. Out of eitr = you change back."); MaskTickSeconds = B(f, "9 - Masquerade Staff", "TickSeconds", 1f, "Seconds between drain ticks at quality 1."); MaskTickPerLevel = B(f, "9 - Masquerade Staff", "TickSecondsPerLevel", 0.5f, "Extra seconds between ticks at quality 2; later levels add less (falloff). Defaults: Q2 1.5s, Q3 1.9s, Q4 2.2s."); MaskTickFalloff = B(f, "9 - Masquerade Staff", "TickFalloff", 0.8f, "Each further level adds this share of the previous level's extra seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); MaskMinTickPerLevel = B(f, "9 - Masquerade Staff", "MinTickSecondsPerLevel", 0.1f, "Floor for what each extra level adds (Forge of Potential qualities)."); MaskMaxHeight = B(f, "9 - Masquerade Staff", "MaxDisguiseHeight", 1.9f, "Disguises taller than this (metres) are shrunk to fit: pocket Trolls. Smaller creatures keep their real size."); MaskMaxLength = B(f, "9 - Masquerade Staff", "MaxDisguiseLength", 2.4f, "Disguises longer than this (metres) are shrunk to fit: mini Lox."); MaskSameKind = B(f, "9 - Masquerade Staff", "SameKindIgnoresYou", def: true, "Creatures of the same kind as your disguise don't treat you as an enemy (and stop chasing you). Everything else still does."); MaskEndOnHit = B(f, "9 - Masquerade Staff", "HitEndsDisguise", def: true, "Taking any damage ends the disguise. Attacking always ends it."); MaskAllowBosses = B(f, "9 - Masquerade Staff", "AllowBosses", def: true, "Boss trophies can be slotted (a pocket Eikthyr)."); MaskExcludeFlyers = B(f, "9 - Masquerade Staff", "ExcludeFlyers", def: true, "Flying creatures can't be slotted (they have no walking animations)."); MaskExcludedForms = B(f, "9 - Masquerade Staff", "ExcludedForms", "", "Extra creatures that can't be slotted (* wildcards). Water creatures, babies and summons are always excluded."); MaskAttackLockout = B(f, "9 - Masquerade Staff", "AttackLockout", 1f, "Seconds after an attack ends the disguise before you can attack at all, so the click that dropped it (and Valheim's queued retry) does nothing."); MaskRevealRadius = B(f, "9 - Masquerade Staff", "RevealAlertRadius", 15f, "When a disguise ends, creatures of that kind within this many metres become alert to you: no free sneak attacks on the ones you fooled. 0 = off."); MaskToggleCooldown = B(f, "9 - Masquerade Staff", "ToggleCooldown", 1.5f, "Seconds after changing (either way) before the staff can be cast again."); MaskPlaySound = B(f, "9 - Masquerade Staff", "PlayCreatureSound", def: true, "Play the creature's sound when someone puts on a disguise."); MaskCastEffect = B(f, "9 - Masquerade Staff", "CastEffect", def: true, "Green puff when someone changes.", null, synced: false); MaskTopperSize = B(f, "10 - Masquerade Staff Model", "TopperSize", 0.22f, "Creature size on the staff as a share of the staff's length. Trim, twist and icon settings are shared with the Hen staff's model section.", null, synced: false); MaskGlow = B(f, "10 - Masquerade Staff Model", "GlowStrength", 1.2f, "Green glow brightness. 0 = off.", null, synced: false); MaskLight = B(f, "10 - Masquerade Staff Model", "GreenLight", def: true, "Small green light from the topper.", null, synced: false); ModelFile = B(f, "6 - Model", "ModelFile", "monkey_staff.glb", "A .glb next to the DLL (or a full path) used as the staff's look. Empty = keep the base staff's look. All model settings need a restart.", null, synced: false); ModelScale = B(f, "6 - Model", "Scale", 1f, "Size multiplier after auto-fitting the model to the base staff's length.", null, synced: false); ModelTwist = B(f, "6 - Model", "TwistDegrees", 180f, "Degrees to spin the model around its length (which way the face points). 180 suits the bundled monkey staff.", null, synced: false); ModelRotation = B(f, "6 - Model", "RotationOffset", "0,0,0", "Extra x,y,z rotation in degrees.", null, synced: false); ModelOffset = B(f, "6 - Model", "PositionOffset", "0,0,0", "Extra x,y,z offset in metres, e.g. slide it through your hand.", null, synced: false); FlipModel = B(f, "6 - Model", "FlipEnds", def: false, "Turn the model end-for-end if the head ends up at the bottom.", null, synced: false); ModelOutline = B(f, "6 - Model", "Outline", def: true, "Draw the model's black cartoon-outline shell, if it has one.", null, synced: false); GlowStrength = B(f, "6 - Model", "GlowStrength", 2f, "Brightness of the model's glowing parts. 0 = off.", null, synced: false); HideOriginalParts = B(f, "6 - Model", "HideOriginalParts", def: true, "Hide small leftover pieces of the base staff's model.", null, synced: false); HideOriginalEffects = B(f, "6 - Model", "HideOriginalEffects", def: false, "Hide the base staff's particle effects.", null, synced: false); RenderIcon = B(f, "6 - Model", "RenderIcon", def: true, "Render a new inventory icon from the model.", null, synced: false); IconLean = B(f, "6 - Model", "IconLean", -20f, "Icon: degrees the staff leans from upright. Negative = head leans left (like Staff of the Wild's icon), positive = right.", null, synced: false); IconShaftShown = B(f, "6 - Model", "IconShaftShown", 0.35f, "Icon: share of the staff's length shown, measured from the head down. Lower = more zoomed in on the head. 1 = whole staff.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1f), synced: false); IconSpin = B(f, "6 - Model", "IconSpin", 0f, "Icon: extra spin around the staff's length, in degrees (180 shows the other side of the head).", null, synced: false); } private static ConfigEntry<T> B<T>(ConfigFile f, string section, string key, T def, string desc, AcceptableValueBase range = null, bool synced = true) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown return f.Bind<T>(section, key, def, new ConfigDescription(desc, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = synced } })); } public static float DurationForQuality(int quality) { int num = Math.Max(1, Math.Min(quality, 100)); float num2 = 0f; for (int i = 0; i < num; i++) { num2 += ((i == 0) ? BaseSeconds.Value : Math.Max(MinSecondsPerLevel.Value, BaseSeconds.Value * (float)Math.Pow(QualityFalloff.Value, i))); } return Math.Max(0.5f, num2); } public static void InvalidateCaches() { _tierWeights = null; _tierOverrides = null; _excludedTargets = null; _excludedForms = null; _effects = null; _variantSuffixes = null; } public static float TierWeight(int tier) { if (_tierWeights == null) { _tierWeights = new Dictionary<int, float>(); foreach (KeyValuePair<string, string> item in Pairs(TierWeights.Value)) { if (int.TryParse(item.Key, out var result) && TryFloat(item.Value, out var f)) { _tierWeights[result] = f; } } } if (_tierWeights.TryGetValue(tier, out var value)) { return value; } return 1f; } public static bool TryTierOverride(string prefab, out int tier) { if (_tierOverrides == null) { _tierOverrides = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, string> item in Pairs(TierOverrides.Value)) { if (int.TryParse(item.Value, out var result)) { _tierOverrides[item.Key] = result; } } } return _tierOverrides.TryGetValue(prefab, out tier); } public static bool IsMaskExcluded(string prefab) { if (!MatchesAny(prefab, MaskAlwaysExcluded)) { return MatchesAny(prefab, ToSet(MaskExcludedForms.Value)); } return true; } public static bool IsEmberExcluded(string prefab) { if (!MatchesAny(prefab, AlwaysExcluded)) { return MatchesAny(prefab, ToSet(HenExcludedForms.Value)); } return true; } public static bool IsExcludedTarget(string prefab) { if (!MatchesAny(prefab, AlwaysExcluded)) { return MatchesAny(prefab, _excludedTargets ?? (_excludedTargets = ToSet(ExcludedTargets.Value))); } return true; } public static bool IsExcludedForm(string prefab) { if (!MatchesAny(prefab, AlwaysExcluded)) { return MatchesAny(prefab, _excludedForms ?? (_excludedForms = ToSet(ExcludedForms.Value))); } return true; } private static bool MatchesAny(string name, IEnumerable<string> patterns) { foreach (string pattern in patterns) { if (Glob(name, pattern)) { return true; } } return false; } private static bool Glob(string name, string pattern) { if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(pattern)) { return false; } if (pattern.IndexOf('*') < 0) { return string.Equals(name, pattern, StringComparison.OrdinalIgnoreCase); } string[] array = pattern.Split('*'); int startIndex = 0; for (int i = 0; i < array.Length; i++) { string text = array[i]; if (text.Length != 0) { int num = name.IndexOf(text, startIndex, StringComparison.OrdinalIgnoreCase); if (num < 0 || (i == 0 && num != 0)) { return false; } startIndex = num + text.Length; } } string text2 = array[^1]; if (text2.Length != 0) { return name.EndsWith(text2, StringComparison.OrdinalIgnoreCase); } return true; } public static RequirementConfig[] ParseRequirements() { return ParseRequirements(Recipe.Value); } public static RequirementConfig[] ParseRequirements(string recipe) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = (recipe ?? "").Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Trim().Split(':'); if (array2.Length >= 2 && array2[0].Length != 0 && int.TryParse(array2[1], out var result)) { int result2 = 0; if (array2.Length > 2) { int.TryParse(array2[2], out result2); } list.Add(new RequirementConfig(array2[0].Trim(), result, result2, true)); } } if (list.Count == 0) { Plugin.Log.LogWarning((object)"Recipe config parsed to nothing; the staff will be free to craft."); } return list.ToArray(); } public static HashSet<string> ToSet(string csv) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(csv)) { return hashSet; } string[] array = csv.Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } private static IEnumerable<KeyValuePair<string, string>> Pairs(string csv) { if (string.IsNullOrEmpty(csv)) { yield break; } string[] array = csv.Split(','); foreach (string text in array) { int num = text.IndexOf(':'); if (num > 0) { yield return new KeyValuePair<string, string>(text.Substring(0, num).Trim(), text.Substring(num + 1).Trim()); } } } private static bool TryFloat(string s, out float f) { return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out f); } } internal static class Commands { public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new KillsCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new EitrCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new LearnCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ForgetCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new NoCooldownCommand()); } internal static void Print(string s) { Console instance = Console.instance; if (instance != null) { instance.Print(s); } } } internal class KillsCommand : ConsoleCommand { public override string Name => "chaospoly_pool"; public override string Help => "List the shapes your Chaos Polymorph staff can use, with their biome tier."; public override void Run(string[] args) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !CreatureCatalog.EnsureBuilt()) { Commands.Print("Load into a world first."); return; } HashSet<string> kills = KillTracker.GetKills(localPlayer); HashSet<string> pool = KillTracker.GetPool(localPlayer); foreach (string item in pool.OrderBy(CreatureCatalog.TierOf).ThenBy((string x) => x)) { CreatureInfo creatureInfo = CreatureCatalog.Get(item); string text = ((creatureInfo == null) ? "unknown prefab" : (creatureInfo.FormEligible ? "usable" : ("blocked: " + creatureInfo.FormBlockReason))); string text2 = (kills.Contains(item) ? "killed" : "trophy"); Commands.Print($"T{CreatureCatalog.TierOf(item)} {item} [family {CreatureCatalog.Family(item)}] ({text2}, {text})"); } Commands.Print($"{pool.Count} shapes known."); } } internal class EitrCommand : ConsoleCommand { public override string Name => "chaospoly_eitr"; public override string Help => "Show your max eitr and what one polymorph cast costs right now."; public override void Run(string[] args) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Commands.Print($"Max eitr {((Character)localPlayer).GetMaxEitr():0}, cast cost {StaffRuntime.EitrCost(localPlayer):0} ({Cfg.EitrMode.Value})."); Commands.Print("Duration by quality: " + string.Join(", ", from q in Enumerable.Range(1, 6) select $"Q{q} {Cfg.DurationForQuality(q):0.#}s")); } } } internal class LearnCommand : ConsoleCommand { public override string Name => "chaospoly_learn"; public override string Help => "[prefab] Add a shape to your pool (testing)."; public override bool IsCheat => true; public override void Run(string[] args) { if (args.Length < 1 || CreatureCatalog.Get(args[0]) == null) { Commands.Print("Unknown creature prefab."); return; } KillTracker.Add(Player.m_localPlayer, CreatureCatalog.Get(args[0]).Name); Commands.Print("Learned " + args[0] + "."); } } internal class ForgetCommand : ConsoleCommand { public override string Name => "chaospoly_forget"; public override string Help => "[prefab|all] Remove killed shapes from your pool (testing). Trophy-known shapes come back unless KnownTrophiesCountAsKills is off."; public override bool IsCheat => true; public override void Run(string[] args) { if (args.Length < 1) { Commands.Print("Usage: chaospoly_forget <prefab|all>"); } else { Commands.Print(KillTracker.Remove(Player.m_localPlayer, args[0]) ? ("Forgot " + args[0] + ".") : "Nothing to forget."); } } } internal class NoCooldownCommand : ConsoleCommand { public override string Name => "chaospoly_nocooldown"; public override string Help => "Toggle all the staves' cooldowns off/on for this session (testing)."; public override bool IsCheat => true; public override void Run(string[] args) { HenStaff.NoCooldown = !HenStaff.NoCooldown; Commands.Print(HenStaff.NoCooldown ? "Staff cooldowns OFF until restart." : "Staff cooldowns back ON."); } } internal sealed class CreatureInfo { public string Name; public int Tier; public string TierSource; public bool FormEligible; public string FormBlockReason; public string TrophyToken; public float Height; public GameObject Prefab; public Character Char; } internal static class CreatureCatalog { private static Dictionary<string, CreatureInfo> _byName; private static readonly Dictionary<string, int> VanillaTiers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { { "Boar", 1 }, { "Deer", 1 }, { "Neck", 1 }, { "Greyling", 1 }, { "Greydwarf", 2 }, { "Greydwarf_Elite", 2 }, { "Greydwarf_Shaman", 2 }, { "Troll", 2 }, { "Skeleton", 2 }, { "Skeleton_NoArcher", 2 }, { "Skeleton_Poison", 2 }, { "Ghost", 2 }, { "Bjorn", 2 }, { "Draugr", 3 }, { "Draugr_Elite", 3 }, { "Draugr_Ranged", 3 }, { "Blob", 3 }, { "BlobElite", 3 }, { "Leech", 3 }, { "Surtling", 3 }, { "Wraith", 3 }, { "Abomination", 3 }, { "Wolf", 4 }, { "Hatchling", 4 }, { "Fenring", 4 }, { "Fenring_Cultist", 4 }, { "StoneGolem", 4 }, { "Ulv", 4 }, { "Bat", 4 }, { "Goblin", 5 }, { "GoblinArcher", 5 }, { "GoblinBrute", 5 }, { "GoblinShaman", 5 }, { "Lox", 5 }, { "Deathsquito", 5 }, { "BlobTar", 5 }, { "Unbjorn", 5 }, { "Seeker", 6 }, { "SeekerBrute", 6 }, { "SeekerBrood", 6 }, { "Tick", 6 }, { "Gjall", 6 }, { "Hare", 6 }, { "Dverger", 6 }, { "DvergerMage", 6 }, { "DvergerMageFire", 6 }, { "DvergerMageIce", 6 }, { "DvergerMageSupport", 6 }, { "Charred_Melee", 7 }, { "Charred_Archer", 7 }, { "Charred_Twitcher", 7 }, { "Charred_Mage", 7 }, { "Morgen", 7 }, { "Asksvin", 7 }, { "Volture", 7 }, { "FallenValkyrie", 7 }, { "BlobLava", 7 }, { "DvergerAshlands", 7 }, { "JotunWarrior", 8 }, { "JotunWarriorDualWield", 8 }, { "JotunWitch", 8 }, { "Elaking", 8 }, { "ElakingMole", 8 }, { "ElakingLantern", 8 }, { "Frysling", 8 }, { "BlobFrost", 8 }, { "FrostWisp", 8 }, { "GoblinDeepNorth", 8 }, { "DvergerDeepNorth", 8 }, { "Barka", 8 }, { "Moose", 8 }, { "Seal", 8 }, { "ShadowPerson", 8 }, { "Skeleton_DeepNorth", 8 }, { "TrollFrost", 8 }, { "Greydwarf_Frozen", 8 }, { "Greydwarf_Shaman_Frozen", 8 } }; public static IEnumerable<CreatureInfo> All { get { if (!EnsureBuilt()) { return Enumerable.Empty<CreatureInfo>(); } return _byName.Values; } } public static void Invalidate() { _byName = null; } public static bool EnsureBuilt() { if (_byName != null) { return true; } if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } Build(); return true; } public static CreatureInfo Get(string prefab) { if (string.IsNullOrEmpty(prefab) || !EnsureBuilt()) { return null; } _byName.TryGetValue(prefab, out var value); return value; } public static int TierOf(string prefab) { return Get(prefab)?.Tier ?? Cfg.UnknownTier.Value; } private static void Build() { _byName = new Dictionary<string, CreatureInfo>(StringComparer.OrdinalIgnoreCase); Dictionary<string, int> spawnTiers = ScanSpawnTables(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { Character component = prefab.GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)prefab.GetComponent<Player>() != (Object)null)) { CreatureInfo creatureInfo = new CreatureInfo { Name = ((Object)prefab).name, Prefab = prefab, Char = component, Height = BodyHeight(prefab) }; ResolveTier(creatureInfo, component, spawnTiers); creatureInfo.FormEligible = Eligibility.IsFormEligible(prefab, component, out creatureInfo.FormBlockReason); creatureInfo.TrophyToken = FindTrophy(prefab); _byName[((Object)prefab).name] = creatureInfo; } } } if (!Cfg.Verbose.Value) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Creature catalog ({_byName.Count} creatures):"); foreach (CreatureInfo item in from x in _byName.Values orderby x.Tier, x.Name select x) { stringBuilder.AppendLine(string.Format(" T{0} {1,-32} tier from {2,-10} form={3}", item.Tier, item.Name, item.TierSource, item.FormEligible ? "yes" : ("no (" + item.FormBlockReason + ")"))); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } private static float BodyHeight(GameObject go) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) float y = go.transform.localScale.y; CapsuleCollider component = go.GetComponent<CapsuleCollider>(); if ((Object)(object)component != (Object)null) { return Mathf.Max(component.height, component.radius * 2f) * y; } Collider componentInChildren = go.GetComponentInChildren<Collider>(true); if (!((Object)(object)componentInChildren != (Object)null)) { return 1f; } Bounds bounds = componentInChildren.bounds; return ((Bounds)(ref bounds)).size.y * y; } public static string CreatureForTrophy(string trophyToken) { if (string.IsNullOrEmpty(trophyToken) || !EnsureBuilt()) { return null; } List<CreatureInfo> list = _byName.Values.Where((CreatureInfo i) => i.TrophyToken == trophyToken).ToList(); if (list.Count == 0) { return null; } return (list.FirstOrDefault((CreatureInfo i) => string.Equals(Family(i.Name), i.Name, StringComparison.OrdinalIgnoreCase)) ?? list[0]).Name; } private static void ResolveTier(CreatureInfo info, Character ch, Dictionary<string, int> spawnTiers) { if (Cfg.TryTierOverride(info.Name, out var tier)) { info.Tier = tier; info.TierSource = "config"; return; } if (VanillaTiers.TryGetValue(info.Name, out tier)) { info.Tier = tier; info.TierSource = "vanilla"; return; } if (spawnTiers.TryGetValue(info.Name, out tier)) { info.Tier = tier; info.TierSource = "spawns"; return; } float health = ch.m_health; if (health <= 0f) { info.Tier = Cfg.UnknownTier.Value; info.TierSource = "unknown"; } else { info.Tier = ((health <= 40f) ? 1 : ((health <= 150f) ? 2 : ((health <= 400f) ? 3 : ((health <= 800f) ? 4 : ((health <= 1500f) ? 5 : ((health <= 3000f) ? 6 : 7)))))); info.TierSource = "health"; } } private static Dictionary<string, int> ScanSpawnTables() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); try { SpawnSystemList[] array = Resources.FindObjectsOfTypeAll<SpawnSystemList>(); foreach (SpawnSystemList val in array) { if ((Object)(object)val == (Object)null || val.m_spawners == null) { continue; } foreach (SpawnData spawner in val.m_spawners) { if (spawner == null || (Object)(object)spawner.m_prefab == (Object)null) { continue; } int num = TierFromBiome(spawner.m_biome); if (num > 0) { string name = ((Object)spawner.m_prefab).name; if (!dictionary.TryGetValue(name, out var value) || num < value) { dictionary[name] = num; } } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Spawn table scan failed, falling back to health tiers: " + ex.Message)); } return dictionary; } private static int TierFromBiome(Biome b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_001c: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if ((b & 1) != 0) { return 1; } if ((b & 8) != 0) { return 2; } if ((b & 2) != 0) { return 3; } if ((b & 4) != 0) { return 4; } if ((b & 0x10) != 0) { return 5; } if ((b & 0x200) != 0) { return 6; } if ((b & 0x20) != 0) { return 7; } if ((b & 0x40) != 0) { return 8; } return 0; } private static string FindTrophy(GameObject go) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 CharacterDrop component = go.GetComponent<CharacterDrop>(); if ((Object)(object)component == (Object)null || component.m_drops == null) { return null; } foreach (Drop drop in component.m_drops) { ItemDrop val = (((Object)(object)drop?.m_prefab != (Object)null) ? drop.m_prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null && (int)val.m_itemData.m_shared.m_itemType == 13) { return val.m_itemData.m_shared.m_name; } } return null; } public static string Family(string prefab) { if (string.IsNullOrEmpty(prefab)) { return prefab; } IEnumerable<string> values = prefab.Split('_').Where((string part, int i) => i == 0 || !Cfg.VariantSuffixSet.Contains(part)); return string.Join("_", values); } public static string PickForm(IEnumerable<string> pool, string targetOriginal, string targetCurrent) { int num = TierOf(targetOriginal); string b = Family(targetOriginal); string b2 = Family(targetCurrent); Dictionary<string, List<CreatureInfo>> dictionary = new Dictionary<string, List<CreatureInfo>>(StringComparer.OrdinalIgnoreCase); foreach (string item in pool) { CreatureInfo creatureInfo = Get(item); if (creatureInfo == null || !creatureInfo.FormEligible) { continue; } string text = Family(creatureInfo.Name); if (!string.Equals(text, b, StringComparison.OrdinalIgnoreCase) && !string.Equals(text, b2, StringComparison.OrdinalIgnoreCase)) { if (!dictionary.TryGetValue(text, out var value)) { value = (dictionary[text] = new List<CreatureInfo>()); } value.Add(creatureInfo); } } List<KeyValuePair<string, float>> list2 = new List<KeyValuePair<string, float>>(); float num2 = 0f; foreach (KeyValuePair<string, List<CreatureInfo>> item2 in dictionary) { int num3 = item2.Value.Min((CreatureInfo i) => i.Tier); float num4 = Cfg.TierWeight(num3); if (num3 > num) { num4 *= Cfg.HigherTierMultiplier.Value; } if (!(num4 <= 0f)) { list2.Add(new KeyValuePair<string, float>(item2.Key, num4)); num2 += num4; } } if (list2.Count == 0) { return null; } string key = list2[list2.Count - 1].Key; float num5 = Random.Range(0f, num2); foreach (KeyValuePair<string, float> item3 in list2) { num5 -= item3.Value; if (num5 <= 0f) { key = item3.Key; break; } } return PickVariant(key, dictionary[key]); } private static string PickVariant(string family, List<CreatureInfo> members) { CreatureInfo creatureInfo = members.FirstOrDefault((CreatureInfo m) => string.Equals(m.Name, family, StringComparison.OrdinalIgnoreCase)); if (creatureInfo != null) { return creatureInfo.Name; } List<CreatureInfo> list = members.Where((CreatureInfo m) => m.Name.IndexOf("sleeping", StringComparison.OrdinalIgnoreCase) < 0 || m.Name.IndexOf("nonsleeping", StringComparison.OrdinalIgnoreCase) >= 0).ToList(); List<CreatureInfo> list2 = ((list.Count > 0) ? list : members); return list2[Random.Range(0, list2.Count)].Name; } } internal static class Eligibility { private static readonly FieldInfo StartsTamedField = AccessTools.Field(typeof(Character), "m_tamed"); public static bool IsValidTarget(Character c) { string reason; return IsValidTarget(c, out reason); } public static bool IsValidTarget(Character c, out string reason) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) reason = null; if ((Object)(object)c == (Object)null) { reason = "null"; return false; } if (c is Player) { reason = "player"; return false; } if (c.IsDead()) { reason = "dead"; return false; } if (c.IsTamed()) { reason = "tamed"; return false; } if (c.IsBoss()) { reason = "boss"; return false; } if ((int)c.m_faction == 0) { reason = "friendly/summon"; return false; } if ((Object)(object)((Component)c).GetComponent<CharacterTimedDestruction>() != (Object)null) { reason = "timed summon"; return false; } ZNetView val = Access.NView(c); if ((Object)(object)val == (Object)null || !val.IsValid()) { reason = "no network view"; return false; } string text = Polymorph.CurrentPrefabName(c); if (Cfg.IsExcludedTarget(Polymorph.GetOriginalPrefabName(c) ?? text) || Cfg.IsExcludedTarget(text)) { reason = "excluded in config"; return false; } if (Cfg.ExcludeWaterCreatures.Value && IsWaterOnly(((Component)c).gameObject)) { reason = "water creature"; return false; } return true; } public static bool IsEmberFormEligible(string prefab, out string reason) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) CreatureInfo creatureInfo = CreatureCatalog.Get(prefab); if (creatureInfo == null) { reason = "unknown creature"; return false; } GameObject prefab2 = creatureInfo.Prefab; Character val = creatureInfo.Char; if (val.m_boss) { reason = "boss"; return false; } if ((int)val.m_faction == 0) { reason = "summon"; return false; } if ((Object)(object)prefab2.GetComponent<BaseAI>() == (Object)null) { reason = "no AI"; return false; } if ((Object)(object)prefab2.GetComponent<Growup>() != (Object)null) { reason = "baby"; return false; } if ((Object)(object)prefab2.GetComponent<CharacterTimedDestruction>() != (Object)null) { reason = "summon"; return false; } if (val.m_flying) { reason = "flyer"; return false; } if (IsWaterOnly(prefab2)) { reason = "water creature"; return false; } if ((Object)(object)prefab2.GetComponentInChildren<Animator>(true) == (Object)null) { reason = "no visual"; return false; } if (creatureInfo.Height > Cfg.HenMaxFormHeight.Value) { reason = $"too big ({creatureInfo.Height:0.#}m)"; return false; } if (Cfg.IsEmberExcluded(creatureInfo.Name)) { reason = "excluded in config"; return false; } reason = null; return true; } public static bool IsMaskFormEligible(string prefab, out string reason) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) reason = null; if (prefab == "Player") { return true; } CreatureInfo creatureInfo = CreatureCatalog.Get(prefab); if (creatureInfo == null) { reason = "unknown creature"; return false; } GameObject prefab2 = creatureInfo.Prefab; Character val = creatureInfo.Char; if (val.m_boss && !Cfg.MaskAllowBosses.Value) { reason = "boss"; return false; } if ((int)val.m_faction == 0) { reason = "summon"; return false; } if ((Object)(object)prefab2.GetComponent<Growup>() != (Object)null) { reason = "baby"; return false; } if ((Object)(object)prefab2.GetComponent<CharacterTimedDestruction>() != (Object)null) { reason = "summon"; return false; } if (val.m_flying && Cfg.MaskExcludeFlyers.Value) { reason = "flyer"; return false; } if (IsWaterOnly(prefab2)) { reason = "water creature"; return false; } if ((Object)(object)prefab2.GetComponentInChildren<Animator>(true) == (Object)null) { reason = "no visual"; return false; } if (Cfg.IsMaskExcluded(creatureInfo.Name)) { reason = "excluded in config"; return false; } return true; } public static bool IsFormEligible(GameObject go, Character ch, out string reason) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) reason = null; if (ch.m_boss) { reason = "boss"; return false; } if ((int)ch.m_faction == 0) { reason = "friendly"; return false; } if ((Object)(object)go.GetComponent<BaseAI>() == (Object)null) { reason = "no AI"; return false; } if ((Object)(object)go.GetComponent<Growup>() != (Object)null) { reason = "baby"; return false; } Tameable component = go.GetComponent<Tameable>(); if (!((Object)(object)component != (Object)null) || !component.m_startsTamed) { bool flag = default(bool); int num; if (StartsTamedField != null) { object value = StartsTamedField.GetValue(ch); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) == 0) { if ((Object)(object)go.GetComponent<CharacterTimedDestruction>() != (Object)null) { reason = "timed summon"; return false; } if (Cfg.ExcludeFlyingForms.Value && ch.m_flying) { reason = "flying"; return false; } if (Cfg.ExcludeWaterCreatures.Value && IsWaterOnly(go)) { reason = "water"; return false; } if (Cfg.IsExcludedForm(((Object)go).name)) { reason = "config"; return false; } return true; } } reason = "starts tame"; return false; } public static bool IsWaterOnly(GameObject go) { MonsterAI component = go.GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null) { return component.m_avoidLand; } return false; } } internal sealed class GltfModel { public sealed class Part { public List<Vector3> Positions = new List<Vector3>(); public List<Vector3> Normals = new List<Vector3>(); public List<Vector2> Uvs = new List<Vector2>(); public List<int> Indices = new List<int>(); public int Material; } public sealed class MaterialInfo { public string Name; public Color BaseColor = Color.white; public int BaseTex = -1; public int NormalTex = -1; public int EmissiveTex = -1; public Color Emissive = Color.black; public float EmissiveStrength = 1f; public bool DoubleSided; } public readonly List<Part> Parts = new List<Part>(); public readonly List<MaterialInfo> Materials = new List<MaterialInfo>(); private readonly List<byte[]> _images = new List<byte[]>(); private readonly List<int> _textureSource = new List<int>(); private Dictionary<string, object> _json; private byte[] _bin; public static GltfModel Load(string path) { GltfModel gltfModel = new GltfModel(); gltfModel.Read(File.ReadAllBytes(path)); return gltfModel; } private void Read(byte[] d) { //IL_0241: Unknown result type (might be due to invalid IL or missing references) if (d.Length < 20 || BitConverter.ToUInt32(d, 0) != 1179937895) { throw new InvalidDataException("not a .glb file"); } int num; for (int i = 12; i + 8 <= d.Length; i += 8 + num) { num = BitConverter.ToInt32(d, i); switch (BitConverter.ToUInt32(d, i + 4)) { case 1313821514u: _json = (Dictionary<string, object>)MiniJson.Parse(Encoding.UTF8.GetString(d, i + 8, num)); break; case 5130562u: _bin = new byte[num]; Buffer.BlockCopy(d, i + 8, _bin, 0, num); break; } } if (_json == null || _bin == null) { throw new InvalidDataException("missing JSON or BIN chunk"); } foreach (Dictionary<string, object> item in List("images")) { _images.Add(item.ContainsKey("bufferView") ? View(Int(item["bufferView"])) : null); } foreach (object item2 in List("textures")) { _textureSource.Add(((Dictionary<string, object>)item2).TryGetValue("source", out var value) ? Int(value) : (-1)); } foreach (object item3 in List("materials")) { Materials.Add(ReadMaterial((Dictionary<string, object>)item3)); } List<object> list = List("scenes"); object value2; int index = (_json.TryGetValue("scene", out value2) ? Int(value2) : 0); foreach (object item4 in (list.Count > 0) ? ((List<object>)((Dictionary<string, object>)list[index])["nodes"]) : new List<object>()) { Walk(Int(item4), Matrix4x4.identity); } } private MaterialInfo ReadMaterial(Dictionary<string, object> m) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00d5: Unknown result type (might be due to invalid IL or missing references) object value; MaterialInfo materialInfo = new MaterialInfo { Name = (m.TryGetValue("name", out value) ? (value as string) : "") }; if (m.TryGetValue("pbrMetallicRoughness", out var value2) && value2 is Dictionary<string, object> dictionary) { if (dictionary.TryGetValue("baseColorFactor", out var value3)) { materialInfo.BaseColor = ToColor((List<object>)value3); } if (dictionary.TryGetValue("baseColorTexture", out var value4)) { materialInfo.BaseTex = TexIndex(value4); } } if (m.TryGetValue("normalTexture", out var value5)) { materialInfo.NormalTex = TexIndex(value5); } if (m.TryGetValue("emissiveTexture", out var value6)) { materialInfo.EmissiveTex = TexIndex(value6); } if (m.TryGetValue("emissiveFactor", out var value7)) { materialInfo.Emissive = ToColor((List<object>)value7); } if (m.TryGetValue("doubleSided", out var value8)) { bool flag = default(bool); int num; if (value8 is bool) { flag = (bool)value8; num = 1; } else { num = 0; } materialInfo.DoubleSided = (byte)((uint)num & (flag ? 1u : 0u)) != 0; } if (m.TryGetValue("extensions", out var value9) && value9 is Dictionary<string, object> dictionary2 && dictionary2.TryGetValue("KHR_materials_emissive_strength", out var value10) && value10 is Dictionary<string, object> dictionary3 && dictionary3.TryGetValue("emissiveStrength", out var value11)) { materialInfo.EmissiveStrength = (float)(double)value11; } return materialInfo; } private int TexIndex(object texInfo) { int num = Int(((Dictionary<string, object>)texInfo)["index"]); if (num < 0 || num >= _textureSource.Count) { return -1; } return _textureSource[num]; } public byte[] Image(int index) { if (index < 0 || index >= _images.Count) { return null; } return _images[index]; } private void Walk(int nodeIdx, Matrix4x4 parent) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> dictionary = (Dictionary<string, object>)List("nodes")[nodeIdx]; Matrix4x4 val = parent * LocalMatrix(dictionary); if (dictionary.TryGetValue("mesh", out var value)) { foreach (object item in (List<object>)((Dictionary<string, object>)List("meshes")[Int(value)])["primitives"]) { ReadPrimitive((Dictionary<string, object>)item, val); } } if (!dictionary.TryGetValue("children", out var value2)) { return; } foreach (object item2 in (List<object>)value2) { Walk(Int(item2), val); } } private static Matrix4x4 LocalMatrix(Dictionary<string, object> n) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if (n.TryGetValue("matrix", out var value)) { float[] array = ((List<object>)value).Select((object x) => (float)(double)x).ToArray(); Matrix4x4 result = default(Matrix4x4); for (int num = 0; num < 4; num++) { for (int num2 = 0; num2 < 4; num2++) { ((Matrix4x4)(ref result))[num2, num] = array[num * 4 + num2]; } } return result; } object value2; Vector3 val = (n.TryGetValue("translation", out value2) ? ToV3((List<object>)value2) : Vector3.zero); Quaternion identity = Quaternion.identity; if (n.TryGetValue("rotation", out var value3)) { float[] array2 = ((List<object>)value3).Select((object x) => (float)(double)x).ToArray(); ((Quaternion)(ref identity))..ctor(array2[0], array2[1], array2[2], array2[3]); } object value4; Vector3 val2 = (n.TryGetValue("scale", out value4) ? ToV3((List<object>)value4) : Vector3.one); return Matrix4x4.TRS(val, identity, val2); } private void ReadPrimitive(Dictionary<string, object> p, Matrix4x4 world) { //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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) if (p.TryGetValue("mode", out var value) && Int(value) != 4) { return; } Dictionary<string, object> dictionary = (Dictionary<string, object>)p["attributes"]; if (!dictionary.ContainsKey("POSITION")) { return; } int comps; float[] array = Floats(Int(dictionary["POSITION"]), out comps); int comps2; float[] array2 = (dictionary.ContainsKey("NORMAL") ? Floats(Int(dictionary["NORMAL"]), out comps2) : null); float[] array3 = (dictionary.ContainsKey("TEXCOORD_0") ? Floats(Int(dictionary["TEXCOORD_0"]), out comps2) : null); int num = array.Length / comps; Matrix4x4 inverse = ((Matrix4x4)(ref world)).inverse; Matrix4x4 transpose = ((Matrix4x4)(ref inverse)).transpose; object value2; Part part = new Part { Material = (p.TryGetValue("material", out value2) ? Int(value2) : (-1)) }; for (int i = 0; i < num; i++) { Vector3 val = ((Matrix4x4)(ref world)).MultiplyPoint3x4(new Vector3(array[i * 3], array[i * 3 + 1], array[i * 3 + 2])); part.Positions.Add(new Vector3(0f - val.x, val.y, val.z)); if (array2 != null) { Vector3 val2 = ((Matrix4x4)(ref transpose)).MultiplyVector(new Vector3(array2[i * 3], array2[i * 3 + 1], array2[i * 3 + 2])); Vector3 normalized = ((Vector3)(ref val2)).normalized; part.Normals.Add(new Vector3(0f - normalized.x, normalized.y, normalized.z)); } part.Uvs.Add((Vector2)((array3 != null) ? new Vector2(array3[i * 2], 1f - array3[i * 2 + 1]) : Vector2.zero)); } object value3; int[] array4 = (p.TryGetValue("indices", out value3) ? Ints(Int(value3)) : Enumerable.Range(0, num).ToArray()); for (int j = 0; j + 2 < array4.Length; j += 3) { part.Indices.Add(array4[j]); part.Indices.Add(array4[j + 2]); part.Indices.Add(array4[j + 1]); } Parts.Add(part); } private byte[] View(int viewIdx) { Dictionary<string, object> obj = (Dictionary<string, object>)List("bufferViews")[viewIdx]; object value; int srcOffset = (obj.TryGetValue("byteOffset", out value) ? Int(value) : 0); int num = Int(obj["byteLength"]); byte[] array = new byte[num]; Buffer.BlockCopy(_bin, srcOffset, array, 0, num); return array; } private void AccessorLayout(int accIdx, out int start, out int count, out int comps, out int compType, out int stride) { Dictionary<string, object> dictionary = (Dictionary<string, object>)List("accessors")[accIdx]; Dictionary<string, object> dictionary2 = (Dictionary<string, object>)List("bufferViews")[Int(dictionary["bufferView"])]; start = (dictionary2.TryGetValue("byteOffset", out var value) ? Int(value) : 0) + (dictionary.TryGetValue("byteOffset", out var value2) ? Int(value2) : 0); count = Int(dictionary["count"]); comps = (string)dictionary["type"] switch { "SCALAR" => 1, "VEC2" => 2, "VEC3" => 3, "VEC4" => 4, _ => 1, }; compType = Int(dictionary["componentType"]); int num = ((compType == 5126 || compType == 5125) ? 4 : ((compType != 5123 && compType != 5122) ? 1 : 2)); stride = (dictionary2.TryGetValue("byteStride", out var value3) ? Int(value3) : (num * comps)); } private float[] Floats(int accIdx, out int comps) { AccessorLayout(accIdx, out var start, out var count, out comps, out var compType, out var stride); if (compType != 5126) { throw new InvalidDataException("only float vertex attributes are supported"); } float[] array = new float[count * comps]; for (int i = 0; i < count; i++) { for (int j = 0; j < comps; j++) { array[i * comps + j] = BitConverter.ToSingle(_bin, start + i * stride + j * 4); } } return array; } private int[] Ints(int accIdx) { AccessorLayout(accIdx, out var start, out var count, out var _, out var compType, out var stride); int[] array = new int[count]; for (int i = 0; i < count; i++) { int num = start + i * stride; array[i] = compType switch { 5123 => BitConverter.ToUInt16(_bin, num), 5125 => (int)BitConverter.ToUInt32(_bin, num), _ => _bin[num], }; } return array; } private List<object> List(string key) { if (!_json.TryGetValue(key, out var value)) { return new List<object>(); } return (List<object>)value; } private static int Int(object o) { return Convert.ToInt32(o); } private static Vector3 ToV3(List<object> l) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) return new Vector3((float)(double)l[0], (float)(double)l[1], (float)(double)l[2]); } private static Color ToColor(List<object> l) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) return new Color((float)(double)l[0], (float)(double)l[1], (float)(double)l[2], (l.Count > 3) ? ((float)(double)l[3]) : 1f); } } internal static class HenStaff { public const string Prefab = "StaffEmberHen"; public const string Token = "$item_staffemberhen"; public const string RPC_HenNova = "ChaosPolymorph_HenNova"; public const string RPC_EmberFx = "ChaosPolymorph_EmberFx"; public const string RPC_FormPuff = "ChaosPolymorph_FormPuff"; public const string ItemFormKey = "ChaosPolymorph_EmberForm"; public static readonly int PlayerFormKey = StringExtensionMethods.GetStableHashCode("ChaosPolymorph_EmberForm"); private static float _lastCast = -9999f; public static bool NoCooldown; public static bool IsStaff(ItemData item) { if (item != null && item.m_shared != null) { return item.m_shared.m_name == "$item_staffemberhen"; } return false; } public static string FormOf(ItemData item) { if (item?.m_customData != null && item.m_customData.TryGetValue("ChaosPolymorph_EmberForm", out var value) && !string.IsNullOrEmpty(value)) { return value; } return Cfg.HenDefaultForm.Value; } public static void Register() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00e4: 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) if (!Cfg.HenEnabled.Value) { return; } string value = Cfg.HenBaseStaff.Value; GameObject prefab = PrefabManager.Instance.GetPrefab(value); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<ItemDrop>() == (Object)null) { Plugin.Log.LogWarning((object)("Hen staff: base staff '" + value + "' not found; Hen staff not registered.")); return; } ItemConfig val = new ItemConfig { Name = "$item_staffemberhen", Description = "$item_staffemberhen_description", CraftingStation = Cfg.HenCraftingStation.Value, MinStationLevel = Cfg.HenStationLevel.Value, Requirements = Cfg.ParseRequirements(Cfg.HenRecipe.Value) }; CustomItem val2 = new CustomItem("StaffEmberHen", value, val); SharedData shared = val2.ItemDrop.m_itemData.m_shared; shared.m_maxQuality = Mathf.Max(1, Cfg.HenMaxQuality.Value); shared.m_damages = default(DamageTypes); shared.m_damagesPerLevel = default(DamageTypes); MakeQuietCast(shared, Cfg.HenCastFrom.Value, value, "Hen staff"); try { HenModel.Apply(val2.ItemPrefab, shared, StaffStyle.Ember); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Ember topper failed, using the plain base staff look: {arg}"); } ItemManager.Instance.AddItem(val2); Plugin.Log.LogInfo((object)("Registered StaffEmberHen (cloned from " + value + ").")); } public static void MakeQuietCast(SharedData shared, string castFromName, string baseName, string label) { GameObject prefab = PrefabManager.Instance.GetPrefab(castFromName); Attack val = ((!((Object)(object)prefab != (Object)null)) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_attack); if (val != null) { shared.m_attack = val.Clone(); Plugin.Log.LogInfo((object)(label + " uses " + ((Object)prefab).name + "'s cast animation '" + shared.m_attack.m_attackAnimation + "'.")); } else { Plugin.Log.LogWarning((object)(label + ": cast source '" + castFromName + "' not found; keeping " + baseName + "'s cast.")); } Attack attack = shared.m_attack; attack.m_spawnOnTrigger = null; attack.m_attackProjectile = null; attack.m_spawnOnHit = null; attack.m_projectiles = 1; shared.m_consumeStatusEffect = null; SetEnum(attack, "m_attackType", "None"); Set(shared, "m_attackStatusEffect", null); if (shared.m_secondaryAttack != null) { shared.m_secondaryAttack.m_spawnOnTrigger = null; shared.m_secondaryAttack.m_attackProjectile = null; SetEnum(shared.m_secondaryAttack, "m_attackType", "None"); } } public static float Radius(int quality) { int num = Math.Max(1, Math.Min(quality, 100)); float num2 = Cfg.HenBaseRadius.Value; for (int i = 1; i < num; i++) { num2 += Math.Max(Cfg.HenMinRadiusPerLevel.Value, Cfg.HenRadiusPerLevel.Value * (float)Math.Pow(Cfg.HenRadiusFalloff.Value, i - 1)); } return num2; } public static float EitrCost(Player p) { if (Cfg.HenEitrMode.Value == EitrCostMode.Flat) { return Mathf.Max(0f, Cfg.HenEitrFlat.Value); } return Mathf.Max(Cfg.HenEitrMinimum.Value, ((Character)p).GetMaxEitr() * Cfg.HenEitrPercent.Value); } public static bool BeforeAttack(Player p, ItemData weapon) { float num = (NoCooldown ? 0f : Cfg.HenCooldown.Value); float num2 = num - (Time.time - _lastCast); if (num > 0f && num2 > 0f) { if (Cfg.ShowMessages.Value) { ((Character)p).Message((MessageType)1, $"The staff is still smouldering ({num2:0}s)", 0, (Sprite)null, false); } return false; } weapon.m_shared.m_attack.m_attackEitr = EitrCost(p); return true; } public static void AfterAttackStarted() { _lastCast = Time.time; } public static void Nova(Player caster, ItemData weapon) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: 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) if (!CreatureCatalog.EnsureBuilt()) { return; } string text = FormOf(weapon); if (!Eligibility.IsEmberFormEligible(text, out var reason)) { Caster.Debug("slotted form " + text + " is not allowed (" + reason + "); using " + Cfg.HenDefaultForm.Value); text = Cfg.HenDefaultForm.Value; } float num = Radius(weapon?.m_quality ?? 1); float num2 = Mathf.Max(0.5f, Cfg.HenSeconds.Value); List<Character> list = Reach.InRange(((Component)caster).transform.position, num); int num3 = 0; foreach (Character item in list) { string reason2 = "caster"; if ((Object)(object)item == (Object)(object)caster || !Eligibility.IsValidTarget(item, out reason2)) { if ((Object)(object)item != (Object)null && !(item is Player)) { Caster.Debug(" ember nova skip " + Polymorph.CurrentPrefabName(item) + ": " + reason2); } } else { Access.NView(item).InvokeRPC("ChaosPolymorph_HenNova", new object[3] { ((Character)caster).GetZDOID(), num2, text }); num3++; } } Caster.Debug($"Ember nova ({text}) r={num:0.#}m dur={num2}s caught {num3}"); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ChaosPolymorph_EmberFx", new object[3] { text, ((Component)caster).transform.position, num }); if (Cfg.ShowMessages.Value && num3 > 0) { ((Character)caster).Message((MessageType)1, (num3 == 1) ? "1 creature emberized" : $"{num3} creatures emberized", 0, (Sprite)null, false); } } public static void HandleEmberFx(long sender, string form, Vector3 pos, float radius) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNetScene.instance == (Object)null)) { Caster.Debug(string.Format("ember cast fx received ({0}, r={1:0.#}, effects={2})", form, radius, Cfg.HenCastEffect.Value ? "on" : "off")); if (Cfg.HenCastEffect.Value) { EmberFx.Burst(pos, radius, ring: true); GameObject prefab = ZNetScene.instance.GetPrefab(Cfg.HenCastEffectFrom.Value); GameObject val = ((!((Object)(object)prefab != (Object)null)) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_attack.m_attackProjectile); Fx.Play((((Object)(object)val != (Object)null) ? val.GetComponent<Projectile>() : null)?.m_hitEffects, pos, Quaternion.identity, Mathf.Max(0.5f, radius / 3f) * Cfg.HenCastEffectScale.Value); } if (Cfg.HenPlaySound.Value) { Fx.CreatureSound(form, pos, sender == ZDOMan.GetSessionID()); } } } public static void HandleFormPuff(long sender, string form, Vector3 pos) { //IL_001a: 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) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_006c: 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_0076: Unknown result type (might be due to invalid IL or missing references) if (Cfg.HenCastEffect.Value && !((Object)(object)ZNetScene.instance == (Object)null)) { EmberFx.Burst(pos + Vector3.up * 0.5f, 1.2f, ring: false); GameObject prefab = ZNetScene.instance.GetPrefab(form); Character val = ((prefab != null) ? prefab.GetComponent<Character>() : null); if ((Object)(object)val != (Object)null) { Fx.Play(val.m_hitEffects, pos + Vector3.up * 0.5f, Quaternion.identity, 1f); } } } public static string FormFromItem(ItemData dragged) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Invalid comparison between Unknown and I4 if (dragged?.m_shared == null) { return null; } string item = (((Object)(object)dragged.m_dropPrefab != (Object)null) ? ((Object)dragged.m_dropPrefab).name : ""); if (Cfg.ToSet(Cfg.HenEggItems.Value).Contains(item)) { return Cfg.HenDefaultForm.Value; } if ((int)dragged.m_shared.m_itemType != 13) { return null; } return CreatureCatalog.CreatureForTrophy(dragged.m_shared.m_name); } public static bool TrySlot(Player p, ItemData staff, ItemData dragged, Inventory fromInventory) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00e6: Unknown result type (might be due to invalid IL or missing references) string text = FormFromItem(dragged); if (text == null) { return false; } if (!Eligibility.IsEmberFormEligible(text, out var reason)) { ((Character)p).Message((MessageType)2, "The staff can't hold that creature (" + reason + ").", 0, (Sprite)null, false); return true; } if (text == FormOf(staff)) { ((Character)p).Message((MessageType)2, "The staff already holds that creature.", 0, (Sprite)null, false); return true; } if (fromInventory != null) { fromInventory.RemoveItem(dragged, 1); } staff.m_customData["ChaosPolymorph_EmberForm"] = text; if (((Humanoid)p).GetCurrentWeapon() == staff) { PublishEquippedForm(p, staff); } ((Character)p).Message((MessageType)2, "The staff now holds an ember " + Pretty(text) + ".", 0, (Sprite)null, false); if (Cfg.HenCastEffect.Value) { EmberFx.Burst(((Component)p).transform.position + Vector3.up * 1.2f, 0.8f, ring: false); } if (Cfg.HenPlaySound.Value) { Fx.CreatureSound(text, ((Component)p).transform.position, isCaster: true); } Caster.Debug("slotted " + text + " into the Ember staff"); return true; } public static void PublishEquippedForm(Player p, ItemData staff) { ZNetView val = Access.NView((Character)(object)p); if ((Object)(object)val != (Object)null && val.IsValid() && val.IsOwner()) { val.GetZDO().Set(PlayerFormKey, FormOf(staff)); } } public static string Pretty(string prefab) { if (prefab == "Player") { return "Viking"; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefab) : null); Character val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Character>() : null); if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(val2.m_name) && Localization.instance != null) { return Localization.instance.Localize(val2.m_name); } return prefab; } private static void Set(object o, string field, object value) { AccessTools.Field(o.GetType(), field)?.SetValue(o, value); } private static void SetEnum(object o, string field, string name) { FieldInfo fieldInfo = AccessTools.Field(o.GetType(), field); if (!(fieldInfo == null) && fieldInfo.FieldType.IsEnum && Enum.GetNames(fieldInfo.FieldType).Contains(name)) { fieldInfo.SetValue(o, Enum.Parse(fieldInfo.FieldType, name)); } } } internal static class HenModel { public static Material EmberTemplate; private static GameObject _iconRoot; private static GameObject _inactiveHolder; public static Material Tint(Material src, StaffStyle style) { if ((Object)(object)src == (Object)null) { return null; } if (!style.Cache.TryGetValue(src, out var value) || (Object)(object)value == (Object)null) { value = (style.Cache[src] = MakeTinted(src, style)); } return value; } public static void Apply(GameObject itemPrefab, SharedData shared, StaffStyle style, Action<Sprite> onIcon = null) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0293: 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_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Unknown result type (might be due to invalid IL or missing references) //IL_05c6: Unknown result type (might be due to invalid IL or missing references) //IL_05c7: Unknown result type (might be due to invalid IL or missing references) //IL_05d1: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Expected O, but got Unknown //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04f6: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) if ((int)SystemInfo.graphicsDeviceType == 4) { return; } StringBuilder stringBuilder = new StringBuilder(style.Label + " staff model:\n"); EmberFx.FindMaterial(itemPrefab); GameObject prefab = PrefabManager.Instance.GetPrefab("Hen"); EmberTemplate = (((Object)(object)prefab != (Object)null) ? (from r in prefab.GetComponentsInChildren<Renderer>(true) select r.sharedMaterial).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null && m.HasProperty("_EmissionColor") && m.HasProperty("_Color"))) : null); if (Cfg.HenHideOriginalEffects.Value) { ParticleSystemRenderer[] componentsInChildren = itemPrefab.GetComponentsInChildren<ParticleSystemRenderer>(true); for (int num = 0; num < componentsInChildren.Length; num++) { ((Renderer)componentsInChildren[num]).enabled = false; } Light[] componentsInChildren2 = itemPrefab.GetComponentsInChildren<Light>(true); for (int num = 0; num < componentsInChildren2.Length; num++) { ((Behaviour)componentsInChildren2[num]).enabled = false; } } List<MeshFilter> list = (from f in itemPrefab.GetComponentsInChildren<MeshFilter>(true) where (Object)(object)f.sharedMesh != (Object)null && (Object)(object)((Component)f).GetComponent<MeshRenderer>() != (Object)null select f).ToList(); if (list.Count == 0) { Plugin.Log.LogWarning((object)(style.Label + " staff base has no mesh renderers.")); return; } float num2 = list.Max(delegate(MeshFilter f) { //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) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = f.sharedMesh.bounds; return MaxC(((Bounds)(ref bounds2)).size); }); Dictionary<Mesh, Mesh> dictionary = new Dictionary<Mesh, Mesh>(); EmberTopper emberTopper = null; MeshFilter shaft = null; Vector3 headDir = Vector3.up; int axis = 1; bool headPos = true; float top = 0f; float foot = 0f; foreach (MeshFilter item in list) { Mesh sharedMesh = item.sharedMesh; Bounds bounds = sharedMesh.bounds; MeshRenderer component = ((Component)item).GetComponent<MeshRenderer>(); stringBuilder.AppendLine($" base part '{PathOf(((Component)item).transform, itemPrefab.transform)}' mesh={((Object)sharedMesh).name} size={((Bounds)(ref bounds)).size} readable={sharedMesh.isReadable}"); if (MaxC(((Bounds)(ref bounds)).size) < num2 * 0.6f) { if (Cfg.HenTrimHead.Value) { ((Renderer)component).enabled = false; } continue; } int num3 = ((!(((Bounds)(ref bounds)).size.x >= ((Bounds)(ref bounds)).size.y) || !(((Bounds)(ref bounds)).size.x >= ((Bounds)(ref bounds)).size.z)) ? ((((Bounds)(ref bounds)).size.y >= ((Bounds)(ref bounds)).size.z) ? 1 : 2) : 0); Vector3 val = (Vector3)(num3 switch { 1 => Vector3.up, 0 => Vector3.right, _ => Vector3.forward, }); Vector3 val2 = ((Bounds)(ref bounds)).max; float num4 = Mathf.Abs(((Vector3)(ref val2))[num3]); val2 = ((Bounds)(ref bounds)).min; bool flag = num4 >= Mathf.Abs(((Vector3)(ref val2))[num3]); Vector3 val3 = (flag ? val : (-val)); float num5; if (!flag) { val2 = ((Bounds)(ref bounds)).min; num5 = ((Vector3)(ref val2))[num3]; } else { val2 = ((Bounds)(ref bounds)).max; num5 = ((Vector3)(ref val2))[num3]; } float num6 = num5; float num7; if (!flag) { val2 = ((Bounds)(ref bounds)).max; num7 = ((Vector3)(ref val2))[num3]; } else { val2 = ((Bounds)(ref bounds)).min; num7 = ((Vector3)(ref val2))[num3]; } float num8 = num7; val2 = ((Bounds)(ref bounds)).size; float num9 = ((Vector3)(ref val2))[num3]; float num10 = num6; if (Cfg.HenTrimHead.Value && Cfg.HenTrimFraction.Value > 0f) { float num11 = num6 - (num6 - num8) * Cfg.HenTrimFraction.Value; if (!dictionary.TryGetValue(sharedMesh, out var value)) { string how; Mesh val4 = MeshReadback.ReadableCopy(sharedMesh, out how); stringBuilder.AppendLine(" mesh data: " + how); value = (dictionary[sharedMesh] = (((Object)(object)val4 != (Object)null) ? TrimMesh(val4, num3, num11, flag) : null)); } if ((Object)(object)value != (Object)null) { item.sharedMesh = value; stringBuilder.AppendLine($" trimmed the head ({Cfg.HenTrimFraction.Value:P0})"); } else { item.sharedMesh = PlainShaft(num3, num8, num11, num9 * Cfg.HenShaftThickness.Value); ((Renderer)component).sharedMaterials = (Material[])(object)new Material[1] { WoodMaterial(((Renderer)component).sharedMaterial) }; stringBuilder.AppendLine(" using a plain wooden shaft instead"); } num10 = num11; } Vector3 localPosition = val * num10 + val3 * Cfg.HenHeightOffset.Value * num9; GameObject val6 = new GameObject("EmberTopper"); val6.transform.SetParent(((Component)item).transform, false); val6.transform.localPosition = localPosition; val6.transform.localRotation = Quaternion.AngleAxis(Cfg.HenTwist.Value, val3) * Quaternion.FromToRotation(Vector3.up, val3); EmberTopper emberTopper2 = val6.AddComponent<EmberTopper>(); emberTopper2.StyleId = style.Id; emberTopper2.TargetSize = num9 * style.Size(); emberTopper2.Build(style.DefaultForm()); if ((Object)(object)emberTopper == (Object)null) { emberTopper = emberTopper2; headDir = val3; shaft = item; axis = num3; headPos = flag; top = num10; foot = num8; } } if (Cfg.HenRenderIcon.Value && (Object)(object)emberTopper != (Object)null) { GameObject val7 = BuildIconModel(emberTopper, shaft, headDir, axis, headPos, top, foot, stringBuilder); RenderManager.Instance.EnqueueRender(new RenderRequest(val7) { Rotation = Quaternion.identity, UseCache = false }, (Action<Sprite>)delegate(Sprite sprite) { if ((Object)(object)sprite != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { sprite }; onIcon?.Invoke(sprite); } }); } if (Cfg.Verbose.Value) { Plugin.Log.LogInfo((object)stringBuilder.ToString()); } } private static GameObject BuildIconModel(EmberTopper topper, MeshFilter shaft, Vector3 headDir, int axis, bool headPos, float top, float foot, StringBuilder log) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_01a4: Unknown result type (might be due