Decompiled source of Swamp Revival After Bonemass v1.0.3

BepInEx/plugins/PrimeForestSpirit/PrimeForestSpirit.dll

Decompiled 4 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeForestSpirit")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.2.0")]
[assembly: AssemblyInformationalVersion("0.4.2")]
[assembly: AssemblyProduct("PrimeForestSpirit")]
[assembly: AssemblyTitle("PrimeForestSpirit")]
[assembly: AssemblyVersion("0.4.2.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 BiomeRevival.PrimeForestSpirit
{
	[BepInPlugin("com.prime.forestspirit", "Prime Forest Spirit", "0.4.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class PrimeForestSpiritPlugin : BaseUnityPlugin
	{
		public const string PluginId = "com.prime.forestspirit";

		public const string PrefabName = "PrimeForestSpirit";

		internal static PrimeForestSpiritPlugin Instance;

		internal static SpiritSettings Settings;

		public static Func<bool> RestorationGate;

		private SpiritVisuals visuals;

		private void Awake()
		{
			Instance = this;
			Settings = new SpiritSettings(((BaseUnityPlugin)this).Config);
			PrefabManager.OnVanillaPrefabsAvailable += Register;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Prime Forest Spirit 0.4.2: original visuals/movement/lifetime; nighttime restored visibility, sleeping offscreen/daytime visuals and lights.");
		}

		private void Register()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			GameObject val = null;
			try
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab("LuredWisp");
				if (!Object.op_Implicit((Object)(object)prefab))
				{
					throw new InvalidOperationException("Installed LuredWisp prefab was not available.");
				}
				if (Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab("PrimeForestSpirit")))
				{
					throw new InvalidOperationException("Prefab name already registered: PrimeForestSpirit");
				}
				val = PrefabManager.Instance.CreateEmptyPrefab("PrimeForestSpirit", false);
				if (!Object.op_Implicit((Object)(object)val) || val.activeInHierarchy)
				{
					throw new InvalidOperationException("Expected an inactive Jotunn prefab container; refusing unsafe construction.");
				}
				val.SetActive(false);
				Component[] components = val.GetComponents<Component>();
				foreach (Component val2 in components)
				{
					if (!(val2 is Transform))
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
				}
				val.layer = LayerMask.NameToLayer("Default");
				val.tag = "spawned";
				visuals = new SpiritVisuals(Settings, ((BaseUnityPlugin)this).Logger);
				visuals.Build(prefab, val);
				ZNetView obj = val.AddComponent<ZNetView>();
				obj.m_persistent = true;
				obj.m_distant = false;
				obj.m_type = (ObjectType)0;
				obj.m_syncInitialScale = false;
				ZSyncTransform obj2 = val.AddComponent<ZSyncTransform>();
				obj2.m_syncPosition = true;
				obj2.m_syncRotation = false;
				obj2.m_syncScale = false;
				obj2.m_syncBodyVelocity = false;
				obj2.m_characterParentSync = false;
				val.AddComponent<SpiritWander>();
				val.AddComponent<FireflyPulse>();
				val.AddComponent<FireflyVisibility>();
				val.AddComponent<SpiritLifetime>();
				SpiritVisuals.Validate(val);
				val.SetActive(true);
				PrefabManager.Instance.AddPrefab(val);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("REGISTERED PrimeForestSpirit: luminous point/halo at " + Settings.Scale + " scale, light=" + Settings.LightIntensity + "/" + Settings.LightRange + ", materials=" + visuals.MaterialCount + ", owner-controlled wandering. No interaction/combat/mist components."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("PrimeForestSpirit registration failed; no spawning enabled: " + ex));
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		internal void Diagnostic(string message)
		{
			if (Settings.Diagnostics)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
			}
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	internal sealed class SpiritSettings
	{
		internal readonly float Scale;

		internal readonly float LightIntensity;

		internal readonly float LightRange;

		internal readonly float LightDistance;

		internal readonly Color FireflyColor;

		internal readonly float CoreDiameter;

		internal readonly float HaloDiameter;

		internal readonly float CoreBrightness;

		internal readonly float HaloBrightness;

		internal readonly float CoreOpacity;

		internal readonly float HaloOpacity;

		internal readonly float PulseMinSeconds;

		internal readonly float PulseMaxSeconds;

		internal readonly float PulseMinimum;

		internal readonly float VisualDistance;

		internal readonly float VisibilityInterval;

		internal readonly float VisibilityHysteresis;

		internal readonly float Radius;

		internal readonly float Speed;

		internal readonly float Steering;

		internal readonly float PauseChance;

		internal readonly float PauseMin;

		internal readonly float PauseMax;

		internal readonly float LegMin;

		internal readonly float LegMax;

		internal readonly float HoverHeight;

		internal readonly float BobAmplitude;

		internal readonly float BobPeriod;

		internal readonly float SurfaceInterval;

		internal readonly float ObstacleRadius;

		internal readonly float ObstacleDistance;

		internal readonly float CurveRate;

		internal readonly float SurfaceResponse;

		internal readonly float AvoidanceResponse;

		internal readonly float RenderResponse;

		internal readonly bool Diagnostics;

		internal SpiritSettings(ConfigFile config)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			Scale = Number(config, "Visuals", "VisualScale", 1f, 0.1f, 1f, "Scale relative to LuredWisp, including particles. Restart required for settings changes.");
			Color value = config.Bind<Color>("Firefly", "FireflyColor", new Color(1f, 0.68f, 0.18f, 1f), "Warm golden-yellow tint shared by core, halo and light. Replaces old GoldColor; restart required.").Value;
			FireflyColor = new Color(Mathf.Clamp01(value.r), Mathf.Clamp01(value.g), Mathf.Clamp01(value.b), 1f);
			LightIntensity = Number(config, "Visuals", "LightIntensity", 0.8f, 0f, 2f, "Point-light intensity; zero removes scene illumination but preserves the emissive glow.");
			LightRange = Number(config, "Visuals", "LightRange", 3f, 0.1f, 5f, "Point-light range in metres; no shadows.");
			LightDistance = Number(config, "Visuals", "LightCullDistance", 15f, 2f, 40f, "Vanilla LightLod distance in metres.");
			CoreDiameter = Number(config, "Firefly", "CoreDiameter", 0.055f, 0.01f, 0.2f, "Luminous billboard core diameter in metres at VisualScale=1; no solid mesh.");
			HaloDiameter = Number(config, "Firefly", "HaloDiameter", 0.45f, 0.1f, 1.5f, "Soft radial halo diameter in metres at VisualScale=1.");
			CoreBrightness = Number(config, "Firefly", "CoreBrightness", 2f, 0.1f, 5f, "Peak unlit core RGB multiplier; appearance depends on tone mapping/bloom.");
			HaloBrightness = Number(config, "Firefly", "HaloBrightness", 1f, 0.1f, 3f, "Peak unlit halo RGB multiplier.");
			CoreOpacity = Number(config, "Firefly", "CoreOpacity", 0.85f, 0.05f, 1f, "Core peak alpha before smooth pulse modulation.");
			HaloOpacity = Number(config, "Firefly", "HaloOpacity", 0.22f, 0.01f, 0.8f, "Halo peak alpha; procedural alpha fades smoothly to zero at its edge.");
			PulseMinSeconds = Number(config, "Firefly", "PulsePeriodMinSeconds", 2f, 0.5f, 20f, "Minimum individual pulse period; stable per-object randomization.");
			PulseMaxSeconds = Mathf.Max(PulseMinSeconds, Number(config, "Firefly", "PulsePeriodMaxSeconds", 4f, 0.5f, 30f, "Maximum individual pulse period."));
			PulseMinimum = Number(config, "Firefly", "PulseMinimumBrightness", 0.08f, 0f, 0.5f, "Dim-phase fraction of peak; modulates core/halo alpha and point-light intensity together.");
			VisualDistance = Number(config, "Visibility", "VisualDistance", 80f, 20f, 120f, "Glow-only camera distance in metres, subject to native object loading/fog/occlusion. Does not expand illumination or global draw distances.");
			VisibilityInterval = Number(config, "Visibility", "CheckIntervalSeconds", 0.25f, 0.1f, 1f, "Local per-object camera-distance check interval; no scene scan.");
			VisibilityHysteresis = Number(config, "Visibility", "HysteresisMetres", 2f, 0f, 10f, "Extra distance before hiding a currently visible glow, preventing edge toggling.");
			Radius = Number(config, "Movement", "WanderRadius", 10f, 1f, 50f, "Horizontal roaming radius around the original network spawn position, with smooth edge steering.");
			Speed = Number(config, "Movement", "MoveSpeed", 1.05f, 0.05f, 2f, "Maximum horizontal speed in metres per second; v0.2 default is 1.75x the v0.1 default.");
			Steering = Number(config, "Movement", "SteeringRate", 1.2f, 0.1f, 5f, "Velocity easing rate; smaller values give gentler turns.");
			CurveRate = Number(config, "Movement", "CurveAngularRate", 0.18f, 0.02f, 0.6f, "Angular rate of the continuously moving two-orbit attractor; no waypoint arrivals.");
			SurfaceResponse = Number(config, "Movement", "SurfaceResponse", 2.5f, 0.2f, 10f, "Per-frame filtering of sampled surface heights and vertical speed response.");
			AvoidanceResponse = Number(config, "Movement", "AvoidanceResponse", 3f, 0.2f, 10f, "Per-frame filtering of occasional obstacle samples.");
			RenderResponse = Number(config, "Movement", "RenderResponse", 12f, 2f, 30f, "LateUpdate visual-position smoothing rate on all peers; root synchronization remains native.");
			PauseChance = Number(config, "Movement", "PauseChance", 0.4f, 0f, 1f, "Chance of pausing after a wander leg.");
			PauseMin = Number(config, "Movement", "PauseMinSeconds", 1.5f, 0.1f, 30f, "Minimum pause duration.");
			PauseMax = Mathf.Max(PauseMin, Number(config, "Movement", "PauseMaxSeconds", 4.5f, 0.1f, 60f, "Maximum pause duration."));
			LegMin = Number(config, "Movement", "DirectionMinSeconds", 7f, 1f, 60f, "Minimum cruising time before a pause opportunity; no abrupt direction change occurs.");
			LegMax = Mathf.Max(LegMin, Number(config, "Movement", "DirectionMaxSeconds", 16f, 1f, 120f, "Maximum cruising time before a pause opportunity."));
			BobAmplitude = Number(config, "Movement", "BobAmplitude", 0.1f, 0f, 0.4f, "Maximum child-visual vertical bob in metres.");
			BobPeriod = Number(config, "Movement", "BobPeriodSeconds", 4f, 1f, 15f, "Main bob period, combined with a second slower oscillation.");
			HoverHeight = Mathf.Max(BobAmplitude + 0.2f, Number(config, "Movement", "HoverHeight", 1.3f, 0.3f, 5f, "Root height above sampled terrain or water; at least bob amplitude plus 0.2m."));
			SurfaceInterval = Number(config, "Movement", "SurfaceCheckSeconds", 0.25f, 0.1f, 2f, "Interval for terrain, water and obstacle samples; filtered every frame. No scene scans.");
			ObstacleRadius = Number(config, "Movement", "ObstacleRadius", 0.15f, 0.05f, 0.5f, "Sphere-cast clearance against terrain and structures.");
			ObstacleDistance = Number(config, "Movement", "ObstacleLookAhead", 0.9f, 0.3f, 3f, "Minimum obstacle look-ahead distance; automatically increased for speed/check interval.");
			Diagnostics = config.Bind<bool>("Diagnostics", "LogOwnership", false, "Log owner changes per spirit; no per-frame logging.").Value;
		}

		private static float Number(ConfigFile config, string section, string key, float value, float min, float max, string description)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return config.Bind<float>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())).Value;
		}
	}
	internal sealed class SpiritVisuals
	{
		private readonly SpiritSettings settings;

		private readonly ManualLogSource log;

		private Material glow;

		private Texture2D radial;

		internal int MaterialCount => Object.op_Implicit((Object)(object)glow) ? 1 : 0;

		internal SpiritVisuals(SpiritSettings settings, ManualLogSource log)
		{
			this.settings = settings;
			this.log = log;
		}

		internal void Build(GameObject donor, GameObject root)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: 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)
			Transform val = donor.transform.Find("effects/flare");
			ParticleSystemRenderer val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<ParticleSystemRenderer>() : null);
			Material val3 = (Object.op_Implicit((Object)(object)val2) ? ((Renderer)val2).sharedMaterial : null);
			if (!Object.op_Implicit((Object)(object)val3) || ((Object)val3.shader).name != "Legacy Shaders/Particles/Alpha Blended" || !val3.HasProperty("_TintColor") || !val3.HasProperty("_MainTex"))
			{
				throw new InvalidOperationException("Inspected LuredWisp transparent flare material is missing/changed; refusing a solid fallback.");
			}
			radial = CreateRadialTexture();
			glow = new Material(val3)
			{
				name = "PrimeForestSpirit_FireflyGlow",
				renderQueue = 3000
			};
			glow.SetTexture("_MainTex", (Texture)(object)radial);
			Color val4 = settings.FireflyColor * 0.5f;
			val4.a = settings.CoreOpacity * settings.PulseMinimum * 0.5f;
			glow.SetColor("_TintColor", val4);
			if (glow.HasProperty("_ZWrite"))
			{
				glow.SetInt("_ZWrite", 0);
			}
			if (glow.HasProperty("_SrcBlend"))
			{
				glow.SetInt("_SrcBlend", 5);
			}
			if (glow.HasProperty("_DstBlend"))
			{
				glow.SetInt("_DstBlend", 10);
			}
			GameObject val5 = new GameObject("PrimeForestSpiritVisuals");
			val5.transform.SetParent(root.transform, false);
			val5.transform.localScale = Vector3.one * settings.Scale;
			ParticleSystemRenderer val6 = CreatePoint(val5.transform, "PrimeFireflyCore", settings.CoreDiameter);
			ParticleSystemRenderer val7 = CreatePoint(val5.transform, "PrimeFireflyHalo", settings.HaloDiameter);
			GameObject val8 = new GameObject("PrimeFireflyLight");
			val8.transform.SetParent(val5.transform, false);
			Light obj = val8.AddComponent<Light>();
			obj.type = (LightType)2;
			obj.color = settings.FireflyColor;
			obj.intensity = settings.LightIntensity * settings.PulseMinimum;
			obj.range = settings.LightRange;
			obj.shadows = (LightShadows)0;
			LightLod obj2 = val8.AddComponent<LightLod>();
			obj2.m_lightLod = true;
			obj2.m_lightDistance = settings.LightDistance;
			obj2.m_shadowLod = false;
			LODGroup component = donor.GetComponent<LODGroup>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("LuredWisp LODGroup missing.");
			}
			LOD[] lODs = component.GetLODs();
			if (lODs.Length != 1)
			{
				throw new InvalidOperationException("Unexpected LuredWisp LOD layout; review before registration.");
			}
			lODs[0].renderers = (Renderer[])(object)new Renderer[2]
			{
				(Renderer)val6,
				(Renderer)val7
			};
			lODs[0].screenRelativeTransitionHeight = 0f;
			LODGroup obj3 = root.AddComponent<LODGroup>();
			obj3.SetLODs(lODs);
			obj3.fadeMode = component.fadeMode;
			obj3.animateCrossFading = component.animateCrossFading;
			obj3.localReferencePoint = component.localReferencePoint * settings.Scale;
			obj3.size = component.size * settings.Scale;
			obj3.enabled = component.enabled;
			log.LogInfo((object)("Firefly visuals: no solid mesh, sparks or trails; two stationary billboards, one owned material/radial texture. Shader=" + ((Object)glow.shader).name + "; core/halo=" + settings.CoreDiameter + "/" + settings.HaloDiameter + "m; screen-size cull removed, glow-only distance=" + settings.VisualDistance + "m; light range unchanged=" + settings.LightRange + "m."));
		}

		private Texture2D CreateRadialTexture()
		{
			//IL_00b9: 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_00c9: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			Color[] array = (Color[])(object)new Color[16384];
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					double num = 2.0 * (double)j / 127.0 - 1.0;
					double num2 = 2.0 * (double)i / 127.0 - 1.0;
					array[i * 128 + j] = new Color(1f, 1f, 1f, FireflyMath.RadialAlpha(Math.Sqrt(num * num + num2 * num2)));
				}
			}
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, true)
			{
				name = "PrimeForestSpirit_RadialGlow",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1
			};
			val.SetPixels(array);
			val.Apply(true, true);
			return val;
		}

		private ParticleSystemRenderer CreatePoint(Transform parent, string name, float diameter)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			ParticleSystem val2 = val.AddComponent<ParticleSystem>();
			val2.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = val2.main;
			((MainModule)(ref main)).duration = 1f;
			((MainModule)(ref main)).loop = true;
			((MainModule)(ref main)).playOnAwake = true;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(float.PositiveInfinity);
			((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0f);
			((MainModule)(ref main)).startSize3D = false;
			((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(diameter);
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.white);
			((MainModule)(ref main)).maxParticles = 1;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)0;
			((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0;
			ShapeModule shape = val2.shape;
			((ShapeModule)(ref shape)).enabled = false;
			EmissionModule emission = val2.emission;
			((EmissionModule)(ref emission)).enabled = true;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
			((EmissionModule)(ref emission)).rateOverDistance = MinMaxCurve.op_Implicit(0f);
			((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1]
			{
				new Burst(0f, (short)1)
			});
			TrailModule trails = val2.trails;
			((TrailModule)(ref trails)).enabled = false;
			LightsModule lights = val2.lights;
			((LightsModule)(ref lights)).enabled = false;
			CollisionModule collision = val2.collision;
			((CollisionModule)(ref collision)).enabled = false;
			TriggerModule trigger = val2.trigger;
			((TriggerModule)(ref trigger)).enabled = false;
			ExternalForcesModule externalForces = val2.externalForces;
			((ExternalForcesModule)(ref externalForces)).enabled = false;
			ParticleSystemRenderer val3 = val.GetComponent<ParticleSystemRenderer>();
			if (!Object.op_Implicit((Object)(object)val3))
			{
				val3 = val.AddComponent<ParticleSystemRenderer>();
			}
			val3.renderMode = (ParticleSystemRenderMode)0;
			val3.alignment = (ParticleSystemRenderSpace)0;
			((Renderer)val3).sharedMaterial = glow;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val3).receiveShadows = false;
			return val3;
		}

		internal static void Validate(GameObject root)
		{
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					throw new InvalidOperationException("Unresolved script in firefly prefab.");
				}
				bool num;
				if (!((Object)(object)val.gameObject == (Object)(object)root))
				{
					if (val is Transform || val is ParticleSystem || val is ParticleSystemRenderer || val is Light)
					{
						continue;
					}
					num = val is LightLod;
				}
				else
				{
					if (val is Transform || val is ZNetView || val is ZSyncTransform || val is SpiritWander || val is FireflyPulse || val is FireflyVisibility || val is SpiritLifetime)
					{
						continue;
					}
					num = val is LODGroup;
				}
				if (!num)
				{
					throw new InvalidOperationException("Disallowed firefly component: " + ((object)val).GetType().FullName);
				}
			}
			if (root.GetComponentsInChildren<ParticleSystem>(true).Length != 2 || root.GetComponentsInChildren<ParticleSystemRenderer>(true).Length != 2 || root.GetComponentsInChildren<Light>(true).Length != 1)
			{
				throw new InvalidOperationException("Expected exactly two glow systems and one point light.");
			}
			LODGroup component = root.GetComponent<LODGroup>();
			LOD[] array = (LOD[])(Object.op_Implicit((Object)(object)component) ? ((Array)component.GetLODs()) : ((Array)new LOD[0]));
			if (array.Length != 1 || array[0].renderers.Length != 2 || (Object)(object)array[0].renderers[0] == (Object)(object)array[0].renderers[1])
			{
				throw new InvalidOperationException("Expected exactly two distinct firefly LOD renderers.");
			}
			if (array[0].screenRelativeTransitionHeight != 0f)
			{
				throw new InvalidOperationException("Unexpected screen-size cutoff on extended-visibility firefly.");
			}
			Renderer[] renderers = array[0].renderers;
			foreach (Renderer val2 in renderers)
			{
				if (!(val2 is ParticleSystemRenderer) || !((Component)val2).transform.IsChildOf(root.transform))
				{
					throw new InvalidOperationException("Firefly LOD refers outside its billboard hierarchy.");
				}
			}
			ParticleSystem[] componentsInChildren2 = root.GetComponentsInChildren<ParticleSystem>(true);
			int i = 0;
			while (i < componentsInChildren2.Length)
			{
				ParticleSystem val3 = componentsInChildren2[i];
				MainModule main = val3.main;
				if (((MainModule)(ref main)).maxParticles == 1)
				{
					main = val3.main;
					if ((int)((MainModule)(ref main)).simulationSpace == 0)
					{
						TrailModule trails = val3.trails;
						if (!((TrailModule)(ref trails)).enabled)
						{
							CollisionModule collision = val3.collision;
							if (!((CollisionModule)(ref collision)).enabled)
							{
								TriggerModule trigger = val3.trigger;
								if (!((TriggerModule)(ref trigger)).enabled)
								{
									LightsModule lights = val3.lights;
									if (!((LightsModule)(ref lights)).enabled)
									{
										i++;
										continue;
									}
								}
							}
						}
					}
				}
				throw new InvalidOperationException("Unexpected gameplay, trail or particle count in glow system.");
			}
		}
	}
	[DefaultExecutionOrder(200)]
	public sealed class FireflyPulse : MonoBehaviour
	{
		private ZNetView view;

		private ParticleSystemRenderer core;

		private ParticleSystemRenderer halo;

		private Light pointLight;

		private MaterialPropertyBlock properties;

		private SpiritSettings settings;

		private double period;

		private double cycle;

		private bool initialized;

		private FireflyVisibility visibility;

		private static readonly int TintId = Shader.PropertyToID("_TintColor");

		private void Start()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			view = ((Component)this).GetComponent<ZNetView>();
			settings = PrimeForestSpiritPlugin.Settings;
			visibility = ((Component)this).GetComponent<FireflyVisibility>();
			Transform val = ((Component)this).transform.Find("PrimeForestSpiritVisuals");
			if (!Object.op_Implicit((Object)(object)view) || !Object.op_Implicit((Object)(object)val) || settings == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			core = ((Component)val.Find("PrimeFireflyCore")).GetComponent<ParticleSystemRenderer>();
			halo = ((Component)val.Find("PrimeFireflyHalo")).GetComponent<ParticleSystemRenderer>();
			pointLight = ((Component)val.Find("PrimeFireflyLight")).GetComponent<Light>();
			properties = new MaterialPropertyBlock();
			Apply(settings.PulseMinimum);
		}

		private void LateUpdate()
		{
			if (settings != null && properties != null && Object.op_Implicit((Object)(object)view) && view.IsValid() && (!Object.op_Implicit((Object)(object)visibility) || visibility.Visible))
			{
				if (!initialized)
				{
					FireflyMath.Parameters((uint)((object)Unsafe.As<ZDOID, ZDOID>(ref view.GetZDO().m_uid)/*cast due to .constrained prefix*/).GetHashCode(), settings.PulseMinSeconds, settings.PulseMaxSeconds, out period, out cycle);
					initialized = true;
				}
				cycle = (cycle + (double)Mathf.Min(Time.deltaTime, 0.1f) / period) % 1.0;
				Apply(FireflyMath.Pulse(cycle, settings.PulseMinimum));
			}
		}

		private void Apply(float pulse)
		{
			SetTint((Renderer)(object)core, settings.CoreBrightness, settings.CoreOpacity * pulse);
			SetTint((Renderer)(object)halo, settings.HaloBrightness, settings.HaloOpacity * pulse);
			pointLight.intensity = settings.LightIntensity * pulse;
		}

		private void SetTint(Renderer renderer, float brightness, float alpha)
		{
			//IL_0006: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			Color val = settings.FireflyColor * (brightness * 0.5f);
			val.a = alpha * 0.5f;
			properties.SetColor(TintId, val);
			renderer.SetPropertyBlock(properties);
		}
	}
	internal static class FireflyMath
	{
		internal static float RadialAlpha(double radius)
		{
			double num = Math.Max(0.0, 1.0 - radius * radius);
			if (!(radius >= 1.0))
			{
				return (float)(num * num * num);
			}
			return 0f;
		}

		internal static float Pulse(double cycle, float minimum)
		{
			return minimum + (1f - minimum) * (float)(0.5 - 0.5 * Math.Cos(Math.PI * 2.0 * cycle));
		}

		internal static void Parameters(uint identity, float min, float max, out double period, out double cycle)
		{
			uint num = identity ^ 0xF17EF17Eu;
			num ^= num >> 16;
			num *= 2146121005;
			num ^= num >> 15;
			num *= 2221713035u;
			num ^= num >> 16;
			period = (double)min + (double)(max - min) * SpiritMath.Next01(ref num);
			cycle = SpiritMath.Next01(ref num);
		}
	}
	public sealed class FireflyVisibility : MonoBehaviour
	{
		private Renderer core;

		private Renderer halo;

		private SpiritSettings settings;

		private float timer;

		private bool visible = true;

		private GameObject visualRoot;

		private static int conditionFrame = -1;

		private static bool night;

		private static bool restored;

		internal bool Visible => visible;

		private void Start()
		{
			settings = PrimeForestSpiritPlugin.Settings;
			Transform val = ((Component)this).transform.Find("PrimeForestSpiritVisuals");
			if (!Object.op_Implicit((Object)(object)val) || settings == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			visualRoot = ((Component)val).gameObject;
			core = (Renderer)(object)((Component)val.Find("PrimeFireflyCore")).GetComponent<ParticleSystemRenderer>();
			halo = (Renderer)(object)((Component)val.Find("PrimeFireflyHalo")).GetComponent<ParticleSystemRenderer>();
		}

		private void Update()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			if (settings == null || !Object.op_Implicit((Object)(object)core) || !Object.op_Implicit((Object)(object)halo))
			{
				return;
			}
			timer -= Time.deltaTime;
			if (!(timer > 0f))
			{
				timer = settings.VisibilityInterval;
				if (conditionFrame != Time.frameCount)
				{
					conditionFrame = Time.frameCount;
					night = Object.op_Implicit((Object)(object)EnvMan.instance) && EnvMan.IsNight();
					restored = PrimeForestSpiritPlugin.RestorationGate?.Invoke() ?? (Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey("prime_swamp_restored"));
				}
				Camera mainCamera = Utils.GetMainCamera();
				bool num = night;
				bool num2 = restored;
				bool camera = Object.op_Implicit((Object)(object)mainCamera);
				float squaredDistance;
				if (!Object.op_Implicit((Object)(object)mainCamera))
				{
					squaredDistance = float.MaxValue;
				}
				else
				{
					Vector3 val = ((Component)mainCamera).transform.position - ((Component)this).transform.position;
					squaredDistance = ((Vector3)(ref val)).sqrMagnitude;
				}
				bool flag = FireflyActivityPolicy.Visible(num, num2, camera, squaredDistance, settings.VisualDistance, settings.VisibilityHysteresis, visible);
				if (flag != visible)
				{
					visible = flag;
					core.forceRenderingOff = !visible;
					halo.forceRenderingOff = !visible;
					visualRoot.SetActive(visible);
				}
			}
		}
	}
	internal static class FireflyActivityPolicy
	{
		internal static bool Visible(bool night, bool restored, bool camera, float squaredDistance, float distance, float hysteresis, bool wasVisible)
		{
			float num = distance + (wasVisible ? hysteresis : 0f);
			if (night && restored && camera)
			{
				return squaredDistance <= num * num;
			}
			return false;
		}
	}
	public sealed class SpiritWander : MonoBehaviour
	{
		private const string HomeKey = "PrimeForestSpirit_home";

		private const string InitializedKey = "PrimeForestSpirit_initialized";

		private const string RandomKey = "PrimeForestSpirit_random";

		private const string PauseKey = "PrimeForestSpirit_paused";

		private const string DeadlineKey = "PrimeForestSpirit_deadline";

		private ZNetView view;

		private Transform visual;

		private SpiritSettings settings;

		private Vector3 home;

		private Vector3 velocity;

		private Vector3 avoidance;

		private Vector3 sampledAvoidance;

		private Vector3 renderPosition;

		private WaterVolume water;

		private uint random;

		private double phase;

		private float surfaceTimer;

		private float floorHeight;

		private float filteredFloor;

		private long deadline;

		private bool wasOwner;

		private bool initialized;

		private bool paused;

		private bool surfaceReady;

		private bool haveFloor;

		private int obstacleMask;

		private void Start()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			view = ((Component)this).GetComponent<ZNetView>();
			visual = ((Component)this).transform.Find("PrimeForestSpiritVisuals");
			settings = PrimeForestSpiritPlugin.Settings;
			renderPosition = ((Component)this).transform.position;
			obstacleMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
			if (!Object.op_Implicit((Object)(object)view) || !Object.op_Implicit((Object)(object)visual) || settings == null)
			{
				((Behaviour)this).enabled = false;
			}
		}

		private void Update()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || settings == null || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			ZDO zDO = view.GetZDO();
			phase = (double)((uint)((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).GetHashCode() % 65521u) * 9.589574803772205E-05;
			bool flag = view.IsOwner();
			if (flag && !wasOwner)
			{
				ReadOwnerState(zDO);
			}
			if (flag != wasOwner && Object.op_Implicit((Object)(object)PrimeForestSpiritPlugin.Instance))
			{
				PrimeForestSpiritPlugin.Instance.Diagnostic(((Object)this).name + " network owner=" + flag);
			}
			wasOwner = flag;
			if (!flag || !initialized)
			{
				return;
			}
			float num = Mathf.Min(Time.deltaTime, 0.1f);
			long ticks = ZNet.instance.GetTime().Ticks;
			surfaceTimer -= num;
			if (surfaceTimer <= 0f)
			{
				SampleSurfaceAndObstacle();
				surfaceTimer = settings.SurfaceInterval;
			}
			if (!surfaceReady)
			{
				velocity = Vector3.zero;
				return;
			}
			if (ticks >= deadline)
			{
				ChooseNext(zDO, ticks);
			}
			filteredFloor = Mathf.Lerp(filteredFloor, floorHeight, SpiritMath.Ease(settings.SurfaceResponse, num));
			avoidance = Vector3.Lerp(avoidance, sampledAvoidance, SpiritMath.Ease(settings.AvoidanceResponse, num));
			Vector3 val = Vector3.zero;
			if (!paused)
			{
				SpiritMath.Curve(ZNet.instance.GetTimeSeconds(), phase, settings.Radius, settings.CurveRate, out var x, out var z);
				Vector3 val2 = home + new Vector3((float)x, 0f, (float)z) - ((Component)this).transform.position;
				val2.y = 0f;
				val = Vector3.ClampMagnitude(val2 / 1.5f + avoidance * settings.Speed, settings.Speed);
				Vector3 val3 = ((Component)this).transform.position - home;
				val3.y = 0f;
				float magnitude = ((Vector3)(ref val3)).magnitude;
				if (magnitude > settings.Radius * 0.8f)
				{
					float num2 = Mathf.Clamp01((magnitude / settings.Radius - 0.8f) / 0.2f);
					val = Vector3.Lerp(val, -((Vector3)(ref val3)).normalized * settings.Speed, num2);
				}
			}
			float num3 = filteredFloor + settings.HoverHeight - ((Component)this).transform.position.y;
			val.y = Mathf.Clamp(num3 * settings.SurfaceResponse, (0f - settings.Speed) * 0.7f, settings.Speed * 0.7f);
			velocity = Vector3.Lerp(velocity, val, SpiritMath.Ease(settings.Steering, num));
			Vector3 position = ((Component)this).transform.position;
			Vector3 val4 = velocity * num;
			float num4 = (float)SpiritMath.DiscStepFraction(position.x - home.x, position.z - home.z, val4.x, val4.z, settings.Radius);
			Vector3 position2 = position + val4 * num4;
			if (num4 < 1f)
			{
				velocity *= num4;
			}
			position2.y = position.y + val4.y;
			((Component)this).transform.position = position2;
		}

		private void LateUpdate()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)visual) && settings != null && Object.op_Implicit((Object)(object)view) && view.IsValid() && Object.op_Implicit((Object)(object)ZNet.instance))
			{
				renderPosition = Vector3.Lerp(renderPosition, ((Component)this).transform.position, SpiritMath.Ease(settings.RenderResponse, Mathf.Min(Time.deltaTime, 0.1f)));
				visual.position = renderPosition + Vector3.up * SpiritMath.Bob(ZNet.instance.GetTimeSeconds(), settings.BobAmplitude, settings.BobPeriod, phase);
			}
		}

		private void ReadOwnerState(ZDO zdo)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			initialized = zdo.GetBool("PrimeForestSpirit_initialized", false);
			if (!initialized)
			{
				home = ((Component)this).transform.position;
				random = (uint)((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).GetHashCode();
				if (random == 0)
				{
					random = 2654435769u;
				}
				paused = true;
				deadline = 0L;
				zdo.Set("PrimeForestSpirit_home", home);
				WriteLeg(zdo);
				zdo.Set("PrimeForestSpirit_initialized", true);
				initialized = true;
			}
			else
			{
				home = zdo.GetVec3("PrimeForestSpirit_home", ((Component)this).transform.position);
				random = (uint)zdo.GetInt("PrimeForestSpirit_random", 1);
				paused = zdo.GetBool("PrimeForestSpirit_paused", false);
				deadline = zdo.GetLong("PrimeForestSpirit_deadline", 0L);
			}
			velocity = Vector3.zero;
			surfaceTimer = 0f;
			haveFloor = false;
		}

		private void ChooseNext(ZDO zdo, long now)
		{
			bool flag = !paused && SpiritMath.Next01(ref random) < (double)settings.PauseChance;
			paused = flag;
			float num = ((!paused) ? Range(settings.LegMin, settings.LegMax) : Range(settings.PauseMin, settings.PauseMax));
			deadline = now + (long)(num * 10000000f);
			WriteLeg(zdo);
		}

		private float Range(float min, float max)
		{
			return min + (max - min) * (float)SpiritMath.Next01(ref random);
		}

		private void WriteLeg(ZDO zdo)
		{
			zdo.Set("PrimeForestSpirit_random", (int)random);
			zdo.Set("PrimeForestSpirit_paused", paused);
			zdo.Set("PrimeForestSpirit_deadline", deadline);
		}

		private void SampleSurfaceAndObstacle()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			//IL_00eb: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			surfaceReady = Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGroundHeight(((Component)this).transform.position, ref floorHeight);
			if (surfaceReady)
			{
				float waterLevel = Floating.GetWaterLevel(((Component)this).transform.position, ref water);
				floorHeight = Mathf.Max(floorHeight, waterLevel);
				floorHeight = Mathf.Max(floorHeight, ZoneSystem.instance.m_waterLevel);
				if (!haveFloor)
				{
					filteredFloor = floorHeight;
					haveFloor = true;
				}
				Vector3 val = velocity;
				val.y = 0f;
				float num = Mathf.Max(settings.ObstacleDistance, settings.Speed * settings.SurfaceInterval * 2f + settings.ObstacleRadius);
				sampledAvoidance = Vector3.zero;
				RaycastHit val2 = default(RaycastHit);
				if (((Vector3)(ref val)).sqrMagnitude > 0.01f && Physics.SphereCast(((Component)this).transform.position, settings.ObstacleRadius, ((Vector3)(ref val)).normalized, ref val2, num, obstacleMask, (QueryTriggerInteraction)1))
				{
					Vector3 normal = ((RaycastHit)(ref val2)).normal;
					normal.y = 0f;
					sampledAvoidance = ((Vector3)(ref normal)).normalized * 2f;
				}
			}
		}
	}
	internal static class SpiritMath
	{
		internal static double Next01(ref uint state)
		{
			if (state == 0)
			{
				state = 2654435769u;
			}
			state ^= state << 13;
			state ^= state >> 17;
			state ^= state << 5;
			return (double)(state >> 8) / 16777216.0;
		}

		internal static void Disc(ref uint state, double radius, out double x, out double z)
		{
			double num = Next01(ref state) * Math.PI * 2.0;
			double num2 = Math.Sqrt(Next01(ref state)) * radius;
			x = Math.Cos(num) * num2;
			z = Math.Sin(num) * num2;
		}

		internal static float Ease(float rate, float dt)
		{
			return (float)(1.0 - Math.Exp((0f - Math.Max(0f, rate)) * Math.Max(0f, dt)));
		}

		internal static void Curve(double time, double phase, double radius, double rate, out double x, out double z)
		{
			double num = time * rate + phase + 0.16 * Math.Sin(time * rate * 0.43 + phase * 0.7);
			double num2 = (0.0 - time) * rate * 1.371 + phase * 1.731;
			x = radius * (0.55 * Math.Cos(num) + 0.2 * Math.Cos(num2));
			z = radius * (0.55 * Math.Sin(num) + 0.2 * Math.Sin(num2));
		}

		internal static double DiscStepFraction(double x, double z, double dx, double dz, double radius)
		{
			double num = x * x + z * z;
			double num2 = (x + dx) * (x + dx) + (z + dz) * (z + dz);
			double num3 = radius * radius;
			if (num > num3 + 1E-09)
			{
				return (num2 <= num) ? 1 : 0;
			}
			if (num2 <= num3)
			{
				return 1.0;
			}
			double num4 = dx * dx + dz * dz;
			if (num4 < 1E-16)
			{
				return 0.0;
			}
			double num5 = 2.0 * (x * dx + z * dz);
			double num6 = num - num3;
			return Math.Max(0.0, Math.Min(1.0, (0.0 - num5 + Math.Sqrt(Math.Max(0.0, num5 * num5 - 4.0 * num4 * num6))) / (2.0 * num4)));
		}

		internal static float Bob(double time, float amplitude, float period, double phase)
		{
			return amplitude * (float)((Math.Sin(time * Math.PI * 2.0 / (double)period + phase) + 0.23 * Math.Sin(time * Math.PI * 2.0 / ((double)period * 1.731) + phase * 1.37)) / 1.23);
		}
	}
	public sealed class SpiritLifetime : MonoBehaviour
	{
		private const string ExpiryKey = "PrimeForestSpirit_ambientExpiry";

		private ZNetView view;

		private float checkTimer;

		private bool destroying;

		private void Start()
		{
			view = ((Component)this).GetComponent<ZNetView>();
		}

		private void Update()
		{
			checkTimer -= Time.deltaTime;
			if (checkTimer > 0f || destroying)
			{
				return;
			}
			checkTimer = 1f;
			if (Object.op_Implicit((Object)(object)view) && view.IsValid() && view.IsOwner() && Object.op_Implicit((Object)(object)ZNet.instance) && Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				ZDO zDO = view.GetZDO();
				long ticks = ZNet.instance.GetTime().Ticks;
				long num = zDO.GetLong("PrimeForestSpirit_ambientExpiry", 0L);
				if (num == 0L)
				{
					num = ticks + SpiritLifetimeMath.DurationTicks((uint)((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).GetHashCode());
					zDO.Set("PrimeForestSpirit_ambientExpiry", num);
				}
				if (ticks >= num)
				{
					destroying = true;
					ZNetScene.instance.Destroy(((Component)this).gameObject);
				}
			}
		}
	}
	internal static class SpiritLifetimeMath
	{
		internal static long DurationTicks(uint identity)
		{
			FireflyMath.Parameters(identity ^ 0xA6B13C59u, 240f, 360f, out var period, out var _);
			return (long)(period * 10000000.0);
		}
	}
}

BepInEx/plugins/PrimeSwampDecorations/PrimeSwampDecorations.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeSwampDecorations")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyInformationalVersion("0.3.1")]
[assembly: AssemblyProduct("PrimeSwampDecorations")]
[assembly: AssemblyTitle("PrimeSwampDecorations")]
[assembly: AssemblyVersion("0.3.1.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 PrimeSwampDecorations
{
	[BepInPlugin("com.primeswamp.decorations", "Prime Swamp Decorations", "0.3.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PrimeSwampPlugin : BaseUnityPlugin
	{
		private static readonly string[,] Sources = new string[10, 3]
		{
			{ "PrimeSwampCampfire", "fire_pit_haldor", "light" },
			{ "PrimeSwampIronFirepit", "fire_pit_hildir", "light" },
			{ "PrimeSwampStandingIronTorch", "piece_groundtorch", "light" },
			{ "PrimeSwampSconce", "piece_walltorch", "light" },
			{ "PrimeSwampBogWitchFirePit", "BogWitch_Fire_Pit", "light" },
			{ "PrimeSwampHearth", "hearth", "light" },
			{ "PrimeSwampCandle", "Candle_resin", "light" },
			{ "PrimeSwampBed", "bed", "utility" },
			{ "PrimeSwampWorkbench", "piece_workbench", "utility" },
			{ "PrimeSwampForge", "forge", "utility" }
		};

		private void Awake()
		{
			PrefabManager.OnVanillaPrefabsAvailable += OnPrefabsAvailable;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Prime Swamp Decorations 0.3.1 loaded; native donors, no MVBP wait or build menus.");
		}

		private void OnPrefabsAvailable()
		{
			((MonoBehaviour)this).StartCoroutine(RegisterPrefabs());
			PrefabManager.OnVanillaPrefabsAvailable -= OnPrefabsAvailable;
		}

		private IEnumerator RegisterPrefabs()
		{
			InstallInteractionPatches();
			for (int i = 0; i < Sources.GetLength(0); i++)
			{
				string text = Sources[i, 0];
				string text2 = Sources[i, 1];
				bool flag = Sources[i, 2] == "light";
				try
				{
					GameObject val = PrefabManager.Instance.CreateClonedPrefab(text, text2);
					if ((Object)(object)val == (Object)null)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Source not found: " + text2));
						continue;
					}
					int num = 0;
					int num2 = 0;
					EffectArea[] componentsInChildren = val.GetComponentsInChildren<EffectArea>(true);
					foreach (EffectArea val2 in componentsInChildren)
					{
						if ((val2.m_type & 4) != 0)
						{
							val2.m_type = (Type)(val2.m_type & 0xFB);
							if ((int)val2.m_type == 0)
							{
								((Behaviour)val2).enabled = false;
							}
							num++;
						}
					}
					if (flag)
					{
						Fireplace[] componentsInChildren2 = val.GetComponentsInChildren<Fireplace>(true);
						foreach (Fireplace instance in componentsInChildren2)
						{
							SetField(instance, "m_startFuel", 100f);
							SetField(instance, "m_maxFuel", 100f);
							SetField(instance, "m_secPerFuel", 1E+09f);
							num2++;
						}
					}
					PrefabManager.Instance.AddPrefab(val);
					((BaseUnityPlugin)this).Logger.LogInfo((object)("REGISTERED " + text + " <- " + text2 + " | suppression removed=" + num + " | fireplaces=" + num2));
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("FAILED " + text + ": " + ex));
				}
			}
			yield break;
		}

		private static void SetField(object instance, string name, float value)
		{
			FieldInfo field = instance.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(float))
			{
				field.SetValue(instance, value);
			}
		}

		private void InstallInteractionPatches()
		{
			try
			{
				Type type = Type.GetType("HarmonyLib.Harmony, 0Harmony") ?? Type.GetType("HarmonyLib.Harmony, HarmonyX");
				Type type2 = Type.GetType("HarmonyLib.HarmonyMethod, 0Harmony") ?? Type.GetType("HarmonyLib.HarmonyMethod, HarmonyX");
				if (type == null || type2 == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Harmony unavailable: light prompts not hidden");
					return;
				}
				object harmony = Activator.CreateInstance(type, "com.primeswamp.decorations.interactions");
				ConstructorInfo constructor = type2.GetConstructor(new Type[1] { typeof(MethodInfo) });
				MethodInfo methodInfo = null;
				MethodInfo[] methods = type.GetMethods();
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (methodInfo2.Name == "Patch" && methodInfo2.GetParameters().Length >= 2 && methodInfo2.GetParameters()[0].ParameterType == typeof(MethodBase))
					{
						methodInfo = methodInfo2;
						break;
					}
				}
				if (constructor == null || methodInfo == null)
				{
					throw new Exception("Harmony patch API not found");
				}
				PatchMethod(harmony, methodInfo, constructor, "GetHoverText", "HideHoverText");
				PatchMethod(harmony, methodInfo, constructor, "GetHoverName", "HideHoverName");
				PatchMethod(harmony, methodInfo, constructor, "Interact", "BlockInteraction");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom light interaction patches installed.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not hide light interactions: " + ex));
			}
		}

		private static void PatchMethod(object harmony, MethodInfo patch, ConstructorInfo ctor, string original, string prefix)
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(Fireplace).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2.Name == original)
				{
					methodInfo = methodInfo2;
					break;
				}
			}
			if (!(methodInfo == null))
			{
				MethodInfo method = typeof(PrimeSwampPlugin).GetMethod(prefix, BindingFlags.Static | BindingFlags.NonPublic);
				object obj = ctor.Invoke(new object[1] { method });
				object[] array = new object[patch.GetParameters().Length];
				array[0] = methodInfo;
				array[1] = obj;
				patch.Invoke(harmony, array);
			}
		}

		private static bool IsOurLight(Fireplace fireplace)
		{
			if ((Object)(object)fireplace == (Object)null)
			{
				return false;
			}
			Transform val = ((Component)fireplace).transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name.StartsWith("PrimeSwamp", StringComparison.Ordinal) && ((Object)val).name != "PrimeSwampBed" && ((Object)val).name != "PrimeSwampWorkbench" && ((Object)val).name != "PrimeSwampForge")
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool HideHoverText(Fireplace __instance, ref string __result)
		{
			if (!IsOurLight(__instance))
			{
				return true;
			}
			__result = "";
			return false;
		}

		private static bool HideHoverName(Fireplace __instance, ref string __result)
		{
			if (!IsOurLight(__instance))
			{
				return true;
			}
			__result = "";
			return false;
		}

		private static bool BlockInteraction(Fireplace __instance, ref bool __result)
		{
			if (!IsOurLight(__instance))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
}

BepInEx/plugins/PrimeSwampNPCs/PrimeSwampNPCs.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeSwampNPCs")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.9.0")]
[assembly: AssemblyInformationalVersion("0.1.9+clothing-dialogue.1")]
[assembly: AssemblyProduct("PrimeSwampNPCs")]
[assembly: AssemblyTitle("PrimeSwampNPCs")]
[assembly: AssemblyVersion("0.1.9.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 BiomeRevival.PrimeSwampNPCs
{
	public sealed class NpcRuntime : MonoBehaviour
	{
		private static readonly FieldRef<VisEquipment, int> RenderedLegHash = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentLegItemHash");

		private float appearanceAudit = -1f;

		private static readonly FieldRef<MonsterAI, StaticTarget> StaticTargetField = AccessTools.FieldRefAccess<MonsterAI, StaticTarget>("m_targetStatic");

		private static readonly Func<BaseAI, float, Vector3, float, bool, bool> MoveHome = AccessTools.MethodDelegate<Func<BaseAI, float, Vector3, float, bool, bool>>(AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4]
		{
			typeof(float),
			typeof(Vector3),
			typeof(float),
			typeof(bool)
		}, (Type[])null), (object)null, true);

		private static readonly Func<BaseAI, float, Vector3, bool> RunAway = AccessTools.MethodDelegate<Func<BaseAI, float, Vector3, bool>>(AccessTools.Method(typeof(BaseAI), "Flee", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<MonsterAI, bool> SetAlert = AccessTools.MethodDelegate<Action<MonsterAI, bool>>(AccessTools.Method(typeof(MonsterAI), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null), (object)null, true);

		private readonly List<Character> candidates = new List<Character>();

		private float threatScan;

		private Character danger;

		private bool returning;

		private bool fleeing;

		private static readonly Func<BaseAI, Vector3, bool> FarmHavePath = AccessTools.MethodDelegate<Func<BaseAI, Vector3, bool>>(AccessTools.Method(typeof(BaseAI), "HavePath", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<BaseAI> FarmStop = AccessTools.MethodDelegate<Action<BaseAI>>(AccessTools.Method(typeof(BaseAI), "StopMoving", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<BaseAI, float> LastFarmPath = AccessTools.FieldRefAccess<BaseAI, float>("m_lastFindPathTime");

		private readonly FarmerClock farmClock = new FarmerClock();

		private Vector3 farmDestination;

		private float farmRetry;

		private float farmPoseTimer;

		private float farmPoseSafetyUntil;

		private bool farmAgentChanged;

		private AgentType originalFarmAgent;

		private Vector3 civilianWaterFacing;

		private bool civilianShore;

		private readonly CivilianActivity farmerSettings = new CivilianActivity
		{
			Mode = "Farming"
		};

		private ZoneSystem priestAltarWorld;

		private readonly List<Vector3> priestAltars = new List<Vector3>();

		private static readonly FieldRef<Humanoid, Attack> CurrentAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack");

		private float playerContactWait;

		private static readonly int AggravatedKey = (int)AccessTools.Field(AccessTools.TypeByName("ZDOVars"), "s_aggravated").GetValue(null);

		private bool playerCombat;

		private long nextCombatReaction;

		private long nextWitnessRequest;

		private uint reactionRandom;

		public string Profession;

		internal static readonly List<NpcRuntime> Instances = new List<NpcRuntime>();

		internal static readonly Action<MonsterAI, Character> SetTarget = AccessTools.MethodDelegate<Action<MonsterAI, Character>>(AccessTools.Method(typeof(MonsterAI), "SetTarget", (Type[])null, (Type[])null), (object)null, true);

		internal static readonly Action<BaseAI, Vector3> SetPatrol = AccessTools.MethodDelegate<Action<BaseAI, Vector3>>(AccessTools.Method(typeof(BaseAI), "SetPatrolPoint", new Type[1] { typeof(Vector3) }, (Type[])null), (object)null, true);

		private static readonly FieldRef<MonsterAI, Character> Target = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature");

		private static readonly Action<VisEquipment> RefreshBody = AccessTools.MethodDelegate<Action<VisEquipment>>(AccessTools.Method(typeof(VisEquipment), "UpdateBaseModel", (Type[])null, (Type[])null), (object)null, true);

		private static readonly int ModelIndexKey = (int)AccessTools.Field(AccessTools.TypeByName("ZDOVars"), "s_modelIndex").GetValue(null);

		private static readonly FieldRef<Humanoid, ItemData> HiddenRight = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_hiddenRightItem");

		private static readonly FieldRef<Humanoid, ItemData> HiddenLeft = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_hiddenLeftItem");

		internal ZNetView View;

		internal Humanoid Human;

		internal MonsterAI AI;

		internal NpcDefinition Definition;

		internal ItemData Weapon;

		internal ItemData Arrow;

		internal AppearanceRecord Look;

		private ItemData shield;

		private ItemData peace;

		private ItemData torch;

		private VisEquipment visuals;

		private ZSyncAnimation animationSync;

		private Animator animator;

		private uint random;

		private uint identity;

		private float timer;

		private float workTimer;

		private int equipmentMode = -1;

		private bool initialized;

		private bool wasOwner;

		private bool canWork;

		private bool inventoryBuilt;

		private string workTrigger;

		private bool hadDanger;

		private static readonly NpcSpeechGate SpeechGate = new NpcSpeechGate();

		private static ZNet speechWorld;

		private static readonly Func<ZRoutedRpc, long> GetServer = AccessTools.MethodDelegate<Func<ZRoutedRpc, long>>(AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null), (object)null, true);

		private readonly FarmerClock bathClock = new FarmerClock();

		private Vector3 bathDestination;

		private float bathRetry;

		private bool bathDanger;

		internal Vector3 Home => View.GetZDO().GetVec3("PrimeNPC_home", ((Component)this).transform.position);

		private CivilianActivity ActivitySettings
		{
			get
			{
				if (Profession != "PrimeFarmer")
				{
					return Definition?.Activity;
				}
				farmerSettings.Enabled = PrimeSwampNPCsPlugin.FarmerActivityEnabled.Value;
				farmerSettings.Radius = PrimeSwampNPCsPlugin.FarmerWorkRadius.Value;
				farmerSettings.MinimumTravelDistance = PrimeSwampNPCsPlugin.FarmerTravelMinimum.Value;
				farmerSettings.WalkTimeoutSeconds = PrimeSwampNPCsPlugin.FarmerWalkTimeout.Value;
				farmerSettings.IdleMinimumSeconds = PrimeSwampNPCsPlugin.FarmerIdleMinimum.Value;
				farmerSettings.IdleMaximumSeconds = PrimeSwampNPCsPlugin.FarmerIdleMaximum.Value;
				farmerSettings.WorkMinimumSeconds = PrimeSwampNPCsPlugin.FarmerWorkMinimum.Value;
				farmerSettings.WorkMaximumSeconds = PrimeSwampNPCsPlugin.FarmerWorkMaximum.Value;
				farmerSettings.WorkChance = PrimeSwampNPCsPlugin.FarmerWorkChance.Value;
				farmerSettings.MaximumWaterDepth = PrimeSwampNPCsPlugin.FarmerWaterDepth.Value;
				return farmerSettings;
			}
		}

		internal bool OwnsFarmerMovement
		{
			get
			{
				if (NpcCivilianPolicy.Supported(Profession) && initialized && Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner() && ActivitySettings != null && ActivitySettings.Enabled && !((Character)Human).IsDead() && !InCombat && !fleeing)
				{
					return !returning;
				}
				return false;
			}
		}

		internal bool CosmeticFarmEvent
		{
			get
			{
				if (NpcCivilianPolicy.Supported(Profession) && !InCombat)
				{
					if (farmClock.Phase != FarmerPhase.Working)
					{
						return Time.time < farmPoseSafetyUntil;
					}
					return true;
				}
				return false;
			}
		}

		internal bool Angry
		{
			get
			{
				if (Object.op_Implicit((Object)(object)AI))
				{
					return ((BaseAI)AI).IsAggravated();
				}
				return false;
			}
		}

		internal static long Now
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return 0L;
				}
				return ZNet.instance.GetTime().Ticks;
			}
		}

		internal bool InCombat
		{
			get
			{
				if (Object.op_Implicit((Object)(object)View) && View.IsValid())
				{
					if (!View.IsOwner())
					{
						return View.GetZDO().GetBool("PrimeNPC_combat", false);
					}
					if (!fleeing && Object.op_Implicit((Object)(object)AI))
					{
						return Object.op_Implicit((Object)(object)((BaseAI)AI).GetTargetCreature());
					}
					return false;
				}
				return false;
			}
		}

		private static long ServerPeer => GetServer(ZRoutedRpc.instance);

		internal bool OwnsSwimmerMovement
		{
			get
			{
				if (Profession == "PrimeSwimmer" && initialized && Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner())
				{
					return !((Character)Human).IsDead();
				}
				return false;
			}
		}

		private unsafe void AuditAppearance()
		{
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0551: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fc: 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_0479: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || !View.IsOwner())
			{
				return;
			}
			if (PrimeSwampNPCsPlugin.AppearanceDiagnostics.Value)
			{
				PrimeSwampNPCsPlugin.Log("APPEARANCE_STATE " + Profession + " model=" + Look.Gender + " clothing=" + string.Join(",", Look.Armor) + " work=" + Look.Peace + " right=" + (Object.op_Implicit((Object)(object)Human.RightItem?.m_dropPrefab) ? ((Object)Human.RightItem.m_dropPrefab).name : "none"));
			}
			if (PrimeSwampNPCsPlugin.AppearanceDiagnostics.Value)
			{
				string text = Array.Find(Look.Armor, NpcClothingPolicy.LegItem) ?? "";
				int num = ((!(text == "")) ? StringExtensionMethods.GetStableHashCode(text) : 0);
				PrimeSwampNPCsPlugin.Log("APPEARANCE_LEG_HASH " + Profession + " expected=" + num + " rendered=" + RenderedLegHash.Invoke(visuals) + " match=" + (num == RenderedLegHash.Invoke(visuals)));
			}
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>();
			foreach (Renderer val in componentsInChildren)
			{
				if ((!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) || !val.enabled || !((Component)val).gameObject.activeInHierarchy)
				{
					continue;
				}
				string text2 = ((Object)val).name;
				Transform parent = ((Component)val).transform.parent;
				while (Object.op_Implicit((Object)(object)parent) && (Object)(object)parent != (Object)(object)((Component)this).transform)
				{
					text2 = ((Object)parent).name + "/" + text2;
					parent = parent.parent;
				}
				Bounds bounds;
				Vector3 val7;
				if (PrimeSwampNPCsPlugin.AppearanceDiagnostics.Value)
				{
					if (((Object)val).name == "body")
					{
						Material[] sharedMaterials = val.sharedMaterials;
						foreach (Material val2 in sharedMaterials)
						{
							if (Object.op_Implicit((Object)(object)val2) && val2.HasProperty("_LegsTex"))
							{
								string text3 = Array.Find(Look.Armor, NpcClothingPolicy.LegItem) ?? "";
								object obj2;
								if (!(text3 == ""))
								{
									GameObject obj = NpcFactory.Find(text3);
									obj2 = ((obj == null) ? null : obj.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_armorMaterial);
								}
								else
								{
									obj2 = null;
								}
								Material val3 = (Material)obj2;
								Texture val4 = ((Object.op_Implicit((Object)(object)val3) && val3.HasProperty("_LegsTex")) ? val3.GetTexture("_LegsTex") : null);
								Texture texture = val2.GetTexture("_LegsTex");
								PrimeSwampNPCsPlugin.Log("APPEARANCE_LEG_TEXTURE " + Profession + " source=" + (Object.op_Implicit((Object)(object)val4) ? ((Object)val4).name : "none") + " body=" + (Object.op_Implicit((Object)(object)texture) ? ((Object)texture).name : "none") + " match=" + ((Object)(object)val4 == (Object)(object)texture));
							}
						}
					}
					int num2 = 0;
					SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
					if (val5 != null)
					{
						Transform[] bones = val5.bones;
						foreach (Transform val6 in bones)
						{
							if (Object.op_Implicit((Object)(object)val6) && !val6.IsChildOf(((Component)this).transform))
							{
								num2++;
							}
						}
					}
					string[] obj3 = new string[10] { "APPEARANCE_MESH ", Profession, " mesh=", text2, " bounds=", null, null, null, null, null };
					bounds = val.bounds;
					obj3[5] = ((object)(*(Bounds*)(&bounds))/*cast due to .constrained prefix*/).ToString();
					obj3[6] = " scale=";
					val7 = ((Component)val).transform.lossyScale;
					obj3[7] = ((object)(*(Vector3*)(&val7))/*cast due to .constrained prefix*/).ToString();
					obj3[8] = " foreignBones=";
					obj3[9] = num2.ToString();
					PrimeSwampNPCsPlugin.Log(string.Concat(obj3));
				}
				bounds = val.bounds;
				val7 = ((Bounds)(ref bounds)).extents;
				if (((Vector3)(ref val7)).magnitude <= 6f)
				{
					bounds = val.bounds;
					if (Vector3.Distance(((Bounds)(ref bounds)).center, ((Component)this).transform.position) <= 6f)
					{
						continue;
					}
				}
				string[] obj4 = new string[10] { "APPEARANCE_OUTLIER ", Profession, " mesh=", text2, " bounds=", null, null, null, null, null };
				bounds = val.bounds;
				obj4[5] = ((object)(*(Bounds*)(&bounds))/*cast due to .constrained prefix*/).ToString();
				obj4[6] = " work=";
				obj4[7] = Look.Peace;
				obj4[8] = " chest/legs=";
				obj4[9] = string.Join(",", Look.Armor);
				PrimeSwampNPCsPlugin.Warn(string.Concat(obj4));
			}
		}

		internal bool RemembersOffender(Character other)
		{
			if (Object.op_Implicit((Object)(object)other) && other.IsPlayer() && Object.op_Implicit((Object)(object)AI))
			{
				return ((BaseAI)AI).IsAggravated();
			}
			return false;
		}

		internal bool IsAngryAt(Character other)
		{
			return RemembersOffender(other);
		}

		private bool Provoked(Character other)
		{
			//IL_0018: 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)
			if (Object.op_Implicit((Object)(object)other) && View.GetZDO().GetZDOID("PrimeNPC_threat") == other.GetZDOID())
			{
				return View.GetZDO().GetLong("PrimeNPC_threatUntil", 0L) > Now;
			}
			return false;
		}

		internal static bool Livestock(Character c)
		{
			if (Object.op_Implicit((Object)(object)c) && !c.IsPlayer() && !Object.op_Implicit((Object)(object)((Component)c).GetComponent<NpcRuntime>()))
			{
				return c.IsTamed();
			}
			return false;
		}

		private bool ImmediateThreat(Character enemy)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			Character val = (Object.op_Implicit((Object)(object)enemy.GetBaseAI()) ? enemy.GetBaseAI().GetTargetCreature() : null);
			if (Object.op_Implicit((Object)(object)val) && !val.IsDead() && ((Object)(object)val == (Object)(object)Human || Object.op_Implicit((Object)(object)((Component)val).GetComponent<NpcRuntime>()) || Livestock(val)))
			{
				Vector3 val2 = ((Component)val).transform.position - ((Component)enemy).transform.position;
				return ((Vector3)(ref val2)).sqrMagnitude <= Definition.ThreatRadius * Definition.ThreatRadius;
			}
			return false;
		}

		private bool Allowed(Character target)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_00cf: 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)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)target) || target.IsDead() || target.GetHealth() <= 0f || (Object)(object)target == (Object)(object)Human || !PriestAltarSafe(((Component)this).transform.position) || !PriestTargetSafe(target))
			{
				return false;
			}
			if ((NpcCivilianPolicy.Additional(Profession) || Profession == "PrimeWarrior" || Profession == "PrimeSwimmer") && (int)target.GetFaction() == 1 && !Provoked(target) && !ImmediateThreat(target))
			{
				return false;
			}
			return NpcBehaviorPolicy.Defend(BaseAI.IsEnemy((Character)(object)Human, target), Provoked(target), ImmediateThreat(target), NpcBehaviorPolicy.Proactive(Profession), target.IsPlayer(), IsAngryAt(target), Vector3.Distance(((Component)this).transform.position, Home), Vector3.Distance(((Component)target).transform.position, Home), Definition.DefenseRadius);
		}

		internal void UpdateDefensiveTarget(float dt, out bool see, out bool hear)
		{
			//IL_0068: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			see = (hear = false);
			if (!initialized || !View.IsOwner() || ((Character)Human).IsDead())
			{
				Target.Invoke(AI) = null;
				return;
			}
			StaticTargetField.Invoke(AI) = null;
			if (Profession == "PrimePriest" && !PriestAltarSafe(((Component)this).transform.position))
			{
				Target.Invoke(AI) = null;
				returning = true;
			}
			Character targetCreature = ((BaseAI)AI).GetTargetCreature();
			if (Object.op_Implicit((Object)(object)targetCreature) && !Allowed(targetCreature))
			{
				Target.Invoke(AI) = null;
				returning = true;
			}
			threatScan -= dt;
			if (!Object.op_Implicit((Object)(object)((BaseAI)AI).GetTargetCreature()) && threatScan <= 0f)
			{
				threatScan = 1f;
				candidates.Clear();
				Character.GetCharactersInRange(Home, Definition.DefenseRadius, candidates);
				Character val = null;
				float num = float.MaxValue;
				foreach (Character candidate in candidates)
				{
					if (Allowed(candidate) && (((BaseAI)AI).CanSeeTarget(candidate) || ((BaseAI)AI).CanHearTarget(candidate)))
					{
						Vector3 val2 = ((Component)candidate).transform.position - ((Component)this).transform.position;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num)
						{
							num = sqrMagnitude;
							val = candidate;
						}
					}
				}
				if (Object.op_Implicit((Object)(object)val))
				{
					SetTarget(AI, val);
					returning = false;
					if (ImmediateThreat(val) && !Provoked(val))
					{
						View.GetZDO().Set("PrimeNPC_threat", val.GetZDOID());
						View.GetZDO().Set("PrimeNPC_threatUntil", Now + 150000000);
					}
				}
			}
			targetCreature = ((BaseAI)AI).GetTargetCreature();
			if (Weapon != null && NpcProfessionPolicy.ContactWeapon(Profession, Look.Weapon))
			{
				Weapon.m_shared.m_aiAttackRange = ((Object.op_Implicit((Object)(object)targetCreature) && targetCreature.IsPlayer()) ? NpcCivilianPolicy.ContactRange(Look.Weapon, Weapon.m_shared.m_attack.m_attackRange) : 2f);
			}
			if (Object.op_Implicit((Object)(object)targetCreature))
			{
				see = ((BaseAI)AI).CanSeeTarget(targetCreature);
				hear = ((BaseAI)AI).CanHearTarget(targetCreature);
				danger = targetCreature;
				if (see | hear)
				{
					SetAlert(AI, arg2: true);
				}
			}
			else if (!fleeing)
			{
				SetAlert(AI, arg2: false);
			}
			fleeing = NpcBehaviorPolicy.Flee(Profession, ((Character)Human).GetHealthPercentage(), Definition.RetreatHealthFraction, Object.op_Implicit((Object)(object)targetCreature) || (Object.op_Implicit((Object)(object)danger) && Provoked(danger)));
			if (fleeing)
			{
				Target.Invoke(AI) = null;
				see = (hear = false);
			}
			if (InCombat || fleeing || returning)
			{
				InterruptFarmerRoutine();
			}
			Equip(InCombat);
		}

		internal void OverrideDefensiveMovement(float dt)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || !View.IsOwner() || ((Character)Human).IsDead() || Profession == "PrimeSwimmer")
			{
				return;
			}
			Vector3 val = ((Component)this).transform.position - Home;
			if (((Vector3)(ref val)).sqrMagnitude > Definition.DefenseRadius * Definition.DefenseRadius)
			{
				Target.Invoke(AI) = null;
				returning = true;
			}
			if (fleeing && Object.op_Implicit((Object)(object)danger) && Provoked(danger))
			{
				Equip(combat: false);
				if (Vector3.Distance(((Component)this).transform.position, Home) > 3f || Vector3.Distance(((Component)danger).transform.position, Home) > 5f)
				{
					MoveHome((BaseAI)(object)AI, dt, Home, 2f, arg5: true);
				}
				else if (Vector3.Distance(((Component)this).transform.position, Home) < Definition.DefenseRadius - 3f)
				{
					RunAway((BaseAI)(object)AI, dt, ((Component)danger).transform.position);
				}
				else
				{
					MoveHome((BaseAI)(object)AI, dt, Home, 2f, arg5: true);
				}
			}
			else if (returning && MoveHome((BaseAI)(object)AI, dt, Home, 2f, arg5: true))
			{
				returning = false;
			}
		}

		internal void DamageAccepted(Character attacker)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)attacker) && Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner() && !((Character)Human).IsDead() && !attacker.IsPlayer())
			{
				AlertNearby(((Component)this).transform.position, attacker, View.GetZDO().GetString("PrimeNPC_settlement", ""));
			}
		}

		private void NativeDeath()
		{
			InterruptFarmerRoutine(broadcast: false);
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner())
			{
				View.GetZDO().Set("PrimeNPC_dead", true);
			}
			Instances.Remove(this);
			((Behaviour)this).enabled = false;
		}

		private void ResetFarmerRoutine()
		{
			if (NpcCivilianPolicy.Supported(Profession))
			{
				InterruptFarmerRoutine();
				farmRetry = 0f;
			}
		}

		private void RestoreFarmAgent()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (farmAgentChanged && Object.op_Implicit((Object)(object)AI))
			{
				((BaseAI)AI).m_pathAgentType = originalFarmAgent;
				LastFarmPath.Invoke((BaseAI)(object)AI) = -1000f;
				farmAgentChanged = false;
			}
		}

		private void InterruptFarmerRoutine(bool broadcast = true)
		{
			if (NpcCivilianPolicy.Supported(Profession))
			{
				bool num = farmClock.Phase == FarmerPhase.Working;
				farmClock.Advance(0f, danger: true, arrived: false, 0f, 0f, workOpportunity: false);
				RestoreFarmAgent();
				if (num)
				{
					CancelFarmPose(broadcast);
				}
			}
		}

		private void CancelFarmPose(bool broadcast)
		{
			farmPoseSafetyUntil = Time.time + 2f;
			ClearFarmPose();
			if (broadcast && Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner())
			{
				View.InvokeRPC(ZNetView.Everybody, "PrimeNPC_CancelFarmPose", Array.Empty<object>());
			}
		}

		private void OnCancelFarmPose(long sender)
		{
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && sender == View.GetZDO().GetOwner())
			{
				farmPoseSafetyUntil = Time.time + 2f;
				ClearFarmPose();
			}
		}

		private void ClearFarmPose()
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)animator))
			{
				return;
			}
			if (Profession == "PrimeFarmer")
			{
				animator.ResetTrigger("swing_hoe");
				animator.ResetTrigger("scything");
			}
			else
			{
				animator.ResetTrigger("swing_hammer");
				animator.ResetTrigger("fishingrod_throw");
			}
			AnimatorStateInfo currentAnimatorStateInfo;
			if (NpcCivilianPolicy.Additional(Profession))
			{
				animator.ResetTrigger(workTrigger);
				if (Profession == "PrimeWitch")
				{
					currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Base Layer.fireball_to_idle"))
					{
						animator.Play("Base Layer.Movement", 0, 0f);
					}
				}
				string text = NpcProfessionPolicy.WorkState(Profession);
				if (!string.IsNullOrEmpty(text))
				{
					currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName(text))
					{
						animator.Play("Base Layer.Movement", 0, 0f);
					}
				}
			}
			if (Profession == "PrimeWarrior")
			{
				animator.ResetTrigger("emote_point");
				currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
				if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Base Layer.Emotes.Emote_point"))
				{
					animator.Play("Base Layer.Movement", 0, 0f);
				}
			}
			if (CurrentAttack.Invoke(Human) != null && !CurrentAttack.Invoke(Human).IsDone())
			{
				return;
			}
			currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
			if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Base Layer.Scything"))
			{
				animator.Play("Base Layer.Movement", 0, 0f);
			}
			int layerIndex = animator.GetLayerIndex("upperbody");
			if (Profession != "PrimeFarmer")
			{
				currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
				if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Base Layer.Fishing throw"))
				{
					animator.Play("Base Layer.Movement", 0, 0f);
				}
			}
			if (layerIndex < 0)
			{
				return;
			}
			currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(layerIndex);
			if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("upperbody.swing_hoe"))
			{
				if (!(Profession == "PrimeCommoner") && !(Profession == "PrimeSculptor"))
				{
					return;
				}
				currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(layerIndex);
				if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("upperbody.swing_hammer"))
				{
					return;
				}
			}
			animator.Play("upperbody.None", layerIndex, 0f);
		}

		internal void UpdateFarmerActivity(float dt)
		{
			//IL_008b: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: 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_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_049c: Unknown result type (might be due to invalid IL or missing references)
			if (!NpcCivilianPolicy.Supported(Profession))
			{
				return;
			}
			if (!OwnsFarmerMovement)
			{
				InterruptFarmerRoutine();
				return;
			}
			CivilianActivity activitySettings = ActivitySettings;
			if (!farmAgentChanged)
			{
				originalFarmAgent = ((BaseAI)AI).m_pathAgentType;
				((BaseAI)AI).m_pathAgentType = (AgentType)5;
				LastFarmPath.Invoke((BaseAI)(object)AI) = -1000f;
				farmAgentChanged = true;
			}
			Equip(combat: false);
			float num = NpcFarmerPolicy.Radius(activitySettings.Radius, Definition.DefenseRadius);
			Vector3 val = ((Component)this).transform.position - Home;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude > num * num)
			{
				CancelIfWorking();
				farmClock.BeginWalk(activitySettings.WalkTimeoutSeconds);
				farmDestination = Home;
			}
			bool flag = false;
			if (farmClock.Phase == FarmerPhase.Walking)
			{
				flag = MoveHome((BaseAI)(object)AI, dt, farmDestination, 0.7f, arg5: false);
			}
			else
			{
				FarmStop((BaseAI)(object)AI);
			}
			if (flag && activitySettings.Mode == "Fishing")
			{
				civilianShore = FindCivilianShore(((Component)this).transform.position, activitySettings, out civilianWaterFacing);
			}
			FarmerPhase phase = farmClock.Phase;
			float pause = ((phase == FarmerPhase.Walking && flag) ? FarmDuration(activitySettings.IdleMinimumSeconds, activitySettings.IdleMaximumSeconds) : 0f);
			bool flag2 = phase == FarmerPhase.Pausing && farmClock.Remaining <= dt && canWork && Object.op_Implicit((Object)(object)animationSync) && NpcCivilianPolicy.CanWork(activitySettings.Mode, civilianShore) && ((Character)Human).IsOnGround() && !((Character)Human).IsSwimming() && NpcPolicy.Unit(ref random) < (double)activitySettings.WorkChance;
			farmClock.Advance(dt, danger: false, flag, pause, flag2 ? FarmDuration(activitySettings.WorkMinimumSeconds, activitySettings.WorkMaximumSeconds) : 0f, flag2);
			if (phase == FarmerPhase.Working && farmClock.Phase != phase)
			{
				CancelFarmPose(broadcast: true);
			}
			if (farmClock.Phase == FarmerPhase.Working)
			{
				if (activitySettings.Mode == "Fishing" && civilianShore)
				{
					((Character)Human).SetLookDir(civilianWaterFacing, 0f);
				}
				farmPoseTimer -= dt;
				if (phase != FarmerPhase.Working)
				{
					farmPoseTimer = 0f;
				}
				if (farmPoseTimer <= 0f && canWork && Object.op_Implicit((Object)(object)animationSync) && NpcCivilianPolicy.CanWork(activitySettings.Mode, civilianShore) && ((Character)Human).IsOnGround() && !((Character)Human).IsSwimming() && !((Character)Human).InAttack())
				{
					bool num2;
					if (!(Profession == "PrimeFarmer"))
					{
						num2 = workTrigger == NpcCivilianPolicy.WorkTrigger(activitySettings.Mode, Look.Peace);
					}
					else
					{
						if (workTrigger == "swing_hoe")
						{
							goto IL_0365;
						}
						num2 = workTrigger == "scything";
					}
					if (num2)
					{
						goto IL_0365;
					}
				}
			}
			goto IL_0392;
			IL_0392:
			if (farmClock.Phase != FarmerPhase.Seeking)
			{
				return;
			}
			farmRetry -= dt;
			if (farmRetry > 0f)
			{
				return;
			}
			farmRetry = 3f;
			bool flag3 = activitySettings.Mode == "Fishing" && NpcPolicy.Unit(ref random) < (double)activitySettings.ShoreChance;
			for (int i = 0; i < 4; i++)
			{
				NpcFarmerPolicy.Destination(ref random, num, out var x, out var z);
				Vector3 point = Home + new Vector3(x, 0f, z);
				Vector3 val2 = point - ((Component)this).transform.position;
				val2.y = 0f;
				if (!(((Vector3)(ref val2)).magnitude < activitySettings.MinimumTravelDistance) && FarmDestinationSafe(ref point))
				{
					bool flag4 = activitySettings.Mode == "Fishing" && FindCivilianShore(point, activitySettings, out civilianWaterFacing);
					if (!flag3 || flag4 || i >= 3)
					{
						civilianShore = flag4;
						farmDestination = point;
						farmClock.BeginWalk(activitySettings.WalkTimeoutSeconds);
						break;
					}
				}
			}
			return;
			IL_0365:
			farmPoseSafetyUntil = Time.time + 2f;
			animationSync.SetTrigger(workTrigger);
			farmPoseTimer = 3f;
			goto IL_0392;
		}

		private void CancelIfWorking()
		{
			if (farmClock.Phase == FarmerPhase.Working)
			{
				CancelFarmPose(broadcast: true);
			}
		}

		private float FarmDuration(float minimum, float maximum)
		{
			return minimum + (float)NpcPolicy.Unit(ref random) * Mathf.Max(0f, maximum - minimum);
		}

		private bool FarmDestinationSafe(ref Vector3 point)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || !Object.op_Implicit((Object)(object)Heightmap.FindHeightmap(point)) || !PriestAltarSafe(point))
			{
				return false;
			}
			point.y = ZoneSystem.instance.GetGroundHeight(point);
			int mask = LayerMask.GetMask(new string[1] { "terrain" });
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(point + Vector3.up * 2f, Vector3.down, ref val, 4f, mask))
			{
				return false;
			}
			int mask2 = LayerMask.GetMask(new string[2] { "static_solid", "piece" });
			bool clear = !Physics.CheckCapsule(point + Vector3.up * 0.5f, point + Vector3.up * 1.5f, 0.3f, mask2, (QueryTriggerInteraction)1);
			if (!NpcFarmerPolicy.SafeGround(point.y, ZoneSystem.instance.m_waterLevel, ActivitySettings.MaximumWaterDepth, Vector3.Angle(((RaycastHit)(ref val)).normal, Vector3.up), clear, reachable: true))
			{
				return false;
			}
			return FarmHavePath((BaseAI)(object)AI, point);
		}

		private bool PriestTargetSafe(Character target)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (Profession != "PrimePriest")
			{
				return true;
			}
			string name = ((Object)((Component)target).gameObject).name;
			if (target.m_boss && (name == "Bonemass" || name == "Bonemass(Clone)"))
			{
				return false;
			}
			return PriestAltarSafe(((Component)target).transform.position);
		}

		private bool PriestAltarSafe(Vector3 point)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (Profession != "PrimePriest" || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return true;
			}
			if ((Object)(object)priestAltarWorld != (Object)(object)ZoneSystem.instance)
			{
				priestAltarWorld = ZoneSystem.instance;
				priestAltars.Clear();
				foreach (LocationInstance value in ZoneSystem.instance.m_locationInstances.Values)
				{
					string text = value.m_location.m_prefabName;
					if (string.IsNullOrEmpty(text))
					{
						text = value.m_location.m_name;
					}
					if (text == "Bonemass")
					{
						priestAltars.Add(value.m_position);
					}
				}
			}
			foreach (Vector3 priestAltar in priestAltars)
			{
				if (!NpcProfessionPolicy.AltarSafe(point.x - priestAltar.x, point.z - priestAltar.z))
				{
					return false;
				}
			}
			return true;
		}

		private bool FindCivilianShore(Vector3 standing, CivilianActivity settings, out Vector3 facing)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			facing = Vector3.zero;
			if (!Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return false;
			}
			float waterLevel = ZoneSystem.instance.m_waterLevel;
			int mask = LayerMask.GetMask(new string[3] { "terrain", "static_solid", "piece" });
			Vector3 val = default(Vector3);
			Vector3 val3 = default(Vector3);
			for (int i = 0; i < 8; i++)
			{
				float num = (float)i * MathF.PI / 4f;
				((Vector3)(ref val))..ctor(Mathf.Cos(num), 0f, Mathf.Sin(num));
				for (int j = 1; j <= 2; j++)
				{
					float num2 = settings.ShoreSearchDistance * (float)j / 2f;
					Vector3 val2 = standing + val * num2;
					if (Object.op_Implicit((Object)(object)Heightmap.FindHeightmap(val2)))
					{
						float groundHeight = ZoneSystem.instance.GetGroundHeight(val2);
						((Vector3)(ref val3))..ctor(val2.x, waterLevel + 0.3f, val2.z);
						if (NpcCivilianPolicy.ShoreWater(clear: !Physics.Linecast(standing + Vector3.up * 1.4f, val3, mask, (QueryTriggerInteraction)1), ground: groundHeight, water: waterLevel, distance: num2, searchDistance: settings.ShoreSearchDistance, loaded: true))
						{
							facing = val;
							return true;
						}
					}
				}
			}
			return false;
		}

		internal void EnsurePlayerMelee(float dt)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || !View.IsOwner() || !InCombat || ((Character)Human).IsDead() || !NpcProfessionPolicy.ContactWeapon(Profession, Look.Weapon))
			{
				playerContactWait = 0f;
				return;
			}
			Character targetCreature = ((BaseAI)AI).GetTargetCreature();
			if (!Object.op_Implicit((Object)(object)targetCreature) || !targetCreature.IsPlayer() || !Allowed(targetCreature))
			{
				playerContactWait = 0f;
				return;
			}
			float reach = NpcMeleePolicy.ContactRange(Weapon.m_shared.m_attack.m_attackRange);
			Collider component = ((Component)targetCreature).GetComponent<Collider>();
			float contactDistance = (Object.op_Implicit((Object)(object)component) ? Vector3.Distance(((Character)Human).GetCenterPoint(), component.ClosestPoint(((Character)Human).GetCenterPoint())) : Vector3.Distance(((Component)Human).transform.position, ((Component)targetCreature).transform.position));
			Attack val = CurrentAttack.Invoke(Human);
			if (!NpcMeleePolicy.Ready(authorizedPlayer: true, ((Character)Human).InAttack() || (val != null && !val.IsDone()), ((BaseAI)AI).CanSeeTarget(targetCreature), contactDistance, reach, Time.time - Weapon.m_lastAttackTime, Weapon.m_shared.m_aiAttackInterval))
			{
				playerContactWait = 0f;
				return;
			}
			playerContactWait += dt;
			if (!(playerContactWait < 1f))
			{
				playerContactWait = 0f;
				((BaseAI)AI).StopMoving();
				Vector3 val2 = targetCreature.GetCenterPoint() - ((Character)Human).GetCenterPoint();
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.001f)
				{
					((Character)Human).SetLookDir(((Vector3)(ref val2)).normalized, 0f);
				}
				if (((Character)Human).StartAttack(targetCreature, false))
				{
					PrimeSwampNPCsPlugin.Log(Profession + ": native player melee started at contact distance " + contactDistance.ToString("F2"));
				}
			}
		}

		private void RegisterReactions()
		{
			View.Register<ZDOID, ZDOID>("PrimeNPC_WitnessDamage", (Action<long, ZDOID, ZDOID>)OnWitnessDamage);
			View.Register<int, ZDOID, Vector3>("PrimeNPC_RequestReaction", (Action<long, int, ZDOID, Vector3>)OnReactionRequest);
			View.Register<int, string>("PrimeNPC_Reaction", (Action<long, int, string>)OnReaction);
		}

		private static Character ReactionActor(ZDOID id)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.GetComponent<Character>();
		}

		private void OnWitnessDamage(long sender, ZDOID playerId, ZDOID pieceId)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_010d: 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)
			if (!Object.op_Implicit((Object)(object)View) || !View.IsValid() || !View.IsOwner() || !initialized || ((Character)Human).IsDead() || InCombat || fleeing || Now < nextWitnessRequest)
			{
				return;
			}
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(pieceId) : null);
			Character val2 = ReactionActor(playerId);
			if (val != null && val.GetOwner() == sender && Object.op_Implicit((Object)(object)val2) && val2.IsPlayer() && !val2.IsDead() && SettlementWitness.Property(val.GetPosition()))
			{
				Vector3 val3 = val.GetPosition() - ((Component)this).transform.position;
				if (!(((Vector3)(ref val3)).sqrMagnitude > 400f) && ((BaseAI)AI).CanSeeTarget(val2))
				{
					nextWitnessRequest = Now + 20000000;
					View.InvokeRPC(ServerPeer, "PrimeNPC_RequestReaction", new object[3]
					{
						1,
						pieceId,
						val.GetPosition()
					});
				}
			}
		}

		private void TryCombatReaction()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			Character targetCreature = ((BaseAI)AI).GetTargetCreature();
			if (!NpcReactionPolicy.Combat(Object.op_Implicit((Object)(object)targetCreature) && targetCreature.IsPlayer(), ((BaseAI)AI).IsAggravated(), InCombat, fleeing))
			{
				playerCombat = false;
				return;
			}
			bool flag = !playerCombat;
			playerCombat = true;
			if (flag || Now >= nextCombatReaction)
			{
				if (reactionRandom == 0)
				{
					reactionRandom = identity ^ 0xB5297A4Du;
				}
				nextCombatReaction = Now + (long)((18.0 + NpcPolicy.Unit(ref reactionRandom) * 12.0) * 10000000.0);
				if (flag || NpcPolicy.Unit(ref reactionRandom) < 0.45)
				{
					View.InvokeRPC(ServerPeer, "PrimeNPC_RequestReaction", new object[3]
					{
						2,
						targetCreature.GetZDOID(),
						Vector3.zero
					});
				}
			}
		}

		private void OnReactionRequest(long sender, int kind, ZDOID context, Vector3 point)
		{
			//IL_00e5: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || sender != View.GetZDO().GetOwner() || ((Character)Human).IsDead() || (kind != 1 && kind != 2))
			{
				return;
			}
			ZDO zDO = View.GetZDO();
			long now = Now;
			if (!NpcReactionPolicy.Cooldown(now, zDO.GetLong("PrimeNPC_nextReaction", 0L)))
			{
				return;
			}
			if (kind == 1)
			{
				if (InCombat || float.IsNaN(point.x) || float.IsNaN(point.y) || float.IsNaN(point.z))
				{
					return;
				}
				Vector3 val = point - ((Component)this).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude > 400f || !SettlementWitness.Property(point))
				{
					return;
				}
			}
			else
			{
				Character val2 = ReactionActor(context);
				if (!Object.op_Implicit((Object)(object)val2) || !val2.IsPlayer() || val2.IsDead() || !zDO.GetBool(AggravatedKey, false) || !InCombat)
				{
					return;
				}
			}
			if ((Object)(object)speechWorld != (Object)(object)ZNet.instance)
			{
				SpeechGate.Clear();
				speechWorld = ZNet.instance;
			}
			if (SpeechGate.TryReserve(((Component)this).transform.position.x, ((Component)this).transform.position.z, (double)now / 10000000.0, 8.0, 20.0))
			{
				uint seed = (uint)(((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).GetHashCode() ^ (int)(now / 10000000));
				string text = NpcReactionPolicy.Choose(Profession, kind, zDO.GetString("PrimeNPC_lastReaction", ""), ref seed);
				zDO.Set("PrimeNPC_lastReaction", text);
				zDO.Set("PrimeNPC_nextReaction", now + 200000000);
				View.InvokeRPC(ZNetView.Everybody, "PrimeNPC_Reaction", new object[2] { kind, text });
			}
		}

		private void OnReaction(long sender, int kind, string text)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && sender == ServerPeer && Object.op_Implicit((Object)(object)Chat.instance) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && (kind == 1 || kind == 2) && !((Character)Human).IsDead())
			{
				Vector3 val = ((Component)Player.m_localPlayer).transform.position - ((Component)this).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 400f))
				{
					Chat.instance.SetNpcText(((Component)this).gameObject, new Vector3(0f, 2.1f, 0f), 20f, 5f, Definition.DisplayName, text, false);
				}
			}
		}

		private void Start()
		{
			View = ((Component)this).GetComponent<ZNetView>();
			Human = ((Component)this).GetComponent<Humanoid>();
			AI = ((Component)this).GetComponent<MonsterAI>();
			visuals = ((Component)this).GetComponent<VisEquipment>();
			animationSync = ((Component)this).GetComponent<ZSyncAnimation>();
			animator = ((Component)this).GetComponentInChildren<Animator>();
			if (!PrimeSwampNPCsPlugin.Definitions.TryGetValue(Profession, out Definition) || !Object.op_Implicit((Object)(object)View) || !Object.op_Implicit((Object)(object)Human) || !Object.op_Implicit((Object)(object)AI))
			{
				((Behaviour)this).enabled = false;
				return;
			}
			View.Register<ZDOID>("PrimeNPC_Provoked", (Action<long, ZDOID>)OnProvoked);
			View.Register<string>("PrimeNPC_Speech", (Action<long, string>)OnSpeech);
			View.Register<string>("PrimeNPC_RequestSpeech", (Action<long, string>)OnSpeechRequest);
			if (NpcCivilianPolicy.Supported(Profession))
			{
				View.Register("PrimeNPC_CancelFarmPose", (Action<long>)OnCancelFarmPose);
			}
			Humanoid human = Human;
			((Character)human).m_onDeath = (Action)Delegate.Combine(((Character)human).m_onDeath, new Action(NativeDeath));
			RegisterReactions();
			Instances.Add(this);
		}

		private void Update()
		{
			timer -= Time.deltaTime;
			if (timer > 0f || !Object.op_Implicit((Object)(object)View) || !View.IsValid())
			{
				return;
			}
			timer = 0.25f;
			if (!initialized && !Initialize())
			{
				return;
			}
			bool flag = View.IsOwner();
			if (flag && !inventoryBuilt)
			{
				initialized = false;
				if (!Initialize())
				{
					return;
				}
			}
			if (flag && !wasOwner)
			{
				ApplyAppearance();
				equipmentMode = -1;
				ResetFarmerRoutine();
				ResetSwimmerRoutine();
			}
			wasOwner = flag;
			if (!flag || ((Character)Human).IsDead() || ((Character)Human).GetHealth() <= 0f)
			{
				return;
			}
			Equip(InCombat);
			TryCombatReaction();
			if (hadDanger && !InCombat && !fleeing)
			{
				View.GetZDO().Set("PrimeNPC_recentDanger", Now + 900000000);
			}
			hadDanger = InCombat || fleeing;
			if (!InCombat)
			{
				TrySpeech();
				TryWork();
			}
			if (appearanceAudit >= 0f)
			{
				appearanceAudit -= 0.25f;
				if (appearanceAudit < 0f)
				{
					AuditAppearance();
				}
			}
		}

		private bool Initialize()
		{
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Expected O, but got Unknown
			//IL_054d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Unknown result type (might be due to invalid IL or missing references)
			//IL_0635: Unknown result type (might be due to invalid IL or missing references)
			//IL_063c: Invalid comparison between Unknown and I4
			ZDO zDO = View.GetZDO();
			identity = (uint)((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).GetHashCode();
			random = NpcProfessionPolicy.AppearanceSeed(Profession, identity);
			string text = zDO.GetString("PrimeNPC_appearance", "");
			int num = NpcCivilianPolicy.AppearanceVersion(Profession);
			if (string.IsNullOrEmpty(text) || zDO.GetInt("PrimeNPC_lookVersion", 0) < num)
			{
				if (!View.IsOwner())
				{
					return false;
				}
				AppearanceRecord appearanceRecord = null;
				try
				{
					if (!string.IsNullOrEmpty(text))
					{
						appearanceRecord = JsonConvert.DeserializeObject<AppearanceRecord>(text);
					}
				}
				catch (JsonException)
				{
				}
				Look = MakeAppearance(appearanceRecord?.Gender ?? zDO.GetInt("PrimeNPC_gender", Definition.Gender));
				if (appearanceRecord != null)
				{
					NpcClothingPolicy.Migrate(Definition, appearanceRecord, Look);
				}
				Look.CombatArmor = ((appearanceRecord != null && appearanceRecord.CombatArmor >= 0f) ? appearanceRecord.CombatArmor : NpcCosmetics.Protection(Definition.BaseArmor, appearanceRecord?.ProtectionItems ?? appearanceRecord?.Armor ?? Look.ProtectionItems, SourceArmor));
				zDO.Set("PrimeNPC_appearance", JsonConvert.SerializeObject((object)Look));
				zDO.Set("PrimeNPC_lookVersion", num);
			}
			else
			{
				Look = JsonConvert.DeserializeObject<AppearanceRecord>(text);
			}
			if (NpcCivilianPolicy.Supported(Profession) && Look != null && Look.Gender == 1 && !string.IsNullOrEmpty(Look.Beard))
			{
				Look.Beard = "";
				if (View.IsOwner())
				{
					zDO.Set("PrimeNPC_appearance", JsonConvert.SerializeObject((object)Look));
				}
			}
			if (!NpcOutfitPolicy.RecordCompatible(Definition, Look) || Look.CombatArmor < 0f)
			{
				PrimeSwampNPCsPlugin.Warn(Profession + ": invalid saved outfit/protection; cannot initialize.");
				((Behaviour)this).enabled = false;
				return false;
			}
			if (!View.IsOwner())
			{
				initialized = true;
				return true;
			}
			Inventory inventory = Human.GetInventory();
			Human.UnequipAllItems();
			inventory.RemoveAll();
			HiddenRight.Invoke(Human) = (HiddenLeft.Invoke(Human) = null);
			ApplyModel();
			string[] armor = Look.Armor;
			foreach (string id in armor)
			{
				ItemData val = AddItem(id, cosmetic: true);
				if (val != null && View.IsOwner())
				{
					Human.EquipItem(val, false);
				}
			}
			Weapon = AddItem(Look.Weapon);
			shield = AddItem(Look.Shield);
			peace = AddItem(Look.Peace);
			if (Definition.TorchEligible)
			{
				torch = AddItem("Torch");
			}
			if (Look.Weapon == "BowHuntsman")
			{
				Arrow = AddItem("ArrowIron");
				if (Arrow != null && View.IsOwner())
				{
					Human.EquipItem(Arrow, false);
				}
			}
			List<Drop> list = new List<Drop>();
			LootRule[] array = Definition.Drops ?? Array.Empty<LootRule>();
			int num2 = ((Profession == "PrimeFarmer") ? NpcPolicy.Pick(ref random, array.Length) : (-1));
			for (int j = 0; j < array.Length; j++)
			{
				if (num2 < 0 || j == num2)
				{
					LootRule lootRule = array[j];
					GameObject val2 = NpcFactory.Find(lootRule.Prefab);
					if (Object.op_Implicit((Object)(object)val2))
					{
						list.Add(new Drop
						{
							m_prefab = val2,
							m_amountMin = lootRule.Min,
							m_amountMax = lootRule.Max,
							m_chance = lootRule.Chance,
							m_levelMultiplier = false,
							m_onePerPlayer = false
						});
					}
					else
					{
						PrimeSwampNPCsPlugin.Warn(Profession + ": missing drop " + lootRule.Prefab);
					}
				}
			}
			((Component)this).GetComponent<CharacterDrop>().m_drops = list;
			if (View.IsOwner())
			{
				if (!zDO.GetBool("PrimeNPC_healthV2", false))
				{
					((Character)Human).SetMaxHealth(Definition.Health * (float)((Character)Human).GetLevel());
					if (string.IsNullOrEmpty(text))
					{
						((Character)Human).SetHealth(((Character)Human).GetMaxHealth());
					}
					zDO.Set("PrimeNPC_healthV2", true);
				}
				if (!zDO.GetBool("PrimeNPC_homeSet", false))
				{
					zDO.Set("PrimeNPC_home", ((Component)this).transform.position);
					zDO.Set("PrimeNPC_homeSet", true);
				}
				SetPatrol((BaseAI)(object)AI, zDO.GetVec3("PrimeNPC_home", ((Component)this).transform.position));
				ApplyAppearance();
				if (zDO.GetLong("PrimeNPC_nextSpeech", 0L) <= Now)
				{
					ScheduleSpeech(zDO);
				}
			}
			if ((peace != null || NpcCivilianPolicy.Additional(Profession) || Profession == "PrimeWarrior") && Object.op_Implicit((Object)(object)animator))
			{
				canWork = false;
				workTrigger = ((NpcCivilianPolicy.Additional(Profession) || Profession == "PrimeWarrior") ? NpcCivilianPolicy.WorkTrigger(Definition.Activity.Mode, Look.Peace) : peace.m_shared.m_attack.m_attackAnimation);
				AnimatorControllerParameter[] parameters = animator.parameters;
				foreach (AnimatorControllerParameter val3 in parameters)
				{
					if ((int)val3.type == 9 && val3.name == workTrigger)
					{
						canWork = true;
					}
				}
			}
			workTimer = 10f + (float)NpcPolicy.Unit(ref random) * 15f;
			inventoryBuilt = true;
			initialized = true;
			appearanceAudit = 0.5f;
			return true;
		}

		private AppearanceRecord MakeAppearance(int requestedGender)
		{
			return NpcPolicy.CreateAppearance(Definition, PrimeSwampNPCsPlugin.Appearance, requestedGender, ref random, PrimeSwampNPCsPlugin.CultivatorChance.Value, PrimeSwampNPCsPlugin.FarmerFemaleChance.Value);
		}

		private static float SourceArmor(string id)
		{
			GameObject val = NpcFactory.Find(id);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<ItemDrop>()))
			{
				return 0f;
			}
			return val.GetComponent<ItemDrop>().m_itemData.GetArmor();
		}

		private void ApplyModel()
		{
			View.GetZDO().Set(ModelIndexKey, Look.Gender, false);
			visuals.SetModel(Look.Gender);
			RefreshBody(visuals);
		}

		internal void PrepareRagdoll(VisEquipment target)
		{
			//IL_00a6: 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)
			if (Look != null && Object.op_Implicit((Object)(object)target))
			{
				ZNetView component = ((Component)target).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner())
				{
					component.GetZDO().Set(ModelIndexKey, Look.Gender, false);
					target.SetModel(Look.Gender);
					RefreshBody(target);
					AppearanceFile appearance = PrimeSwampNPCsPlugin.Appearance;
					Rgb rgb = appearance.Skin[Look.Skin];
					Rgb rgb2 = appearance.Hair[Look.HairColor];
					target.SetSkinColor(new Vector3(rgb.R, rgb.G, rgb.B));
					target.SetHairColor(new Vector3(rgb2.R, rgb2.G, rgb2.B));
				}
			}
		}

		private void ApplyAppearance()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00ee: Invalid comparison between Unknown and I4
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Invalid comparison between Unknown and I4
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Invalid comparison between Unknown and I4
			AppearanceFile appearance = PrimeSwampNPCsPlugin.Appearance;
			Rgb rgb = appearance.Skin[Math.Min(Look.Skin, appearance.Skin.Length - 1)];
			Rgb rgb2 = appearance.Hair[Math.Min(Look.HairColor, appearance.Hair.Length - 1)];
			ApplyModel();
			visuals.SetSkinColor(new Vector3(rgb.R, rgb.G, rgb.B));
			visuals.SetHairColor(new Vector3(rgb2.R, rgb2.G, rgb2.B));
			Human.SetHair(Look.Hair);
			Human.SetBeard(Look.Beard);
			foreach (ItemData allItem in Human.GetInventory().GetAllItems())
			{
				if ((int)allItem.m_shared.m_itemType == 7 || (int)allItem.m_shared.m_itemType == 11 || (int)allItem.m_shared.m_itemType == 6)
				{
					Human.EquipItem(allItem, false);
				}
			}
		}

		private ItemData AddItem(string id, bool cosmetic = false)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			GameObject val = NpcFactory.Find(id);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<ItemDrop>()))
			{
				PrimeSwampNPCsPlugin.Warn(Profession + ": missing equipment " + id);
				return null;
			}
			ItemData val2 = val.GetComponent<ItemDrop>().m_itemData.Clone();
			val2.m_shared = NpcFactory.CopyShared(val2.m_shared);
			val2.m_dropPrefab = val;
			if (cosmetic)
			{
				NpcCosmetics.StripBenefits(val2.m_shared);
			}
			val2.m_shared.m_useDurability = false;
			val2.m_shared.m_aiTargetType = (AiTarget)0;
			val2.m_shared.m_aiAttackInterval = 2f;
			val2.m_shared.m_aiAttackRange = ((id == "BowHuntsman") ? 25 : 2);
			val2.m_shared.m_aiAttackRangeMin = ((id == "BowHuntsman") ? 2 : 0);
			val2.m_shared.m_aiAttackMaxAngle = 45f;
			val2.m_shared.m_aiWhenWalking = true;
			val2.m_shared.m_aiWhenSwiming = true;
			if (!Human.GetInventory().AddItem(val2))
			{
				return null;
			}
			return val2;
		}

		internal void Equip(bool combat)
		{
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Invalid comparison between Unknown and I4
			if (!initialized || !View.IsOwner())
			{
				return;
			}
			bool flag = NpcPolicy.Torch(identity, (Profession == "PrimeWarrior") ? PrimeSwampNPCsPlugin.WarriorTorchChance.Value : PrimeSwampNPCsPlugin.TorchChance.Value, EnvMan.IsNight(), combat, Definition.TorchEligible);
			int num = NpcBehaviorPolicy.Equipment(combat, fleeing, flag && torch != null);
			if (num == equipmentMode || (Profession == "PrimeWarrior" && ((Character)Human).InAttack()))
			{
				return;
			}
			equipmentMode = num;
			appearanceAudit = 0.5f;
			View.GetZDO().Set("PrimeNPC_combat", num == 2);
			if (Human.RightItem != null)
			{
				Human.UnequipItem(Human.RightItem, false);
			}
			if (Human.LeftItem != null)
			{
				Human.UnequipItem(Human.LeftItem, false);
			}
			if (Profession == "PrimeWarrior" && num == 1)
			{
				if (Weapon != null && NpcFinalPolicy.OneHanded(Look.Weapon))
				{
					Human.EquipItem(Weapon, false);
				}
				Human.EquipItem(torch, false);
				return;
			}
			ItemData val = ((num == 1) ? torch : ((num == 0 && peace != null) ? peace : Weapon));
			if (val != null)
			{
				Human.EquipItem(val, false);
			}
			if ((num == 2 || (Profession == "PrimeWarrior" && num == 0)) && shield != null && Weapon != null && (int)Weapon.m_shared.m_itemType == 3)
			{
				Human.EquipItem(shield, false);
			}
		}

		internal static void AlertNearby(Vector3 point, Character attacker, string homeKey)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			foreach (NpcRuntime instance in Instances)
			{
				if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.View) || !instance.View.IsValid())
				{
					continue;
				}
				Vector3 val = ((Component)instance).transform.position - point;
				if (!(((Vector3)(ref val)).sqrMagnitude > 400f) && (homeKey == null || !(instance.View.GetZDO().GetString("PrimeNPC_settlement", "") != homeKey)) && (attacker.IsPlayer() || BaseAI.IsEnemy((Character)(object)instance.Human, attacker)))
				{
					if (instance.View.IsOwner())
					{
						instance.OnProvoked(0L, attacker.GetZDOID());
						continue;
					}
					instance.View.InvokeRPC("PrimeNPC_Provoked", new object[1] { attacker.GetZDOID() });
				}
			}
		}

		private void OnProvoked(long sender, ZDOID attackerId)
		{
			//IL_001f: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (!View.IsOwner() || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			GameObject val = ZNetScene.instance.FindInstance(attackerId);
			Character val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Character>() : null);
			if (!Object.op_Implicit((Object)(object)val2) || !PriestTargetSafe(val2) || Object.op_Implicit((Object)(object)((Component)val2).GetComponent<NpcRuntime>()) || !initialized || val2.IsDead() || Vector3.Distance(((Component)val2).transform.position, Home) > Definition.DefenseRadius)
			{
				return;
			}
			if (val2.IsPlayer())
			{
				((BaseAI)AI).SetAggravated(true, (AggravatedReason)0);
				return;
			}
			long num = Now + (long)(PrimeSwampNPCsPlugin.AngerSeconds.Value * 10000000f);
			ZDO zDO = View.GetZDO();
			zDO.Set("PrimeNPC_threat", attackerId);
			zDO.Set("PrimeNPC_threatUntil", num);
			danger = val2;
			InterruptFarmerRoutine();
			SetAlert(AI, arg2: true);
			fleeing = NpcBehaviorPolicy.Flee(Profession, ((Character)Human).GetHealthPercentage(), Definition.RetreatHealthFraction, threat: true);
			if (!fleeing && (val2.IsPlayer() || BaseAI.IsEnemy((Character)(object)Human, val2)))
			{
				SetTarget(AI, val2);
				Equip(combat: true);
			}
		}

		private void TrySpeech()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = View.GetZDO();
			long now = Now;
			if (zDO.GetLong("PrimeNPC_nextSpeech", 0L) > now)
			{
				return;
			}
			ScheduleSpeech(zDO);
			if (NpcBehaviorPolicy.Speech((float)NpcPolicy.Unit(ref random), PrimeSwampNPCsPlugin.SpeechChance.Value, InCombat || fleeing, neighbourSpeaking: false) && Player.IsPlayerInRange(((Component)this).transform.position, PrimeSwampNPCsPlugin.DialogueDistance.Value))
			{
				string text = NpcPolicy.ChooseSpeech(PrimeSwampNPCsPlugin.Dialogue[Profession].Lines, bonemass: Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey("defeated_bonemass"), last: zDO.GetString("PrimeNPC_lastLine", ""), afterDanger: zDO.GetLong("PrimeNPC_recentDanger", 0L) > now, random: ref random);
				if (!string.IsNullOrEmpty(text))
				{
					zDO.Set("PrimeNPC_lastLine", text);
					View.InvokeRPC(ServerPeer, "PrimeNPC_RequestSpeech", new object[1] { text });
				}
			}
		}

		private void OnSpeech(long sender, string text)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && ZRoutedRpc.instance != null && sender == ServerPeer && Object.op_Implicit((Object)(object)Chat.instance) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !InCombat && !fleeing && Chat.instance.CurrentNpcTexts() <= 0)
			{
				Vector3 val = ((Component)Player.m_localPlayer).transform.position - ((Component)this).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 144f))
				{
					Chat.instance.SetNpcText(((Component)this).gameObject, new Vector3(0f, 2.1f, 0f), 12f, 5f, Definition.DisplayName, text, false);
				}
			}
		}

		private void TryWork()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (NpcCivilianPolicy.Supported(Profession) || !Definition.Work || !canWork || !Object.op_Implicit((Object)(object)animationSync) || peace == null || ((Character)Human).InAttack())
			{
				return;
			}
			workTimer -= 0.25f;
			if (!(workTimer > 0f))
			{
				Vector3 velocity = ((Character)Human).GetVelocity();
				if (!(((Vector3)(ref velocity)).sqrMagnitude > 0.2f))
				{
					workTimer = 20f + (float)NpcPolicy.Unit(ref random) * 25f;
					animationSync.SetTrigger(workTrigger);
				}
			}
		}

		private void OnDestroy()
		{
			Instances.Remove(this);
			if (Object.op_Implicit((Object)(object)Human))
			{
				Humanoid human = Human;
				((Character)human).m_onDeath = (Action)Delegate.Remove(((Character)human).m_onDeath, new Action(NativeDeath));
			}
		}

		private void ScheduleSpeech(ZDO zdo)
		{
			float num = Mathf.Max(1f, PrimeSwampNPCsPlugin.SpeechMin.Value);
			float num2 = Mathf.Max(num, PrimeSwampNPCsPlugin.SpeechMax.Value);
			zdo.Set("PrimeNPC_nextSpeech", Now + (long)(((double)num + NpcPolicy.Unit(ref random) * (double)(num2 - num)) * 10000000.0));
		}

		private void OnSpeechRequest(long sender, string text)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || sender != View.GetZDO().GetOwner() || ((Character)Human).IsDead() || InCombat || fleeing || !Player.IsPlayerInRange(((Component)this).transform.position, PrimeSwampNPCsPlugin.DialogueDistance.Value) || !PrimeSwampNPCsPlugin.Dialogue.TryGetValue(Profession, out var value) || !Array.Exists(value.Lines, (DialogueLine l) => l.Text == text))
			{
				return;
			}
			if ((Object)(object)speechWorld != (Object)(object)ZNet.instance)
			{
				SpeechGate.Clear();
				speechWorld = ZNet.instance;
			}
			double now = (double)Now / 10000000.0;
			if (SpeechGate.TryReserve(((Component)this).transform.position.x, ((Component)this).transform.position.z, now, Math.Max(6f, PrimeSwampNPCsPlugin.SpeechSpacing.Value)))
			{
				View.InvokeRPC(ZNetView.Everybody, "PrimeNPC_Speech", new object[1] { text });
				EffectList speechEffects = PrimeSwampNPCsPlugin.SpeechEffects;
				if (speechEffects != null)
				{
					speechEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
		}

		private void ResetSwimmerRoutine()
		{
			if (!(Profession != "PrimeSwimmer"))
			{
				bathClock.Advance(0f, danger: true, arrived: false, 0f, 0f, workOpportunity: false);
				bathClock.Advance(0f, danger: false, arrived: false, 0f, 0f, workOpportunity: false);
				bathRetry = 0f;
				bathDanger = false;
				threatScan = 0f;
			}
		}

		internal void UpdateSwimmerActivity(float dt)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00c8: 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)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: 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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: 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_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: 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_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			if (!OwnsSwimmerMovement)
			{
				return;
			}
			CivilianActivity activity = Definition.Activity;
			if (!activity.Enabled)
			{
				FarmStop((BaseAI)(object)AI);
				return;
			}
			if ((int)((BaseAI)AI).m_pathAgentType != 1)
			{
				((BaseAI)AI).m_pathAgentType = (AgentType)1;
				LastFarmPath.Invoke((BaseAI)(object)AI) = -1000f;
			}
			float radius = NpcFarmerPolicy.Radius(activity.Radius, Definition.DefenseRadius);
			bool flag = fleeing && Object.op_Implicit((Object)(object)danger) && !danger.IsDead();
			if (flag != bathDanger)
			{
				ResetSwimmerRoutine();
				bathDanger = flag;
			}
			Vector3 val = ((Component)this).transform.position - Home;
			val.y = 0f;
			if (!NpcFinalPolicy.BathInside(val.x, val.z, radius))
			{
				Vector3 point = Home;
				if (BathDestinationSafe(ref point))
				{
					MoveHome((BaseAI)(object)AI, dt, point, 0.5f, flag);
				}
				else
				{
					FarmStop((BaseAI)(object)AI);
				}
				return;
			}
			if (InCombat)
			{
				bathClock.Advance(0f, danger: true, arrived: false, 0f, 0f, workOpportunity: false);
				Character targetCreature = ((BaseAI)AI).GetTargetCreature();
				if (Object.op_Implicit((Object)(object)targetCreature))
				{
					Vector3 val2 = ((Component)targetCreature).transform.position - Home;
					if (!NpcFinalPolicy.BathInside(val2.x, val2.z, radius))
					{
						FarmStop((BaseAI)(object)AI);
					}
				}
				return;
			}
			bool flag2 = bathClock.Phase == FarmerPhase.Walking && MoveHome((BaseAI)(object)AI, dt, bathDestination, 0.5f, flag);
			if (bathClock.Phase != FarmerPhase.Walking)
			{
				FarmStop((BaseAI)(object)AI);
			}
			float pause = (flag2 ? FarmDuration(activity.IdleMinimumSeconds, activity.IdleMaximumSeconds) : 0f);
			bathClock.Advance(dt, danger: false, flag2, pause, 0f, workOpportunity: false);
			if (bathClock.Phase != FarmerPhase.Seeking)
			{
				return;
			}
			bathRetry -= dt;
			if (bathRetry > 0f)
			{
				return;
			}
			bathRetry = (flag ? 1 : 3);
			bool flag3 = false;
			Vector3 val3 = default(Vector3);
			float current = (flag ? Vector3.Distance(((Component)this).transform.position, ((Component)danger).transform.position) : 0f);
			for (int i = 0; i < 4; i++)
			{
				NpcFarmerPolicy.Destination(ref random, radius, out var x, out var z);
				Vector3 point2 = Home + new Vector3(x, 0f, z);
				if (Vector3.Distance(point2, ((Component)this).transform.position) < activity.MinimumTravelDistance || !BathDestinationSafe(ref point2))
				{
					continue;
				}
				if (flag)
				{
					float num = Vector3.Distance(point2, ((Component)danger).transform.position);
					if (!NpcFinalPolicy.Safer(num, current))
					{
						continue;
					}
					current = num;
				}
				val3 = point2;
				flag3 = true;
				if (!flag)
				{
					break;
				}
			}
			if (flag3)
			{
				bathDestination = val3;
				bathClock.BeginWalk(activity.WalkTimeoutSeconds);
			}
			else
			{
				FarmStop((BaseAI)(object)AI);
			}
		}

		private bool BathDestinationSafe(ref Vector3 point)
		{
			//IL_000f: 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_001a: 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_004d: 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_0072: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return false;
			}
			Vector3 val = point - Home;
			val.y = 0f;
			float radius = NpcFarmerPolicy.Radius(Definition.Activity.Radius, Definition.DefenseRadius);
			if (!NpcFinalPolicy.BathInside(val.x, val.z, radius) || !BathFloor(ref point))
			{
				return false;
			}
			Vector3 val2 = ((Component)this).transform.position;
			for (int i = 1; i <= 4; i++)
			{
				Vector3 point2 = Vector3.Lerp(((Component)this).transform.position, point, (float)i / 4f);
				if (!BathFloor(ref point2) || Mathf.Abs(point2.y - val2.y) > 0.7f)
				{
					return false;
				}
				val2 = point2;
			}
			return FarmHavePath((BaseAI)(object)AI, point);
		}

		private bool BathFloor(ref Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Heightmap.FindHeightmap(point)))
			{
				return false;
			}
			int mask = LayerMask.GetMask(new string[3] { "terrain", "static_solid", "piece" });
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(new Vector3(point.x, Home.y + 3f, point.z), Vector3.down, ref val, 8f, mask, (QueryTriggerInteraction)1))
			{
				return false;
			}
			float depth = ZoneSystem.instance.m_waterLevel - ((RaycastHit)(ref val)).point.y;
			point.y = Mathf.Max(((RaycastHit)(ref val)).point.y + 0.1f, ZoneSystem.instance.m_waterLevel - ((Character)Human).m_swimDepth + 0.05f);
			int mask2 = LayerMask.GetMask(new string[2] { "static_solid", "piece" });
			bool clear = !Physics.CheckCapsule(point + Vector3.up * 0.4f, point + Vector3.up * 1.4f, 0.3f, mask2, (QueryTriggerInteraction)1);
			return NpcFinalPolicy.BathGround(depth, Definition.Activity.MaximumWaterDepth, Vector3.Angle(((RaycastHit)(ref val)).normal, Vector3.up), clear, ((RaycastHit)(ref val)).point.y - Home.y);
		}
	}
	internal static class NpcBehaviorPolicy
	{
		internal static bool Proactive(string id)
		{
			if (!(id == "PrimeWarrior"))
			{
				return id == "PrimeDruid";
			}
			return true;
		}

		internal static bool Flee(string id, float healthFraction, float threshold, bool threat)
		{
			if (threat && !Proactive(id))
			{
				return healthFraction <= threshold;
			}
			return false;
		}

		internal static bool Defend(bool hostile, bool provoked, bool immediateThreat, bool proactive, bool player, bool angryAtPlayer, float actorHomeDistance, float targetHomeDistance, float radius)
		{
			if (actorHomeDistance <= radius && targetHomeDistance <= radius)
			{
				if (!player)
				{
					if (hostile)
					{
						return provoked || immediateThreat || proactive;
					}
					return false;
				}
				return angryAtPlayer;
			}
			return false;
		}

		internal static int Equipment(bool combat, bool fleeing, bool torch)
		{
			if (!combat || fleeing)
			{
				if (!torch || fleeing)
				{
					return 0;
				}
				return 1;
			}
			return 2;
		}

		internal static bool Speech(float roll, float chance, bool combat, bool neighbourSpeaking)
		{
			if (!combat && !neighbourSpeaking)
			{
				return roll < Math.Max(0f, Math.Min(1f, chance));
			}
			return false;
		}

		internal static bool BeginDeath(bool owner, bool alreadyStarted)
		{
			if (owner)
			{
				return !alreadyStarted;
			}
			return false;
		}

		internal static bool RemembersOffender(long now, long until, bool offender)
		{
			return now < until && offender;
		}

		internal static bool Retaliating(long now, long until, bool offender, bool inArea)
		{
			return now < until && offender && inArea;
		}

		internal static bool AcceptNpcDamage(bool targetNpc, bool attackerSettler, bool attackerPlayer, bool pvpEnabled)
		{
			if (!targetNpc)
			{
				return !attackerPlayer || pvpEnabled;
			}
			return !attackerSettler;
		}

		internal static float MigratedHealth(float health, float oldMax, float newMax)
		{
			return Math.Min(newMax, Math.Max(0f, (oldMax > 0f) ? (health / oldMax * newMax) : health));
		}
	}
	internal sealed class NpcSpeechGate
	{
		private sealed class Reservation
		{
			internal double X;

			internal double Z;

			internal double Until;

			internal double Radius;
		}

		private readonly List<Reservation> reservations = new List<Reservation>();

		internal void Clear()
		{
			reservations.Clear();
		}

		internal bool TryReserve(double x, double z, double now, double quiet, double radius = 12.0)
		{
			reservations.RemoveAll((Reservation r) => r.Until <= now);
			foreach (Reservation reservation in reservations)
			{
				if ((reservation.X - x) * (reservation.X - x) + (reservation.Z - z) * (reservation.Z - z) <= Math.Max(radius, reservation.Radius) * Math.Max(radius, reservation.Radius))
				{
					return false;
				}
			}
			reservations.Add(new Reservation
			{
				X = x,
				Z = z,
				Until = now + quiet,
				Radius = radius
			});
			return true;
		}
	}
	internal static class NpcCivilianPolicy
	{
		internal static bool Original(string id)
		{
			if (!(id == "PrimeFarmer") && !(id == "PrimeCommoner"))
			{
				return id == "PrimeFisherman";
			}
			return true;
		}

		internal static bool Additional(string id)
		{
			switch (id)
			{
			default:
				return id == "PrimeSculptor";
			case "PrimeWitch":
			case "PrimeDruid":
			case "PrimePriest":
				return true;
			}
		}

		internal static bool Supported(string id)
		{
			if (!Original(id) && !Additional(id))
			{
				return id == "PrimeWarrior";
			}
			return true;
		}

		internal static bool ValidMode(string id, string mode)
		{
			if ((!(id == "PrimeCommoner") || !(mode == "Hammer")) && (!(id == "PrimeFisherman") || !(mode == "Fishing")) && (!(id == "PrimeWitch") || !(mode == "Ritual")) && (!(id == "PrimeDruid") || !(mode == "Observe")) && (!(id == "PrimePriest") || !(mode == "Prayer")) && (!(id == "PrimeSculptor") || !(mode == "Hammer")) && (!(id == "PrimeWarrior") || !(mode == "Patrol")))
			{
				if (id == "PrimeSwimmer")
				{
					return mode == "Bath";
				}
				return false;
			}
			return true;
		}

		internal static string WorkTrigger(string mode, string tool)
		{
			if (!(mode == "Ritual") || !(tool == "StaffGreenRoots"))
			{
				if (!(mode == "Prayer") || !(tool == "StaffShield"))
				{
					switch (mode)
					{
					case "Hammer":
						if (tool == "Hammer")
						{
							return "swing_hammer";
						}
						goto default;
					default:
						if (!(mode == "Fishing") || !(tool == "FishingRod"))
						{
							return "";
						}
						return "fishingrod_throw";
					case "Observe":
					case "Patrol":
						return "emote_point";
					}
				}
				return "staff_shield";
			}
			return "staff_fireball0";
		}

		internal static bool ShoreWater(float ground, float water, float distance, float searchDistance, bool loaded, bool clear)
		{
			if (loaded && clear && ground <= water - 1f && distance >= 2f)
			{
				return distance <= searchDistance;
			}
			return false;
		}

		internal static bool CanWork(string mode, bool shore)
		{
			return mode != "Fishing" || shore;
		}

		internal static int AppearanceVersion(string id)
		{
			if (!(id == "PrimeSwimmer"))
			{
				return 9;
			}
			return 7;
		}

		internal static float ContactRange(string weapon, float nativeReach)
		{
			switch (weapon)
			{
			default:
				return 2f;
			case "KnifeChitin":
			case "SwordIron":
			case "MaceIron":
			case "SpearElderbark":
			case "AxeIron":
			case "AtgeirIron":
			case "Battleaxe":
				return NpcMeleePolicy.ContactRange(nativeReach);
			}
		}
	}
	internal static class NpcClothingPolicy
	{
		internal static bool LegItem(string id)
		{
			switch (id)
			{
			default:
				return id == "ArmorIronLegs";
			case "ArmorRagsLegs":
			case "ArmorLeatherLegs":
			case "ArmorTrollLeatherLegs":
			case "ArmorRootLegs":
				return true;
			}
		}

		internal static void Migrate(NpcDefinition definition, AppearanceRecord saved, AppearanceRecord result)
		{
			result.Gender = saved.Gender;
			result.Skin = saved.Skin;
			result.HairColor = saved.HairColor;
			result.Hair = saved.Hair;
			result.Beard = ((saved.Gender == 0) ? saved.Beard : "");
			result.Weapon = saved.Weapon;
			result.Shield = saved.Shield;
			result.Peace = saved.Peace;
			result.ProtectionItems = saved.ProtectionItems ?? saved.Armor;
			result.CombatArmor = saved.CombatArmor;
			if (NpcOutfitPolicy.RecordCompatible(definition, saved))
			{
				result.Armor = saved.Armor;
				return;
			}
			OutfitDefinition outfitDefinition = null;
			OutfitDefinition[] outfits = definition.Outfits;
			foreach (OutfitDefinition outfitDefinition2 in outfits)
			{
				if (outfitDefinition2.Gender == saved.Gender && NpcOutfitPolicy.Compatible(outfitDefinition2, definition.Id) && Array.IndexOf(saved.Armor ?? Array.Empty<string>(), outfitDefinition2.Chest) >= 0)
				{
					outfitDefinition = outfitDefinition2;
					break;
				}
			}
			List<string> list = new List<string>();
			string[] armor;
			if (outfitDefinition != null)
			{
				if (outfitDefinition.Chest != "")
				{
					list.Add(outfitDefinition.Chest);
				}
				if (outfitDefinition.Legs != "")
				{
					list.Add(outfitDefinition.Legs);
				}
			}
			else
			{
				armor = result.Armor;
				foreach (string text in armor)
				{
					if (!text.StartsWith("Helmet", StringComparison.Ordinal))
					{
						list.Add(text);
					}
				}
			}
			string[] array = ((saved.Gender == 0) ? definition.MaleHelmets : definition.FemaleHelmets);
			armor = saved.Armor ?? Array.Empty<string>();
			foreach (string text2 in armor)
			{
				if (text2.StartsWith("Helmet", StringComparison.Ordinal) && Array.IndexOf(array ?? Array.Empty<string>(), text2) >= 0)
				{
					list.Add(text2);
					break;
				}
			}
			result.Armor = list.ToArray();
		}
	}
	internal sealed class NpcConfiguration
	{
		internal ProfessionFile Professions;

		internal AppearanceFile Appearance;

		internal DialogueFile Dialogue;

		internal SettlementFile Settlements;
	}
	internal static class NpcConfigurationLoader
	{
		private static readonly string[] ExpectedIds = new string[9] { "PrimeFarmer", "PrimeSwimmer", "PrimeDruid", "PrimeWitch", "PrimeFisherman", "PrimeWarrior", "PrimePriest", "PrimeCommoner", "PrimeSculptor" };

		internal static NpcConfiguration LoadDirectory(string directory)
		{
			string text = Path.Combine(directory, "professions.json");
			string text2 = Path.Combine(directory, "appearance.json");
			string text3 = Path.Combine(directory, "dialogue.json");
			string text4 = Path.Combine(directory, "settlements.json");
			NpcConfiguration npcConfiguration = new NpcConfiguration
			{
				Professions = Read<ProfessionFile>(text),
				Appearance = Read<AppearanceFile>(text2),
				Dialogue = Read<DialogueFile>(text3),
				Settlements = Read<SettlementFile>(text4)
			};
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			NpcDefinition[] array = Array(npcConfiguration.Professions.Professions, text, "Professions", nonempty: true);
			Require(array.Length == ExpectedIds.Length, text, "Professions", "must contain all nine professions");
			for (int i = 0; i < array.Length; i++)
			{
				NpcDefinition npcDefinition = array[i];
				string text5 = "Professions[" + i + "]";
				Text(npcDefinition.Id, text, text5 + ".Id");
				Text(npcDefinition.DisplayName, text, text5 + ".DisplayName");
				Require(System.Array.IndexOf(ExpectedIds, npcDefinition.Id) >= 0 && hashSet.Add(npcDefinition.Id), text, text5 + ".Id", "must be a unique supported Prime NPC ID");
				Require(npcDefinition.Gender >= -1 && npcDefinition.Gender <= 1, text, text5 + ".Gender", "must be -1, 0 or 1");
				Number(npcDefinition.Health, 0f, float.MaxValue, text, text5 + ".Health", inclusive: false);
				Number(npcDefinition.WanderRadius, 0f, float.MaxValue, text, text5 + ".WanderRadius");
				Number(npcDefinition.HelmetChance, 0f, 1f, text, text5 + ".HelmetChance");
				Number(npcDefinition.FemaleChance, 0f, 1f, text, text5 + ".FemaleChance");
				Number(npcDefinition.CosmeticHelmetChance, -1f, 1f, text, text5 + ".CosmeticHelmetChance");
				Require(npcDefinition.Id == "PrimeFarmer" || (!NpcCivilianPolicy.Supported(npcDefinition.Id) && !NpcFinalPolicy.Final(npcDefinition.Id)) || npcDefinition.Activity != null, text, text5 + ".Activity", "required civilian activity settings are missing or null");
				if (npcDefinition.Activity != null)
				{
					CivilianActivity a = npcDefinition.Activity;
					string text6 = text5 + ".Activity";
					Require(NpcCivilianPolicy.ValidMode(npcDefinition.Id, a.Mode), text, text6 + ".Mode", "mode must match the civilian profession; Farmer keeps its existing cfg routine");
					if (NpcCivilianPolicy.Additional(npcDefinition.Id))
					{
						if (a.Mode == "Observe")
						{
							Require(npcDefinition.PeaceItems != null && npcDefinition.PeaceItems.Length == 0, text, text6, "observers retain their configured combat item while peaceful");
						}
						else
						{
							Require(npcDefinition.PeaceItems != null && npcDefinition.PeaceItems.Length != 0 && System.Array.TrueForAll(npcDefinition.PeaceItems, (string tool) => NpcCivilianPolicy.WorkTrigger(a.Mode, tool) != ""), text, text6, "activity requires its verified decorative tool");
						}
					}
					Number(a.Radius, 3f, 30f, text, text6 + ".Radius");
					Number(a.MinimumTravelDistance, 1f, a.Radius, text, text6 + ".MinimumTravelDistance");
					Number(a.WalkTimeoutSeconds, 4f, 60f, text, text6 + ".WalkTimeoutSeconds");
					Number(a.IdleMinimumSeconds, 1f, 60f, text, text6 + ".IdleMinimumSeconds");
					Number(a.IdleMaximumSeconds, a.IdleMinimumSeconds, 60f, text, text6 + ".IdleMaximumSeconds");
					Number(a.WorkMinimumSeconds, 1f, 60f, text, text6 + ".WorkMinimumSeconds");
					Number(a.WorkMaximumSeconds, a.WorkMinimumSeconds, 60f, text, text6 + ".WorkMaximumSeconds");
					Number(a.WorkChance, 0f, 1f, text, text6 + ".WorkChance");
					Number(a.MaximumWaterDepth, 0f, (npcDefinition.Id == "PrimeSwimmer") ? 2.5f : 0.4f, text, text6 + ".MaximumWaterDepth");
					Number(a.ShoreChance, 0f, 1f, text, text6 + ".ShoreChance");
					Number(a.ShoreSearchDistance, 2f, 12f, text, text6 + ".ShoreSearchDistance");
				}
				if (npcDefinition.Id == "PrimeSwimmer")
				{
					Require(npcDefinition.CombatWeapons != null && npcDefinition.CombatWeapons.Length == 0 && npcDefinition.PeaceItems != null && npcDefinition.PeaceItems.Length == 0 && npcDefinition.Shields != null && npcDefinition.Shields.Length == 0 && npcDefinition.Drops != null && npcDefinition.Drops.Length == 0 && npcDefinition.MaleHelmets != null && npcDefinition.MaleHelmets.Length == 0 && npcDefinition.FemaleHelmets != null && npcDefinition.FemaleHelmets.Length == 0 && npcDefinition.MaleChest != null && npcDefinition.MaleChest.Length == 0 && npcDefinition.FemaleChest != null && npcDefinition.FemaleChest.Length == 0 && npcDefinition.Legs != null && npcDefinition.Legs.Length == 0 && npcDefinition.BaseArmor == 0f && !npcDefinition.TorchEligible, text, text5, "Swimmers must have no weapons/tools/helmets/shields/torch or loot");
					Require(npcDefinition.Activity.Radius <= 4f && npcDefinition.Activity.WorkChance == 0f, text, text5, "bath radius must be at most 4m with native water/rest idle only");
				}
				Number(npcDefinition.BaseArmor, 0f, float.MaxValue, text, text5 + ".BaseArmor");
				Number(npcDefinition.DefenseRadius, 1f, 100f, text, text5 + ".DefenseRadius");
				Number(npcDefinition.ThreatRadius, 0f, npcDefinition.DefenseRadius, text, text5 + ".ThreatRadius");
				Number(npcDefinition.RetreatHealthFraction, 0f, 1f, text, text5 + ".RetreatHealthFraction");
				Strings(npcDefinition.MaleChest, text, text5 + ".MaleChest");
				Strings(npcDefinition.FemaleChest, text, text5 + ".FemaleChest");

BepInEx/plugins/PrimeSwampRevival/PrimeSwampRevival.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BiomeRevival.PrimeSwampNPCs;
using ExpandWorldData;
using ExpandWorldData.Locations;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SoftReferenceableAssets;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeSwampRevival")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.13.0")]
[assembly: AssemblyInformationalVersion("0.1.13+nexus.1")]
[assembly: AssemblyProduct("PrimeSwampRevival")]
[assembly: AssemblyTitle("PrimeSwampRevival")]
[assembly: AssemblyVersion("0.1.13.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BiomeRevival.PrimeSwampRevival
{
	internal sealed class ScheduledWork
	{
		internal readonly string Name;

		internal readonly Action Execute;

		internal ScheduledWork(string name, Action execute)
		{
			Name = name;
			Execute = execute;
		}
	}
	internal static class ActivationPipeline
	{
		private static IEnumerator<ScheduledWork> job;

		private static ZNet world;

		private static bool started;

		private static int failures;

		internal static bool Ready;

		internal static void Step()
		{
			if ((Object)(object)world != (Object)(object)ZNet.instance)
			{
				world = ZNet.instance;
				job?.Dispose();
				job = null;
				started = false;
				Ready = false;
				failures = 0;
			}
			if (!PrimeSwampRevivalPlugin.GenerationAllowed)
			{
				return;
			}
			if (!started)
			{
				started = true;
				job = Integration.ActivationWork().GetEnumerator();
				PrimeSwampRevivalPlugin.Instance?.Note("ACTIVATION_START cinematicReleased=True frame=" + Time.frameCount);
			}
			while (job != null && Performance.CanStart)
			{
				bool flag;
				try
				{
					flag = job.MoveNext();
				}
				catch (Exception ex)
				{
					failures++;
					PrimeSwampRevivalPlugin.Instance?.Note("ACTIVATION_ENUMERATOR_FAILED " + ex);
					flag = false;
				}
				if (!flag)
				{
					job.Dispose();
					job = null;
					Ready = Integration.ContentApplied;
					PrimeSwampRevivalPlugin.Instance?.Note("ACTIVATION_COMPLETE ready=" + Ready + " failedUnits=" + failures);
					break;
				}
				ScheduledWork current = job.Current;
				try
				{
					Performance.Run(current.Name, current.Execute);
				}
				catch (Exception ex2)
				{
					failures++;
					PrimeSwampRevivalPlugin.Instance?.Note("ACTIVATION_UNIT_FAILED " + current.Name + " " + ex2);
				}
			}
		}
	}
	internal static class ActivationPolicy
	{
		internal const double FrameMilliseconds = 4.0;

		internal const double SafetyMilliseconds = 40.0;

		internal const int MaximumUnits = 16;

		internal const int MaximumDeferred = 20000;

		internal static bool Ready(bool active, long start, long now, long duration, bool overlay, int frame, int releasedFrame)
		{
			if (active && (start <= 0 || now >= start + duration) && !overlay)
			{
				return frame > releasedFrame;
			}
			return false;
		}

		internal static bool CanStart(double spent, int units)
		{
			if (spent < 4.0)
			{
				return units < 16;
			}
			return false;
		}

		internal static bool Overdue(double elapsed, int checkpoints)
		{
			if (!(elapsed >= 40.0))
			{
				return checkpoints > 100000;
			}
			return true;
		}
	}
	internal sealed class FrameAllowance
	{
		private int frame = -1;

		private int units;

		private double spent;

		internal bool CanStart => ActivationPolicy.CanStart(spent, units);

		internal void Reset(int value)
		{
			if (frame != value)
			{
				frame = value;
				units = 0;
				spent = 0.0;
			}
		}

		internal void Charge(double elapsed)
		{
			spent += Math.Max(0.0, elapsed);
			units++;
		}
	}
	internal static class AmbientPolicy
	{
		internal static bool Selected(string prefab, bool swamp)
		{
			if (swamp)
			{
				switch (prefab)
				{
				default:
					return prefab == "Fish2";
				case "PrimeBoar":
				case "PrimeNeck":
				case "PrimeForestSpirit":
				case "Seagal":
				case "Fish1":
					return true;
				}
			}
			return false;
		}

		internal static bool DaySpirit(string prefab, bool day, bool night)
		{
			if (prefab == "PrimeForestSpirit" && day)
			{
				return !night;
			}
			return false;
		}

		internal static string TextureName(string supplied, string root)
		{
			return supplied ?? root ?? "";
		}
	}
	internal static class BiomeState
	{
		private static readonly MethodInfo Clone = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null);

		internal static BiomeEnvSetup NativeSwamp;

		private static EnvSetup nativeRain;

		private static EnvMan rainWorld;

		internal static void Install(Harmony harmony)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0061: 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_007a: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("ExpandWorldData.Biome.BiomeManager");
			harmony.Patch((MethodBase)AccessTools.Method(type, "Initialize", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BiomeState), "Capture", (Type[])null)
			{
				priority = int.MaxValue
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(type, "SetupBiomeEnvs", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BiomeState), "GateEnvironments", (Type[])null)
			{
				priority = int.MaxValue
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Type type2 = AccessTools.TypeByName("ExpandWorldData.Environment.EnvironmentManager");
			harmony.Patch((MethodBase)AccessTools.Method(type2, "Initialize", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BiomeState), "Capture", (Type[])null)
			{
				priority = int.MaxValue
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Type type3 = AccessTools.TypeByName("PrimeSwampTrees.PrimeSwampTreesPlugin");
			if (type3 != null)
			{
				AccessTools.Field(type3, "RestorationGate")?.SetValue(null, (Func<bool>)(() => PrimeSwampRevivalPlugin.VisualReady));
			}
			Type type4 = AccessTools.TypeByName("BiomeRevival.PrimeForestSpirit.PrimeForestSpiritPlugin");
			if (type4 != null)
			{
				AccessTools.Field(type4, "RestorationGate")?.SetValue(null, (Func<bool>)(() => PrimeSwampRevivalPlugin.ContentReady));
			}
			Type type5 = AccessTools.TypeByName("CustomTextures.BepInExPlugin");
			if (type5 != null)
			{
				harmony.Patch((MethodBase)AccessTools.Method(type5, "SetupVisEquipment", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BiomeState), "NpcTextures", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool NpcTextures(Humanoid __0)
		{
			if (Object.op_Implicit((Object)(object)__0))
			{
				return !Object.op_Implicit((Object)(object)((Component)__0).GetComponent<NpcRuntime>());
			}
			return true;
		}

		private static void Capture()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				return;
			}
			if ((Object)(object)rainWorld != (Object)(object)EnvMan.instance)
			{
				NativeSwamp = null;
				nativeRain = null;
				rainWorld = EnvMan.instance;
			}
			if (NativeSwamp == null)
			{
				BiomeEnvSetup val = ((IEnumerable<BiomeEnvSetup>)EnvMan.instance.m_biomes).FirstOrDefault((Func<BiomeEnvSetup, bool>)((BiomeEnvSetup b) => (int)b.m_biome == 2));
				if (val != null)
				{
					NativeSwamp = (BiomeEnvSetup)Clone.Invoke(val, null);
					NativeSwamp.m_environments = ((IEnumerable<EnvEntry>)val.m_environments).Select((Func<EnvEntry, EnvEntry>)((EnvEntry e) => (EnvEntry)Clone.Invoke(e, null))).ToList();
				}
			}
			if (nativeRain == null)
			{
				EnvSetup val2 = ((IEnumerable<EnvSetup>)EnvMan.instance.m_environments).FirstOrDefault((Func<EnvSetup, bool>)((EnvSetup e) => e.m_name == "SwampRain"));
				if (val2 != null)
				{
					nativeRain = (EnvSetup)Clone.Invoke(val2, null);
				}
			}
		}

		private static void GateEnvironments(ref List<BiomeEnvSetup> __0)
		{
			Capture();
			if (PrimeSwampRevivalPlugin.VisualReady || NativeSwamp == null)
			{
				return;
			}
			__0 = __0.Where((BiomeEnvSetup b) => (int)b.m_biome != 2).Concat((IEnumerable<BiomeEnvSetup>)(object)new BiomeEnvSetup[1] { Copy(NativeSwamp) }).ToList();
			if (nativeRain != null && Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				List<EnvSetup> environments = EnvMan.instance.m_environments;
				int num = environments.FindIndex((EnvSetup e) => e.m_name == "SwampRain");
				if (num >= 0)
				{
					environments[num] = nativeRain;
				}
			}
		}

		internal static void Apply()
		{
			if (!Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				return;
			}
			List<BiomeEnvSetup> list = (List<BiomeEnvSetup>)Integration.Field("ExpandWorldData.Biome.BiomeManager", "Environments");
			if (list.Count > 0)
			{
				AccessTools.Method(AccessTools.TypeByName("ExpandWorldData.Biome.BiomeManager"), "SetupBiomeEnvs", (Type[])null, (Type[])null).Invoke(null, new object[1] { list.Select(Copy).ToList() });
			}
			AccessTools.Field(typeof(EnvMan), "m_environmentPeriod").SetValue(EnvMan.instance, -1L);
			AccessTools.Field(typeof(EnvMan), "m_ambientMusicTimer").SetValue(EnvMan.instance, 3f);
			PrimeSwampRevivalPlugin.Instance?.Note("ENVIRONMENT_REFRESH restored=" + PrimeSwampRevivalPlugin.VisualReady + " swamp=" + string.Join(",", from b in EnvMan.instance.m_biomes
				where (int)b.m_biome == 2
				select b.m_musicDay + "/" + b.m_musicNight + ":" + string.Join(",", b.m_environments.Select((EnvEntry e) => e.m_environment))));
		}

		private static BiomeEnvSetup Copy(BiomeEnvSetup source)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			BiomeEnvSetup val = (BiomeEnvSetup)Clone.Invoke(source, null);
			val.m_environments = ((IEnumerable<EnvEntry>)source.m_environments).Select((Func<EnvEntry, EnvEntry>)((EnvEntry e) => (EnvEntry)Clone.Invoke(e, null))).ToList();
			return val;
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "SpawnLocation")]
	internal static class BlueprintWitness
	{
		internal sealed class Witness
		{
			internal string Name;

			internal int Expected;

			internal int Actual;

			internal int Invalid;

			internal Witness Previous;

			internal Action Npc;

			internal bool Releasing;
		}

		internal static Witness Current;

		internal static string Last = "No new Prime blueprint observed this session";

		internal static int Minimum(string name, HashSet<string> visiting = null)
		{
			visiting = visiting ?? new HashSet<string>();
			if (!visiting.Add(name))
			{
				throw new InvalidOperationException("Recursive blueprint " + name);
			}
			object[] array = new object[2] { name, null };
			if (!(bool)AccessTools.Method(AccessTools.TypeByName("ExpandWorldData.Data.BlueprintManager"), "TryGet", (Type[])null, (Type[])null).Invoke(null, array))
			{
				throw new InvalidOperationException("Missing blueprint " + name);
			}
			int num = 0;
			int num2 = 0;
			foreach (object item in (IEnumerable)AccessTools.Field(array[1].GetType(), "Objects").GetValue(array[1]))
			{
				num2++;
				string text = (string)AccessTools.Field(item.GetType(), "Prefab").GetValue(item);
				float num3 = (float)AccessTools.Field(item.GetType(), "Chance").GetValue(item);
				int num4 = (Object.op_Implicit((Object)(object)ZNetScene.instance.GetPrefab(text)) ? 1 : Minimum(text, visiting));
				if (num3 >= 1f)
				{
					num += num4;
				}
			}
			visiting.Remove(name);
			if (num2 == 0)
			{
				throw new InvalidOperationException("Empty blueprint " + name);
			}
			return num;
		}

		private static void Prefix(ZoneLocation __0, SpawnMode __4, out Witness __state)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			__state = null;
			FutureGeneration.Scope current = FutureGeneration.Current;
			if (current != null && current.Restored && (int)__4 != 1 && Integration.Name(__0).StartsWith("PrimeSwamp", StringComparison.Ordinal))
			{
				__state = new Witness
				{
					Name = Integration.Name(__0),
					Previous = Current
				};
				Current = __state;
				PrimeSwampRevivalPlugin.Instance?.Note("BLUEPRINT_BEGIN " + __state.Name);
			}
		}

		private static Exception Finalizer(Witness __state, Exception __exception)
		{
			if (__state == null)
			{
				return __exception;
			}
			try
			{
				int num = Minimum(__state.Name);
				bool flag = __exception == null && __state.Expected >= num && __state.Actual == __state.Expected && __state.Invalid == 0;
				Last = __state.Name + " factoryVerified=" + flag + " minimum=" + num + " expected=" + __state.Expected + " actual=" + __state.Actual;
				PrimeSwampRevivalPlugin.Instance?.Note("BLUEPRINT_END " + Last);
				if (flag && __state.Npc != null)
				{
					__state.Releasing = true;
					__state.Npc();
				}
			}
			catch (Exception ex)
			{
				PrimeSwampRevivalPlugin.Instance?.Note("BLUEPRINT_VERIFY_FAILED " + __state.Name + " " + ex);
			}
			finally
			{
				Current = __state.Previous;
			}
			return __exception;
		}

		internal static GameObject Instantiate(GameObject prefab, Vector3 point, Quaternion rotation)
		{
			//IL_0018: 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)
			Witness current = Current;
			if (current != null)
			{
				current.Expected++;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, point, rotation);
			if (current != null)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					current.Actual++;
				}
				else
				{
					current.Invalid++;
				}
			}
			return val;
		}

		internal static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> source)
		{
			int replaced = 0;
			foreach (CodeInstruction item in source)
			{
				if (item.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments()[0] == typeof(GameObject))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 3 && parameters[1].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(Quaternion))
					{
						item.operand = typeof(BlueprintWitness).GetMethod("Instantiate", BindingFlags.Static | BindingFlags.NonPublic);
						replaced++;
					}
				}
				yield return item;
			}
			if (replaced == 0)
			{
				throw new MissingMethodException("EWD physical factory changed");
			}
		}
	}
	[HarmonyPatch(typeof(SettlementManager), "LocationInitialized")]
	internal static class FutureNpcInitialization
	{
		private static bool Prefix(SettlementManager __instance, ZoneLocation __0, Vector3 __1, SpawnMode __2)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			FutureGeneration.Scope current = FutureGeneration.Current;
			if (current == null || !current.Restored)
			{
				return false;
			}
			BlueprintWitness.Witness current2 = BlueprintWitness.Current;
			if (current2 == null || current2.Releasing)
			{
				return true;
			}
			current2.Npc = delegate
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				AccessTools.Method(typeof(SettlementManager), "LocationInitialized", (Type[])null, (Type[])null).Invoke(__instance, new object[3] { __0, __1, __2 });
			};
			return false;
		}
	}
	internal static class Cinematic
	{
		private static CanvasGroup screen;

		private static TMP_Text text;

		private static bool active;

		private static bool musicPlayed;

		private static long musicSequence;

		internal static int ReleasedFrame = -1;

		internal static bool Visible => active;

		internal static void Tick()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			double num = (double)(PrimeSwampRevivalPlugin.Now - PrimeSwampRevivalPlugin.sequenceStart) / 10000000.0;
			if (!PrimeSwampRevivalPlugin.Playing || !Object.op_Implicit((Object)(object)Hud.instance) || !Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				Release();
				return;
			}
			if (!active)
			{
				screen = (CanvasGroup)AccessTools.Field(typeof(Hud), "m_loadingScreen").GetValue(Hud.instance);
				TMP_Text val = (TMP_Text)AccessTools.Field(typeof(MessageHud), "m_messageCenterText").GetValue(MessageHud.instance);
				if (!Object.op_Implicit((Object)(object)screen) || !Object.op_Implicit((Object)(object)val))
				{
					return;
				}
				Cinematic.text = Object.Instantiate<TMP_Text>(val, ((Component)screen).transform, false);
				((Object)Cinematic.text).name = "PrimeRevivalText";
				Cinematic.text.transform.localPosition = Vector3.zero;
				((Component)Cinematic.text).gameObject.SetActive(true);
				((Graphic)Cinematic.text).canvasRenderer.SetAlpha(1f);
				((Graphic)Cinematic.text).raycastTarget = false;
				if (musicSequence != PrimeSwampRevivalPlugin.sequenceStart)
				{
					musicSequence = PrimeSwampRevivalPlugin.sequenceStart;
					musicPlayed = false;
				}
				active = true;
			}
			((Component)screen).gameObject.SetActive(true);
			screen.alpha = Mathf.SmoothStep(0f, 1f, RevivalPolicy.Black(num));
			string[] array = new string[3] { "m_loadingProgress", "m_sleepingProgress", "m_teleportingProgress" };
			foreach (string text in array)
			{
				object? obj = AccessTools.Field(typeof(Hud), text)?.GetValue(Hud.instance);
				GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.SetActive(false);
				}
			}
			int num2 = RevivalPolicy.Message(num);
			Cinematic.text.text = num2 switch
			{
				2 => "Slowly, life returns to the wetlands…", 
				1 => "An ancient corruption begins to fade…", 
				_ => "", 
			};
			Cinematic.text.alpha = Mathf.SmoothStep(0f, 1f, RevivalPolicy.TextAlpha(num));
			if (num >= 14.0 && !musicPlayed)
			{
				musicPlayed = true;
				if (Object.op_Implicit((Object)(object)MusicMan.instance) && (string)AccessTools.Method(typeof(MusicMan), "GetCurrentMusic", (Type[])null, (Type[])null).Invoke(MusicMan.instance, null) != "morning")
				{
					MusicMan.instance.TriggerMusic("morning");
				}
			}
		}

		internal static void Release()
		{
			if (!active)
			{
				return;
			}
			try
			{
				if (Object.op_Implicit((Object)(object)text))
				{
					Object.Destroy((Object)(object)((Component)text).gameObject);
				}
				if (Object.op_Implicit((Object)(object)screen))
				{
					screen.alpha = 0f;
				}
			}
			finally
			{
				screen = null;
				text = null;
				active = false;
				CinematicSafety.End();
				ReleasedFrame = Time.frameCount;
				PrimeSwampRevivalPlugin.Instance?.Note("CINEMATIC_RELEASED frame=" + ReleasedFrame);
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateBlackScreen")]
	internal static class RevivalFade
	{
		private static bool Prefix()
		{
			return !PrimeSwampRevivalPlugin.Playing;
		}
	}
	internal static class CinematicSafety
	{
		internal static ConfigEntry<float> RadiusSetting;

		private static readonly List<Vector3> areas = new List<Vector3>();

		private static readonly List<Player> players = new List<Player>();

		private static readonly HashSet<ZDOID> removed = new HashSet<ZDOID>();

		private static readonly FieldInfo Drops = AccessTools.Field(typeof(CharacterDrop), "m_dropsEnabled");

		private static ZNet world;

		private static long eventId;

		private static long until;

		private static double deadline;

		private static float radius;

		private static bool ended = true;

		internal static bool Active
		{
			get
			{
				if (ended || !Object.op_Implicit((Object)(object)world) || (Object)(object)world != (Object)(object)ZNet.instance)
				{
					return false;
				}
				bool num = CinematicSafetyPolicy.Active(sameWorld: true, ended: false, PrimeSwampRevivalPlugin.Now, until, Cinematic.Visible, Time.realtimeSinceStartupAsDouble, deadline);
				if (!num)
				{
					End();
				}
				return num;
			}
		}

		internal static void Reset()
		{
			world = null;
			eventId = (until = 0L);
			ended = true;
			areas.Clear();
			players.Clear();
			removed.Clear();
		}

		internal static void End()
		{
			if (!ended)
			{
				ended = true;
				areas.Clear();
				players.Clear();
				removed.Clear();
				PrimeSwampRevivalPlugin.Instance?.Note("CINEMATIC_SAFETY_RELEASED");
			}
		}

		private static void Initialize(long start, float distance)
		{
			world = ZNet.instance;
			eventId = start;
			until = start + 160000000;
			radius = Mathf.Clamp(distance, 1f, 250f);
			ended = false;
			deadline = Time.realtimeSinceStartupAsDouble + Math.Max(0.0, (double)(until - PrimeSwampRevivalPlugin.Now) / 10000000.0) + 2.0;
			players.Clear();
			players.AddRange(Player.GetAllPlayers());
		}

		internal static ZPackage BeginServer(long start)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if (!CinematicSafetyPolicy.NewEvent(Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer(), (Object)(object)world == (Object)(object)ZNet.instance, eventId, start))
			{
				return null;
			}
			Initialize(start, RadiusSetting.Value);
			areas.Clear();
			removed.Clear();
			foreach (Player player in players)
			{
				if (Object.op_Implicit((Object)(object)player))
				{
					areas.Add(((Component)player).transform.position);
				}
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			List<Character> list = new List<Character>();
			int num = 0;
			ZNetView val = default(ZNetView);
			foreach (Vector3 area in areas)
			{
				list.Clear();
				Character.GetCharactersInRange(area, radius, list);
				foreach (Character item in list)
				{
					if (IsHostile(item) && ((Component)item).TryGetComponent<ZNetView>(ref val) && val.IsValid() && removed.Add(val.GetZDO().m_uid))
					{
						try
						{
							RemoveQuietly(item, val);
							num++;
						}
						catch (Exception ex)
						{
							PrimeSwampRevivalPlugin.Instance?.Note("CINEMATIC_CLEANUP_FAILED " + ex);
						}
					}
				}
			}
			PrimeSwampRevivalPlugin.Instance?.Note("HOSTILE_CLEANUP beforeFade=True nativeDeathCompleted=True areas=" + areas.Count + " radius=" + radius + " removed=" + num + " elapsedMs=" + stopwatch.Elapsed.TotalMilliseconds.ToString("F2", CultureInfo.InvariantCulture));
			if (stopwatch.Elapsed.TotalMilliseconds > 4.0)
			{
				PrimeSwampRevivalPlugin.Instance?.Note("BUDGET_WARNING one-time local hostile cleanup elapsedMs=" + stopwatch.Elapsed.TotalMilliseconds.ToString("F2", CultureInfo.InvariantCulture));
			}
			return CinematicSafetyPacket.Write(start, radius, areas);
		}

		internal static void Receive(ZPackage packet)
		{
			CinematicSafetyPacket cinematicSafetyPacket = CinematicSafetyPacket.Read(packet);
			long start = cinematicSafetyPacket.Start;
			if (PrimeSwampRevivalPlugin.Now <= start + 160000000 && (!((Object)(object)world == (Object)(object)ZNet.instance) || eventId != start))
			{
				Initialize(start, cinematicSafetyPacket.Radius);
				areas.Clear();
				areas.AddRange(cinematicSafetyPacket.Centers);
			}
		}

		internal static bool InArea(Vector3 point, float extra = 0f)
		{
			//IL_0020: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return false;
			}
			float num = radius + extra;
			foreach (Vector3 area in areas)
			{
				Vector3 val = area - point;
				if (((Vector3)(ref val)).sqrMagnitude <= num * num)
				{
					return true;
				}
			}
			return false;
		}

		internal static bool IsHostile(Character character, bool prefab = false)
		{
			if (!Object.op_Implicit((Object)(object)character))
			{
				return false;
			}
			bool flag = character.IsPlayer();
			bool flag2 = character.IsTamed();
			bool flag3 = Object.op_Implicit((Object)(object)((Component)character).GetComponent<NpcRuntime>());
			bool flag4 = Integration.ProtectedWildlife(character) || Object.op_Implicit((Object)(object)((Component)character).GetComponent<AnimalAI>());
			bool flag5 = prefab || character.GetHealth() > 0f;
			bool flag6 = false;
			if (!flag && !flag2 && !flag4 && flag5)
			{
				foreach (Player player in players)
				{
					if (Object.op_Implicit((Object)(object)player) && BaseAI.IsEnemy(character, (Character)(object)player))
					{
						flag6 = true;
						break;
					}
				}
			}
			return CinematicSafetyPolicy.Hostile(flag, flag2, flag4, flag3 && !flag6, flag5, flag6, inside: true);
		}

		internal static bool Block(Character character)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (Active && Object.op_Implicit((Object)(object)character) && InArea(((Component)character).transform.position))
			{
				return IsHostile(character);
			}
			return false;
		}

		internal static bool BlockPrefab(GameObject prefab, Vector3 point, float extra = 0f)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (Active && Object.op_Implicit((Object)(object)prefab) && InArea(point, extra))
			{
				return IsHostile(prefab.GetComponent<Character>(), prefab: true);
			}
			return false;
		}

		internal static void RemoveQuietly(Character character, ZNetView view)
		{
			CharacterDrop component = ((Component)character).GetComponent<CharacterDrop>();
			bool dropsEnabled = Object.op_Implicit((Object)(object)component) && (bool)Drops.GetValue(component);
			if (Object.op_Implicit((Object)(object)component))
			{
				component.SetDropsEnabled(false);
			}
			try
			{
				AudioSource[] componentsInChildren = ((Component)character).GetComponentsInChildren<AudioSource>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].Stop();
				}
				view.GetZDO().SetOwner(ZDOMan.GetSessionID());
				ZNetScene.instance.Destroy(((Component)character).gameObject);
			}
			catch
			{
				if (Object.op_Implicit((Object)(object)component))
				{
					component.SetDropsEnabled(dropsEnabled);
				}
				throw;
			}
		}
	}
	[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
	internal static class GuardNativeSpawn
	{
		private static bool Prefix(SpawnData __0, Vector3 __1)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return !CinematicSafety.BlockPrefab(__0.m_prefab, __1);
		}
	}
	[HarmonyPatch(typeof(CreatureSpawner), "Spawn")]
	internal static class GuardLocalSpawner
	{
		private static bool Prefix(CreatureSpawner __instance, ref ZNetView __result)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!CinematicSafety.Active || !CinematicSafety.BlockPrefab(__instance.m_creaturePrefab, ((Component)__instance).transform.position))
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(SpawnArea), "SpawnOne")]
	internal static class GuardSpawnArea
	{
		private static bool Prefix(SpawnArea __instance, ref bool __result)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!CinematicSafety.Active || __instance.m_prefabs.Count == 0)
			{
				return true;
			}
			foreach (SpawnData prefab in __instance.m_prefabs)
			{
				if (!CinematicSafety.BlockPrefab(prefab.m_prefab, ((Component)__instance).transform.position, __instance.m_spawnRadius))
				{
					return true;
				}
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
	internal static class GuardHostileAI
	{
		private static bool Prefix(MonsterAI __instance, ref bool __result)
		{
			if (!CinematicSafety.Active)
			{
				return true;
			}
			if (!CinematicSafety.Block(((Component)__instance).GetComponent<Character>()))
			{
				return true;
			}
			((BaseAI)__instance).StopMoving();
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[]
	{
		typeof(Character),
		typeof(bool)
	})]
	internal static class GuardHostileAttack
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			if (!CinematicSafety.Block((Character)(object)__instance))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class GuardPlayerDamage
	{
		private static bool Prefix(Character __instance)
		{
			if (__instance.IsPlayer())
			{
				return !CinematicSafety.Active;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "Start")]
	internal static class GuardExternalSpawn
	{
		private static void Postfix(Character __instance)
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && CinematicSafety.Block(__instance))
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid())
				{
					CinematicSafety.RemoveQuietly(__instance, component);
				}
			}
		}
	}
	internal sealed class CinematicSafetyPacket
	{
		internal long Start;

		internal float Radius;

		internal Vector3[] Centers;

		internal static ZPackage Write(long start, float radius, List<Vector3> centers)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			ZPackage val = new ZPackage();
			val.Write(start);
			val.Write(radius);
			val.Write(centers.Count);
			foreach (Vector3 center in centers)
			{
				val.Write(center);
			}
			return val;
		}

		internal static CinematicSafetyPacket Read(ZPackage p)
		{
			//IL_0061: 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)
			long num = p.ReadLong();
			float num2 = p.ReadSingle();
			int num3 = p.ReadInt();
			if (num <= 0 || num3 < 0 || num3 > 128 || float.IsNaN(num2) || float.IsInfinity(num2) || num2 < 1f || num2 > 250f)
			{
				throw new FormatException("Invalid cinematic safety packet");
			}
			Vector3[] array = (Vector3[])(object)new Vector3[num3];
			for (int i = 0; i < num3; i++)
			{
				array[i] = p.ReadVector3();
			}
			return new CinematicSafetyPacket
			{
				Start = num,
				Radius = num2,
				Centers = array
			};
		}
	}
	internal static class CinematicSafetyPolicy
	{
		internal static bool Hostile(bool player, bool tamed, bool ambient, bool settler, bool alive, bool enemy, bool inside)
		{
			return !player && !tamed && !ambient && !settler && alive && enemy && inside;
		}

		internal static bool Active(bool sameWorld, bool ended, long now, long until, bool visible, double realtime, double deadline)
		{
			if (sameWorld && !ended && now < until)
			{
				if (!visible)
				{
					return realtime < deadline;
				}
				return true;
			}
			return false;
		}

		internal static bool NewEvent(bool server, bool sameWorld, long seen, long incoming)
		{
			if (server && incoming > 0)
			{
				if (sameWorld)
				{
					return seen != incoming;
				}
				return true;
			}
			return false;
		}
	}
	internal static class FutureGeneration
	{
		internal sealed class Scope
		{
			internal Vector2s Zone;

			internal bool Restored;

			internal Scope Previous;
		}

		internal static Scope Current;

		internal static ZoneLocation Planning;

		internal static void Install(Harmony h)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_0076: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			Type type = typeof(ZoneSystem).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic).Single((Type t) => t.Name.Contains("GenerateLocationsTimeSliced") && t.GetField("location", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
			h.Patch((MethodBase)AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SpacingAllocation), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SpacingAllocation), "Finalizer", (Type[])null), (HarmonyMethod)null);
			SpacingAllocation.Install(h);
			string[][] array = new string[2][]
			{
				new string[2] { "ExpandWorldData.Create", "SharedBPO" },
				new string[2] { "ExpandWorldData.Data.DataManager", "Instantiate" }
			};
			foreach (string[] array2 in array)
			{
				h.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName(array2[0]), array2[1], (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueprintWitness), "Transpile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		internal static bool Swamp(Vector2s id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_005e: Invalid comparison between Unknown and I4
			//IL_0061: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Invalid comparison between Unknown and I4
			Vector3 zonePos = ZoneSystem.GetZonePos(id);
			WorldGenerator instance = WorldGenerator.instance;
			if ((int)instance.GetBiome(zonePos) != 2 && (int)instance.GetBiome(zonePos + new Vector3(-31f, 0f, -31f)) != 2 && (int)instance.GetBiome(zonePos + new Vector3(31f, 0f, -31f)) != 2 && (int)instance.GetBiome(zonePos + new Vector3(-31f, 0f, 31f)) != 2)
			{
				return (int)instance.GetBiome(zonePos + new Vector3(31f, 0f, 31f)) == 2;
			}
			return true;
		}

		internal static void Replace(Vector2s id, ZoneLocation target, Vector3 point)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			ZoneSystem instance = ZoneSystem.instance;
			LocationInstance val = instance.m_locationInstances[id];
			instance.m_locationInstances.Remove(id);
			object[] array = new object[3]
			{
				val.m_location.m_prefab.m_assetID,
				val.m_location.m_group,
				val.m_location.m_groupMax
			};
			string[] array2 = new string[3] { "m_locationIDCache", "m_locationGroupCache", "m_locationMaxGroupCache" };
			for (int i = 0; i < 3; i++)
			{
				IDictionary dictionary = (IDictionary)AccessTools.Field(typeof(ZoneSystem), array2[i]).GetValue(instance);
				if (array[i] == null || !dictionary.Contains(array[i]))
				{
					continue;
				}
				IList list = (IList)dictionary[array[i]];
				for (int num = list.Count - 1; num >= 0; num--)
				{
					if (ZoneSystem.GetZone(((LocationInstance)list[num]).m_position) == id)
					{
						list.RemoveAt(num);
					}
				}
			}
			if (target != null)
			{
				AccessTools.Method(typeof(ZoneSystem), "RegisterLocation", (Type[])null, (Type[])null).Invoke(instance, new object[3] { target, point, false });
			}
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "SpawnZone")]
	internal static class FreshZoneScope
	{
		private static readonly Func<ZoneSystem, Vector2s, bool> Generated = AccessTools.MethodDelegate<Func<ZoneSystem, Vector2s, bool>>(AccessTools.Method(typeof(ZoneSystem), "IsZoneGenerated", (Type[])null, (Type[])null), (object)null, true);

		[HarmonyPriority(int.MaxValue)]
		private unsafe static bool Prefix(ZoneSystem __instance, Vector2s __0, out FutureGeneration.Scope __state, ref bool __result)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || Generated(__instance, __0) || !FutureGeneration.Swamp(__0))
			{
				return true;
			}
			if (PrimeSwampRevivalPlugin.Active && !PrimeSwampRevivalPlugin.ContentReady)
			{
				__result = false;
				return false;
			}
			__state = new FutureGeneration.Scope
			{
				Zone = __0,
				Restored = FuturePolicy.Generate(alreadyGenerated: false, PrimeSwampRevivalPlugin.Active, PrimeSwampRevivalPlugin.ContentReady),
				Previous = FutureGeneration.Current
			};
			FutureGeneration.Current = __state;
			PrimeSwampRevivalPlugin instance = PrimeSwampRevivalPlugin.Instance;
			if (instance != null)
			{
				string[] obj = new string[5] { "NEW_ZONE_BEGIN zone=", null, null, null, null };
				Vector2s val = __0;
				obj[1] = ((object)(*(Vector2s*)(&val))/*cast due to .constrained prefix*/).ToString();
				obj[2] = " restored=";
				obj[3] = __state.Restored.ToString();
				obj[4] = " nativePreviouslyGenerated=False";
				instance.Note(string.Concat(obj));
			}
			return true;
		}

		private unsafe static Exception Finalizer(FutureGeneration.Scope __state, Exception __exception)
		{
			//IL_0014: 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)
			if (__state != null)
			{
				PrimeSwampRevivalPlugin instance = PrimeSwampRevivalPlugin.Instance;
				if (instance != null)
				{
					Vector2s zone = __state.Zone;
					instance.Note("NEW_ZONE_END zone=" + ((object)(*(Vector2s*)(&zone))/*cast due to .constrained prefix*/).ToString() + " success=" + (__exception == null));
				}
				FutureGeneration.Current = __state.Previous;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "PlaceLocations")]
	internal static class FutureLocationSlot
	{
		[HarmonyPriority(int.MaxValue)]
		private unsafe static void Prefix(Vector2s __0)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0067: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_0180: 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)
			FutureGeneration.Scope current = FutureGeneration.Current;
			if (current == null || current.Zone != __0 || !ZoneSystem.instance.m_locationInstances.TryGetValue(__0, out var value) || value.m_placed)
			{
				return;
			}
			if (current.Restored && (Integration.Name(value.m_location).StartsWith("PrimeSwamp", StringComparison.Ordinal) || RevivalPolicy.Ordinary(Integration.Name(value.m_location))) && FutureProtection.Occupied(value.m_position, value.m_location.m_exteriorRadius + 3f))
			{
				FutureGeneration.Replace(__0, null, value.m_position);
				PrimeSwampRevivalPlugin instance = PrimeSwampRevivalPlugin.Instance;
				if (instance != null)
				{
					Vector2s val = __0;
					instance.Note("NEW_ZONE_LOCATION_SKIPPED protected persistent content zone=" + ((object)(*(Vector2s*)(&val))/*cast due to .constrained prefix*/).ToString());
				}
				return;
			}
			string text = Integration.Name(value.m_location);
			ZoneLocation val2 = null;
			if (!current.Restored && text.StartsWith("PrimeSwamp", StringComparison.Ordinal))
			{
				string prefix = FuturePolicy.VanillaPrefix(text);
				List<ZoneLocation> source = (List<ZoneLocation>)Integration.Field("ExpandWorldData.Locations.LocationManager", "DefaultEntries");
				if (prefix != null)
				{
					val2 = ((IEnumerable<ZoneLocation>)source).FirstOrDefault((Func<ZoneLocation, bool>)((ZoneLocation l) => (l.m_biome & 2) != 0 && Integration.Name(l).StartsWith(prefix, StringComparison.Ordinal)));
				}
			}
			else
			{
				if (!current.Restored || text.StartsWith("PrimeSwamp", StringComparison.Ordinal))
				{
					return;
				}
				string text2 = RevivalPolicy.Replacement(text);
				if (text2 == null)
				{
					return;
				}
				val2 = Integration.Canonical(text2);
				if (val2 == null)
				{
					return;
				}
			}
			FutureGeneration.Replace(__0, val2, value.m_position);
			PrimeSwampRevivalPlugin instance2 = PrimeSwampRevivalPlugin.Instance;
			if (instance2 != null)
			{
				string[] obj = new string[6] { "NEW_ZONE_LOCATION zone=", null, null, null, null, null };
				Vector2s val = __0;
				obj[1] = ((object)(*(Vector2s*)(&val))/*cast due to .constrained prefix*/).ToString();
				obj[2] = " ";
				obj[3] = text;
				obj[4] = " -> ";
				obj[5] = ((val2 == null) ? "empty pre-restoration slot" : Integration.Name(val2));
				instance2.Note(string.Concat(obj));
			}
		}
	}
	internal static class FuturePolicy
	{
		internal static bool Generate(bool alreadyGenerated, bool restored, bool cinematicReleased)
		{
			return !alreadyGenerated && restored && cinematicReleased;
		}

		internal static string VanillaPrefix(string prime)
		{
			if (prime.StartsWith("PrimeSwampHut", StringComparison.Ordinal))
			{
				return "SwampHut";
			}
			if (prime.StartsWith("PrimeSwampRuin", StringComparison.Ordinal))
			{
				return "SwampRuin";
			}
			return prime switch
			{
				"PrimeSwampWell1" => "SwampWell", 
				"PrimeSwampTower1" => "StoneTower", 
				"PrimeSwampSquare1" => "Runestone", 
				_ => null, 
			};
		}
	}
	internal static class FutureProtection
	{
		private static readonly int Creator = (int)AccessTools.Field(typeof(ZDOVars), "s_creator").GetValue(null);

		private static readonly int TerrainData = (int)AccessTools.Field(typeof(ZDOVars), "s_TCData").GetValue(null);

		internal static bool Occupied(Vector3 point, float radius)
		{
			//IL_0011: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			List<ZDO> list = new List<ZDO>();
			List<ZDO> list2 = new List<ZDO>();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(point), new SimulationDistance(Mathf.CeilToInt(radius / 64f) + 1, 0, false), list, list2);
			list.AddRange(list2);
			foreach (ZDO item in list)
			{
				Vector3 val = item.GetPosition() - point;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > radius * radius)
				{
					continue;
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(item.GetPrefab());
				if (!Object.op_Implicit((Object)(object)prefab))
				{
					return true;
				}
				if (item.GetLong(Creator, 0L) != 0L || Object.op_Implicit((Object)(object)prefab.GetComponent<Container>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Ship>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Plant>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Piece>()))
				{
					return true;
				}
				if (Object.op_Implicit((Object)(object)prefab.GetComponent<TerrainComp>()))
				{
					byte[] byteArray = item.GetByteArray(TerrainData, (byte[])null);
					if (((byteArray != null && byteArray.Length != 0) ? 1 : 0) > (false ? 1 : 0))
					{
						return true;
					}
				}
				else if (Object.op_Implicit((Object)(object)prefab.GetComponent<Character>()))
				{
					if (item.GetBool("tamed", false))
					{
						return true;
					}
				}
				else if (item.Persistent && !Object.op_Implicit((Object)(object)prefab.GetComponent<TreeBase>()) && !Object.op_Implicit((Object)(object)prefab.GetComponent<TreeLog>()) && !Object.op_Implicit((Object)(object)prefab.GetComponent<Pickable>()))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class Integration
	{
		private const Biome Swamp = (Biome)2;

		private static readonly MethodInfo Clone = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null);

		private static List<ZoneVegetation> vegetation;

		private static List<ZoneLocation> locations;

		private static List<Clutter> clutter;

		private static ZoneSystem zone;

		internal static bool ContentApplied;

		private static readonly Dictionary<Renderer, Material[]> vanillaTrees = new Dictionary<Renderer, Material[]>();

		private static readonly Dictionary<SpawnSystemList, List<SpawnData>> spawns = new Dictionary<SpawnSystemList, List<SpawnData>>();

		private static readonly HashSet<SpawnData> ambientOwned = new HashSet<SpawnData>();

		private static readonly SpawnRefreshGate spawnRefresh = new SpawnRefreshGate();

		private static readonly Dictionary<SpawnSystemList, List<SpawnData>> preparedSpawns = new Dictionary<SpawnSystemList, List<SpawnData>>();

		private static readonly FieldInfo spawnDefaults = AccessTools.Field(AccessTools.TypeByName("ExpandWorldData.Spawn.SpawnManager"), "Defaults");

		private static readonly FieldInfo spawnOverride = AccessTools.Field(AccessTools.TypeByName("ExpandWorldData.Spawn.SpawnManager"), "Override");

		private static readonly HashSet<int> wildlifeHashes = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("Boar"),
			StringExtensionMethods.GetStableHashCode("Neck")
		};

		internal static IReadOnlyList<ZoneLocation> ConfiguredLocations => locations;

		internal static bool ProtectedWildlife(Character character)
		{
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			int item = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO().GetPrefab() : StringExtensionMethods.GetStableHashCode(((Object)((Component)character).gameObject).name.Replace("(Clone)", "").Trim()));
			return wildlifeHashes.Contains(item);
		}

		internal static object Field(string type, string field)
		{
			return AccessTools.Field(AccessTools.TypeByName(type), field).GetValue(null);
		}

		internal static string Name(ZoneLocation l)
		{
			if (!string.IsNullOrEmpty(l.m_prefabName))
			{
				return l.m_prefabName;
			}
			return l.m_name;
		}

		private static T Copy<T>(T item)
		{
			return (T)Clone.Invoke(item, null);
		}

		internal static void Install(Harmony h)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			Patch(h, "ExpandWorldData.Vegetation.VegetationManager", "LoadAndApply", "VegetationLoaded", prefix: false);
			Patch(h, "ExpandWorldData.Locations.LocationManager", "LoadAndApply", "LocationsLoaded", prefix: false);
			Patch(h, "ExpandWorldData.Clutter.ClutterManager", "Set", "ClutterLoaded", prefix: false);
			Patch(h, "ExpandWorldData.Spawn.SpawnManager", "ApplySpawnData", "SpawnsLoaded", prefix: false);
			string[] array = new string[2] { "TryGetColor", "TryGetData" };
			foreach (string method in array)
			{
				Patch(h, "ExpandWorldData.Biome.BiomeManager", method, "BiomeGate", prefix: true);
			}
			array = new string[2] { "GetTerrain", "GetNature" };
			foreach (string method2 in array)
			{
				Patch(h, "ExpandWorldData.Biome.BiomeManager", method2, "BiomeIdentity", prefix: true);
			}
			Type type = AccessTools.TypeByName("CustomTextures.BepInExPlugin");
			if (type != null)
			{
				h.Patch((MethodBase)AccessTools.Method(type, "LoadTexture", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Integration), "TextureGate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void Patch(Harmony h, string type, string method, string hook, bool prefix)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName(type), method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				throw new MissingMethodException(type, method);
			}
			HarmonyMethod val = new HarmonyMethod(typeof(Integration), hook, (Type[])null)
			{
				priority = (prefix ? 800 : 0)
			};
			h.Patch((MethodBase)methodInfo, prefix ? val : null, prefix ? null : val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static List<T> Merge<T>(IEnumerable<T> configured, IEnumerable<T> defaults, string biomeField)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			FieldInfo fieldInfo = AccessTools.Field(typeof(T), biomeField);
			List<T> list = new List<T>();
			foreach (T item in configured ?? Enumerable.Empty<T>())
			{
				Biome val = (Biome)((Biome)fieldInfo.GetValue(item) & -3);
				if ((int)val != 0)
				{
					T val2 = Copy(item);
					fieldInfo.SetValue(val2, val);
					list.Add(val2);
				}
			}
			foreach (T item2 in defaults ?? Enumerable.Empty<T>())
			{
				if (((Biome)fieldInfo.GetValue(item2) & 2) != 0)
				{
					T val3 = Copy(item2);
					fieldInfo.SetValue(val3, (object)(Biome)2);
					list.Add(val3);
				}
			}
			return list;
		}

		private static void TrackZone()
		{
			if (!((Object)(object)zone == (Object)(object)ZoneSystem.instance))
			{
				zone = ZoneSystem.instance;
				vegetation = null;
				locations = null;
				ContentApplied = false;
			}
		}

		private static void VegetationLoaded()
		{
			TrackZone();
			if (Object.op_Implicit((Object)(object)zone))
			{
				vegetation = new List<ZoneVegetation>(zone.m_vegetation);
				ApplyVegetation();
			}
		}

		private static void LocationsLoaded()
		{
			TrackZone();
			if (Object.op_Implicit((Object)(object)zone))
			{
				locations = new List<ZoneLocation>(zone.m_locations);
				ApplyLocations();
			}
		}

		private static void ClutterLoaded()
		{
			if (Object.op_Implicit((Object)(object)ClutterSystem.instance))
			{
				clutter = new List<Clutter>(ClutterSystem.instance.m_clutter);
				ApplyClutter();
			}
		}

		private static void SpawnsLoaded(SpawnSystem __0)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Invalid comparison between Unknown and I4
			IList list = (IList)spawnDefaults.GetValue(null);
			if (list == null)
			{
				return;
			}
			List<SpawnData> list2 = (List<SpawnData>)spawnOverride.GetValue(null);
			if (spawnRefresh.Matches(ZoneSystem.instance, list2, list, list2?.Count ?? 0, list.Count))
			{
				bool flag = true;
				foreach (SpawnSystemList spawnList in __0.m_spawnLists)
				{
					if (Object.op_Implicit((Object)(object)spawnList) && preparedSpawns.TryGetValue(spawnList, out var value))
					{
						spawnList.m_spawners = value;
					}
					else
					{
						flag = false;
					}
				}
				if (flag)
				{
					return;
				}
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			spawns.Clear();
			preparedSpawns.Clear();
			ambientOwned.Clear();
			foreach (object item in list)
			{
				Type type = item.GetType();
				SpawnSystemList val = (SpawnSystemList)type.GetField("Item1").GetValue(item);
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				List<SpawnData> list3 = (List<SpawnData>)type.GetField("Item2").GetValue(item);
				bool flag2 = list2 != null && __0.m_spawnLists.Contains(val);
				spawns[val] = new List<SpawnData>(flag2 ? list2 : list3);
				foreach (SpawnData item2 in spawns[val])
				{
					if (Object.op_Implicit((Object)(object)item2.m_prefab) && AmbientPolicy.Selected(((Object)item2.m_prefab).name, (item2.m_biome & 2) > 0))
					{
						wildlifeHashes.Add(StringExtensionMethods.GetStableHashCode(((Object)item2.m_prefab).name));
					}
				}
				val.m_spawners = Merge(spawns[val], (List<SpawnData>)type.GetField("Item2").GetValue(item), "m_biome");
				preparedSpawns[val] = val.m_spawners;
			}
			if (PrimeSwampRevivalPlugin.ContentReady)
			{
				ApplyAmbientSpawns();
			}
			spawnRefresh.Remember(ZoneSystem.instance, list2, list, list2?.Count ?? 0, list.Count);
			PrimeSwampRevivalPlugin.Instance?.Note("SPAWN_TABLE_PREPARED lists=" + preparedSpawns.Count + " configured=" + (list2?.Count ?? 0) + " elapsedMs=" + stopwatch.Elapsed.TotalMilliseconds.ToString("F2", CultureInfo.InvariantCulture) + "; subsequent zone loads reuse rules");
		}

		private static void ApplyAmbientSpawns()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<SpawnSystemList, List<SpawnData>> spawn in spawns)
			{
				if (Object.op_Implicit((Object)(object)spawn.Key))
				{
					spawn.Key.m_spawners.RemoveAll((SpawnData e) => ambientOwned.Contains(e));
				}
			}
			ambientOwned.Clear();
			foreach (KeyValuePair<SpawnSystemList, List<SpawnData>> spawn2 in spawns)
			{
				if (!Object.op_Implicit((Object)(object)spawn2.Key))
				{
					continue;
				}
				HashSet<string> hashSet = new HashSet<string>();
				foreach (SpawnData item in spawn2.Value)
				{
					if (!Object.op_Implicit((Object)(object)item.m_prefab) || !AmbientPolicy.Selected(((Object)item.m_prefab).name, (item.m_biome & 2) > 0) || AmbientPolicy.DaySpirit(((Object)item.m_prefab).name, item.m_spawnAtDay, item.m_spawnAtNight))
					{
						continue;
					}
					string text = item.m_name + "/" + ((Object)item.m_prefab).name;
					if (hashSet.Add(text))
					{
						if (!string.IsNullOrEmpty(item.m_requiredGlobalKey) && item.m_requiredGlobalKey != PrimeSwampRevivalPlugin.Key)
						{
							PrimeSwampRevivalPlugin.Instance?.Note("AMBIENT_SKIPPED conflicting required key " + text);
							continue;
						}
						SpawnData val = Copy<SpawnData>(item);
						val.m_biome = (Biome)2;
						val.m_requiredGlobalKey = PrimeSwampRevivalPlugin.Key;
						spawn2.Key.m_spawners.Add(val);
						ambientOwned.Add(val);
						PrimeSwampRevivalPlugin.Instance?.Note("AMBIENT_ENABLED " + text + " cap=" + val.m_maxSpawned + " interval=" + val.m_spawnInterval + " chance=" + val.m_spawnChance + " day=" + val.m_spawnAtDay + " night=" + val.m_spawnAtNight);
					}
				}
			}
		}

		internal static string AmbientSummary()
		{
			return string.Join("; ", ambientOwned.Select((SpawnData e) => ((Object)e.m_prefab).name + "/" + e.m_name + " cap=" + e.m_maxSpawned + " key=" + e.m_requiredGlobalKey));
		}

		private static bool BiomeGate(Biome __0, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)__0 != 2 || PrimeSwampRevivalPlugin.VisualReady)
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool BiomeIdentity(Biome __0, ref Biome __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)__0 != 2 || PrimeSwampRevivalPlugin.VisualReady)
			{
				return true;
			}
			__result = (Biome)2;
			return false;
		}

		private static bool TreeGate()
		{
			return PrimeSwampRevivalPlugin.VisualReady;
		}

		private static bool TextureGate(string __0, Texture __1, ref Texture2D __result)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (PrimeSwampRevivalPlugin.VisualReady || (__0 ?? "").IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) < 0 || !(__1 is Texture2D))
			{
				return true;
			}
			__result = (Texture2D)__1;
			return false;
		}

		private static void ApplyVegetation()
		{
			if (Object.op_Implicit((Object)(object)zone) && vegetation != null)
			{
				zone.m_vegetation = (PrimeSwampRevivalPlugin.Active ? vegetation : Merge(vegetation, (List<ZoneVegetation>)Field("ExpandWorldData.Vegetation.VegetationManager", "DefaultEntries"), "m_biome"));
				ContentApplied = PrimeSwampRevivalPlugin.Active;
			}
		}

		private static void ApplyLocations()
		{
			if (!Object.op_Implicit((Object)(object)zone) || locations == null)
			{
				return;
			}
			zone.m_locations = locations.Where((ZoneLocation l) => (l.m_biome & 2) == 0 || !RevivalPolicy.Ordinary(Name(l)) || Name(l).StartsWith("Prime", StringComparison.Ordinal)).ToList();
			Dictionary<int, ZoneLocation> dictionary = (Dictionary<int, ZoneLocation>)AccessTools.Field(typeof(ZoneSystem), "m_locationsByHash").GetValue(zone);
			foreach (ZoneLocation item in (List<ZoneLocation>)Field("ExpandWorldData.Locations.LocationManager", "DefaultEntries"))
			{
				if (!string.IsNullOrEmpty(item.m_prefabName) && !dictionary.ContainsKey(StringExtensionMethods.GetStableHashCode(item.m_prefabName)))
				{
					dictionary[StringExtensionMethods.GetStableHashCode(item.m_prefabName)] = item;
				}
			}
		}

		private static void ApplyClutter()
		{
			if (Object.op_Implicit((Object)(object)ClutterSystem.instance) && clutter != null)
			{
				ClutterSystem.instance.m_clutter = Merge(clutter, (List<Clutter>)Field("ExpandWorldData.Clutter.ClutterManager", "DefaultEntries"), "m_biome");
				AccessTools.Field(typeof(ClutterSystem), "m_forceRebuild").SetValue(ClutterSystem.instance, true);
			}
		}

		internal static void Apply()
		{
			TrackZone();
			ApplyVegetation();
			ApplyLocations();
			ApplyClutter();
			if (PrimeSwampRevivalPlugin.Active)
			{
				return;
			}
			foreach (KeyValuePair<Renderer, Material[]> vanillaTree in vanillaTrees)
			{
				if (Object.op_Implicit((Object)(object)vanillaTree.Key))
				{
					vanillaTree.Key.sharedMaterials = vanillaTree.Value;
				}
			}
		}

		internal static void SnapshotTrees(ZNetScene scene)
		{
			KeyValuePair<Renderer, Material[]>[] array = vanillaTrees.Where((KeyValuePair<Renderer, Material[]> e) => !Object.op_Implicit((Object)(object)e.Key)).ToArray();
			for (int num = 0; num < array.Length; num++)
			{
				KeyValuePair<Renderer, Material[]> keyValuePair = array[num];
				Material[] value = keyValuePair.Value;
				foreach (Material val in value)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						Object.Destroy((Object)(object)val);
					}
				}
				vanillaTrees.Remove(keyValuePair.Key);
			}
			SpawnSystemList[] array2 = spawns.Keys.Where((SpawnSystemList k) => !Object.op_Implicit((Object)(object)k)).ToArray();
			foreach (SpawnSystemList key in array2)
			{
				spawns.Remove(key);
			}
			foreach (KeyValuePair<Renderer, Material[]> vanillaTree in vanillaTrees)
			{
				if (Object.op_Implicit((Object)(object)vanillaTree.Key))
				{
					vanillaTree.Key.sharedMaterials = vanillaTree.Value;
				}
			}
			foreach (GameObject item in scene.m_prefabs.Concat(scene.m_nonNetViewPrefabs))
			{
				if (!Object.op_Implicit((Object)(object)item) || ((Object)item).name.IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				Renderer[] componentsInChildren = item.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					if (!vanillaTrees.ContainsKey(val2))
					{
						vanillaTrees[val2] = ((IEnumerable<Material>)val2.sharedMaterials).Select((Func<Material, Material>)((Material m) => Object.op_Implicit((Object)(object)m) ? new Material(m) : ((Material)null))).ToArray();
					}
				}
			}
		}

		internal static IEnumerable<ScheduledWork> ActivationWork()
		{
			yield return new ScheduledWork("tables/vegetation", delegate
			{
				TrackZone();
				ApplyVegetation();
			});
			yield return new ScheduledWork("tables/locations", ApplyLocations);
			yield return new ScheduledWork("tables/ambient-spawns", ApplyAmbientSpawns);
			yield return new ScheduledWork("environment", BiomeState.Apply);
			foreach (ScheduledWork item in RefreshVisuals())
			{
				yield return item;
			}
		}

		internal static IEnumerable<ScheduledWork> RefreshVisuals()
		{
			Type trees = AccessTools.TypeByName("PrimeSwampTrees.PrimeSwampTreesPlugin");
			object instance = ((trees == null) ? null : AccessTools.Field(trees, "Instance").GetValue(null));
			Type type = AccessTools.TypeByName("CustomTextures.BepInExPlugin");
			MethodInfo replace = ((type == null) ? null : AccessTools.Method(type, "ReplaceOneGameObjectTextures", new Type[3]
			{
				typeof(GameObject),
				typeof(string),
				typeof(string)
			}, (Type[])null));
			HashSet<GameObject> roots = new HashSet<GameObject>();
			if (Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				foreach (GameObject item in ZNetScene.instance.m_prefabs.Concat(ZNetScene.instance.m_nonNetViewPrefabs))
				{
					if (Object.op_Implicit((Object)(object)item))
					{
						roots.Add(item);
					}
				}
			}
			if (Object.op_Implicit((Object)(object)ClutterSystem.instance))
			{
				foreach (Clutter item2 in ClutterSystem.instance.m_clutter)
				{
					if (Object.op_Implicit((Object)(object)item2.m_prefab))
					{
						roots.Add(item2.m_prefab);
					}
				}
			}
			foreach (GameObject item3 in roots.Where((GameObject r) => Object.op_Implicit((Object)(object)r) && ((Object)r).name.IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				GameObject saved = item3;
				if (!(replace != null) || !(((Object)saved).name != "_NetSceneRoot"))
				{
					continue;
				}
				yield return new ScheduledWork("textures/prefab=" + ((Object)saved).name, delegate
				{
					if (Object.op_Implicit((Object)(object)saved))
					{
						replace.Invoke(null, new object[3]
						{
							saved,
							((Object)saved).name,
							"object"
						});
					}
				});
			}
			if (instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				yield break;
			}
			yield return new ScheduledWork("trees/cache", delegate
			{
				AccessTools.Method(AccessTools.Field(trees, "prepared").FieldType, "Clear", (Type[])null, (Type[])null).Invoke(AccessTools.Field(trees, "prepared").GetValue(instance), null);
			});
			MethodInfo prepare = AccessTools.Method(trees, "PrepareGraph", new Type[1] { typeof(GameObject) }, (Type[])null);
			foreach (GameObject item4 in roots.Where((GameObject r) => Object.op_Implicit((Object)(object)r) && ((Object)r).name.IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				GameObject saved2 = item4;
				yield return new ScheduledWork("trees/prefab=" + ((Object)saved2).name, delegate
				{
					if (Object.op_Implicit((Object)(object)saved2))
					{
						prepare.Invoke(instance, new object[1] { saved2 });
					}
				});
			}
			ZNetView[] array = ((Dictionary<ZDO, ZNetView>)AccessTools.Field(typeof(ZNetScene), "m_instances").GetValue(ZNetScene.instance)).Values.ToArray();
			ZNetView[] array2 = array;
			foreach (ZNetView val in array2)
			{
				if (!Object.op_Implicit((Object)(object)val) || ((Object)((Component)val).gameObject).name.IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				ZNetView saved3 = val;
				yield return new ScheduledWork("trees/live=" + (saved3.GetZDO()?.m_uid).ToString(), delegate
				{
					if (Object.op_Implicit((Object)(object)saved3))
					{
						AccessTools.Method(trees, "OnCreated", (Type[])null, (Type[])null).Invoke(instance, new object[2]
						{
							((Component)saved3).gameObject,
							"revival"
						});
					}
				});
			}
		}

		internal static ZoneLocation Canonical(string name)
		{
			return locations?.FirstOrDefault((Func<ZoneLocation, bool>)((ZoneLocation l) => Name(l) == name));
		}

		internal static ZoneLocation VanillaDonor()
		{
			return ((IEnumerable<ZoneLocation>)(List<ZoneLocation>)Field("ExpandWorldData.Locations.LocationManager", "DefaultEntries")).FirstOrDefault((Func<ZoneLocation, bool>)((ZoneLocation l) => Name(l) == "SwampHut1"));
		}
	}
	[HarmonyPatch(typeof(EnvMan), "GetBiomeEnvSetup")]
	internal static class VanillaSwampEnvironment
	{
		[HarmonyPriority(0)]
		private static void Postfix(Biome __0, ref BiomeEnvSetup __result)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if (__result != null && (int)__0 == 2 && !PrimeSwampRevivalPlugin.VisualReady)
			{
				__result = BiomeState.NativeSwamp ?? __result;
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class TreeSnapshot
	{
		[HarmonyPriority(800)]
		private static void Prefix(ZNetScene __instance)
		{
			Integration.SnapshotTrees(__instance);
		}

		[HarmonyPriority(0)]
		private static void Postfix()
		{
			Integration.Apply();
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "SpawnLocation")]
	internal static class WellTerrainContext
	{
		internal sealed class Frame
		{
			internal Vector3 Origin;

			internal Quaternion Rotation;

			internal Frame Previous;

			internal bool Applied;
		}

		internal static Frame Current;

		[HarmonyPriority(int.MaxValue)]
		private static void Prefix(ZoneLocation __0, Vector3 __2, Quaternion __3, SpawnMode __4, out Frame __state)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0036: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			FutureGeneration.Scope current = FutureGeneration.Current;
			if (current != null && current.Restored && (int)__4 != 1 && !(Integration.Name(__0) != "PrimeSwampWell1"))
			{
				__state = new Frame
				{
					Origin = __2,
					Rotation = __3,
					Previous = Current
				};
				Current = __state;
			}
		}

		private static Exception Finalizer(Frame __state, Exception __exception)
		{
			if (__state != null)
			{
				Current = __state.Previous;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(LocationObjectDataAndSwap), "HandleTerrain")]
	internal static class ExcavateWellInterior
	{
		private static readonly FieldInfo Build = AccessTools.Field(typeof(Heightmap), "m_buildData");

		private static readonly FieldInfo Heights = AccessTools.Field(Build.FieldType, "m_baseHeights");

		private unsafe static void Postfix()
		{
			//IL_0034: 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)
			//IL_004e: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			WellTerrainContext.Frame current = WellTerrainContext.Current;
			if (current == null || current.Applied)
			{
				return;
			}
			FutureGeneration.Scope current2 = FutureGeneration.Current;
			if (current2 == null || !current2.Restored)
			{
				return;
			}
			current.Applied = true;
			try
			{
				Vector3 center = current.Origin + current.Rotation * new Vector3(0f, 0f, 0.249f);
				Heightmap val = Heightmap.FindHeightmap(center);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return;
				}
				float groundHeight = ZoneSystem.instance.GetGroundHeight(center);
				float water = ZoneSystem.instance.m_waterLevel;
				if (!LocationTerrainPolicy.Reachable(groundHeight, water))
				{
					PrimeSwampRevivalPlugin instance = PrimeSwampRevivalPlugin.Instance;
					if (instance != null)
					{
						Vector3 val2 = center;
						instance.Note("WELL_WATER_SKIPPED natural water requires more than 6m excavation at " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString());
					}
				}
				else
				{
					if (1.5f + 1.415f * val.m_scale > 3.75f)
					{
						return;
					}
					int cx = default(int);
					int cz = default(int);
					val.WorldToVertex(center, ref cx, ref cz);
					int reach = Mathf.CeilToInt(1.5f / val.m_scale) + 1;
					if (cx - reach < 1 || cz - reach < 1 || cx + reach >= val.m_width || cz + reach >= val.m_width)
					{
						return;
					}
					int changed = 0;
					Terrain.ChangeTerrain(center, (Action<Heightmap, TerrainFakeData>)delegate(Heightmap hm, TerrainFakeData data)
					{
						//IL_0029: Unknown result type (might be due to invalid IL or missing references)
						//IL_002e: Unknown result type (might be due to invalid IL or missing references)
						//IL_0056: Unknown result type (might be due to invalid IL or missing references)
						//IL_008d: Unknown result type (might be due to invalid IL or missing references)
						//IL_0092: Unknown result type (might be due to invalid IL or missing references)
						//IL_0097: Unknown result type (might be due to invalid IL or missing references)
						//IL_01de: Unknown result type (might be due to invalid IL or missing references)
						List<float> list = (List<float>)Heights.GetValue(Build.GetValue(hm));
						List<KeyValuePair<int, float>> list2 = new List<KeyValuePair<int, float>>(25);
						Vector3 position = ((Component)hm).transform.position;
						for (int i = cz - reach; i <= cz + reach; i++)
						{
							for (int j = cx - reach; j <= cx + reach; j++)
							{
								Vector3 val3 = position + new Vector3(((float)(j - hm.m_width / 2) + 0.5f) * hm.m_scale, 0f, ((float)(i - hm.m_width / 2) + 0.5f) * hm.m_scale);
								float num = val3.x - center.x;
								float num2 = val3.z - center.z;
								float num3 = LocationTerrainPolicy.Weight(Mathf.Sqrt(num * num + num2 * num2));
								if (!(num3 <= 0f))
								{
									int num4 = i * (hm.m_width + 1) + j;
									float height = hm.GetHeight(j, i);
									float num5 = Mathf.Min(height, Mathf.Lerp(height, water - 0.35f, num3));
									if (!LocationTerrainPolicy.Allowed(height, num5, list[num4]))
									{
										return;
									}
									if (height - num5 > 0.001f)
									{
										list2.Add(new KeyValuePair<int, float>(num4, num5 - list[num4]));
									}
								}
							}
						}
						foreach (KeyValuePair<int, float> item in list2)
						{
							if (data.SetHeight(item.Key, item.Value))
							{
								changed++;
							}
						}
						if (changed > 0)
						{
							data.MarkOperation(center, 1.5f);
						}
					});
					PrimeSwampRevivalPlugin instance2 = PrimeSwampRevivalPlugin.Instance;
					if (instance2 != null)
					{
						string[] obj = new string[6] { "WELL_WATER initial-generation center=", null, null, null, null, null };
						Vector3 val2 = center;
						obj[1] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
						obj[2] = " outerRadius=1.5 coreRadius=1 target=";
						obj[3] = (water - 0.35f).ToString();
						obj[4] = " vertices=";
						obj[5] = changed.ToString();
						instance2.Note(string.Concat(obj));
					}
				}
			}
			catch (Exception ex)
			{
				PrimeSwampRevivalPlugin.Instance?.Note("WELL_WATER_FAILED retained building geometry: " + ex);
			}
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "PlaceLocations")]
	internal static class TowerVegetationClearing
	{
		private static readonly Type Area = typeof(ZoneSystem).GetNestedType("ClearArea", BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo Center = AccessTools.Field(Area, "m_center");

		private static readonly FieldInfo Radius = AccessTools.Field(Area, "m_radius");

		[HarmonyPriority(int.MinValue)]
		private static void Prefix(Vector2s __0, out Vector3? __state)
		{
			//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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			__state = null;
			FutureGeneration.Scope current = FutureGeneration.Current;
			if (current != null && current.Restored && !(FutureGeneration.Current.Zone != __0) && ZoneSystem.instance.m_locationInstances.TryGetValue(__0, out var value) && !value.m_placed && Integration.Name(value.m_location) == "PrimeSwampTower1")
			{
				__state = value.m_position;
			}
		}

		private static void Postfix(Vector3? __state, object __4)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!__state.HasValue)
			{
				return;
			}
			foreach (object item in (IList)__4)
			{
				Vector3 val = (Vector3)Center.GetValue(item) - __state.Value;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
				{
					Radius.SetValue(item, Mathf.Min((float)Radius.GetValue(item), 6f));
				}
			}
		}
	}
	internal static class LocationTerrainPolicy
	{
		internal const float WellOffset = -6.95f;

		internal const float CenterZ = 0.249f;

		internal const float CoreRadius = 1f;

		internal const float OuterRadius = 1.5f;

		internal const float WaterDepth = 0.35f;

		internal const float MaxDig = 6f;

		internal const float NativeLimit = 8f;

		internal const float TowerClearRadius = 6f;

		internal static bool Reachable(float ground, float water)
		{
			if (!float.IsNaN(ground) && !float.IsInfinity(ground))
			{
				return ground - (water - 0.35f) <= 6f;
			}
			return false;
		}

		internal static float Weight(float radius)
		{
			if (radius >= 1.5f)
			{
				return 0f;
			}
			if (radius <= 1f)
			{
				return 1f;
			}
			float num = (1.5f - radius) / 0.5f;
			return num * num * (3f - 2f * num);
		}

		internal static bool Allowed(float current, float target, float original)
		{
			if (!float.IsNaN(target) && !float.IsInfinity(target) && target <= current && current - target <= 6f)
			{
				return Math.Abs(target - original) <= 8f;
			}
			return false;
		}
	}
	internal sealed class MatchingBuckets<T>
	{
		private readonly List<T> entries;

		private readonly Func<T, string, bool> matches;

		private readonly Dictionary<string, List<T>> buckets = new Dictionary<string, List<T>>(StringComparer.Ordinal);

		internal long MatchCalls;

		internal MatchingBuckets(IEnumerable<T> source, Func<T, string, bool> predicate)
		{
			entries = new List<T>(source);
			matches = predicate;
		}

		internal List<T> Get(string group)
		{
			group = group ?? "";
			if (buckets.TryGetValue(group, out var value))
			{
				return value;
			}
			value = new List<T>();
			foreach (T entry in entries)
			{
				MatchCalls++;
				if (matches(entry, group))
				{
					value.Add(entry);
				}
			}
			buckets.Add(group, value);
			return value;
		}

		internal void Add(T entry)
		{
			entries.Add(entry);
			foreach (KeyValuePair<string, List<T>> bucket in buckets)
			{
				MatchCalls++;
				if (matches(entry, bucket.Key))
				{
					bucket.Value.Add(entry);
				}
			}
		}
	}
	internal static class PackagedTextureSearch
	{
		internal static string Resolve(string assemblyLocation)
		{
			return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(assemblyLocation), "..", "CustomTextures"));
		}

		internal static bool Exists(string native, string packaged)
		{
			if (!Directory.Exists(native))
			{
				return Directory.Exists(packaged);
			}
			return true;
		}

		internal static string[] Files(string native, string pattern, SearchOption option, string packaged)
		{
			List<string> list = new List<string>();
			if (Directory.Exists(packaged))
			{
				list.AddRange(Directory.GetFiles(packaged, pattern, option));
			}
			if (Directory.Exists(native) && !string.Equals(Path.GetFullPath(native), Path.GetFullPath(packaged), StringComparison.OrdinalIgnoreCase))
			{
				list.AddRange(Directory.GetFiles(native, pattern, option));
			}
			return list.ToArray();
		}
	}
	internal static class Performance
	{
		internal sealed class Work : IDisposable
		{
			private readonly Work previous;

			private readonly long start = Stopwatch.GetTimestamp();

			private readonly string name;

			internal double Elapsed => (double)(Stopwatch.GetTimestamp() - start) * 1000.0 / (double)Stopwatch.Frequency;

			internal Work(string value)
			{
				_ = CanStart;
				name = value;
				previous = current;
				current = this;
				Last = name;
				PrimeSwampRevivalPlugin.Instance?.Note("WORK_START " + name + " frame=" + Time.frameCount);
			}

			public void Dispose()
			{
				double elapsed = Elapsed;
				current = previous;
				if (previous == null)
				{
					allowance.Charge(elapsed);
				}
				PrimeSwampRevivalPlugin.Instance?.Note("WORK_END " + name + " elapsedMs=" + elapsed.ToString("F2", CultureInfo.InvariantCulture));
				if (elapsed > 4.0)
				{
					PrimeSwampRevivalPlugin.Instance?.Note("BUDGET_WARNING " + name + " elapsedMs=" + elapsed.ToString("F2", CultureInfo.InvariantCulture) + " targetMs=4 atomic engine call or batch exceeded target");
				}
			}
		}

		private static readonly FrameAllowance allowance = new FrameAllowance();

		private static Work current;

		internal static string Last = "idle";

		internal static bool CanStart
		{
			get
			{
				allowance.Reset(Time.frameCount);
				return allowance.CanStart;
			}
		}

		internal static Work Begin(string name)
		{
			return new Work(name);
		}

		internal static void Run(string name, Action action)
		{
			using (Begin(name))
			{
				action();
			}
		}
	}
	internal sealed class PrimeMusicSetting
	{
		public string name { get; set; }

		public string[] clips { get; set; } = Array.Empty<string>();

		public float volume { get; set; }

		public float fadeInTime { get; set; }

		public bool alwaysFadeOut { get; set; }

		public bool loop { get; set; }

		public bool resume { get; set; }

		public bool ambientMusic { get; set; }
	}
	internal static class PrimeMusicSettings
	{
		internal static void Validate(IEnumerable<PrimeMusicSetting> entries)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (PrimeMusicSetting entry in entries)
			{
				if (entry == null || string.IsNullOrWhiteSpace(entry.name) || !hashSet.Add(entry.name) || entry.clips == null || entry.clips.Any(string.IsNullOrWhiteSpace) || float.IsNaN(entry.volume) || float.IsInfinity(entry.volume) || entry.volume < 0f || float.IsNaN(entry.fadeInTime) || float.IsInfinity(entry.fadeInTime) || entry.fadeInTime < 0f)
				{
					throw new ArgumentException("Invalid/duplicate Prime music setting");
				}
			}
		}

		internal static bool CanResolve(PrimeMusicSetting entry, ISet<string> clips)
		{
			return entry.clips.All(clips.Contains);
		}
	}
	internal static class PrimeNativeMusic
	{
		private static PrimeMusicSetting[] entries;

		private static MusicMan applied;

		internal static void Load()
		{
			entries = JsonConvert.DeserializeObject<PrimeMusicSetting[]>(File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(PrimeNativeMusic).Assembly.Location), "Data", "PrimeMusic.json")));
			if (entries == null || entries.Length == 0)
			{
				throw new InvalidDataException("Empty Prime music catalog");
			}
			PrimeMusicSettings.Validate(entries);
		}

		internal static void Apply(MusicMan manager)
		{
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)manager) || (Object)(object)applied == (Object)(object)manager)
			{
				return;
			}
			if (Chainloader.PluginInfos.ContainsKey("expand_world_music"))
			{
				applied = manager;
				PrimeSwampRevivalPlugin.Instance.Note("PRIME_MUSIC_EXTERNAL Expand World Music supplies the music table.");
				return;
			}
			Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>(StringComparer.Ordinal);
			foreach (NamedMusic item in manager.m_music)
			{
				AudioClip[] array = item.m_clips ?? Array.Empty<AudioClip>();
				foreach (AudioClip val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && !clips.ContainsKey(((Object)val).name))
					{
						clips.Add(((Object)val).name, val);
					}
				}
			}
			HashSet<string> clipNames = new HashSet<string>(clips.Keys, StringComparer.Ordinal);
			string[] array2 = (from e in entries
				where !PrimeMusicSettings.CanResolve(e, clipNames)
				select e.name).ToArray();
			if (array2.Length != 0)
			{
				applied = manager;
				PrimeSwampRevivalPlugin.Instance.ReportError("PRIME_MUSIC_MISSING native clips for " + string.Join(", ", array2) + "; native music retained; verify game/dependency baseline.");
				return;
			}
			List<NamedMusic> list = new List<NamedMusic>(manager.m_music);
			PrimeMusicSetting[] array3 = entries;
			foreach (PrimeMusicSetting entry in array3)
			{
				NamedMusic val2 = new NamedMusic
				{
					m_name = entry.name,
					m_clips = entry.clips.Select((string n) => clips[n]).ToArray(),
					m_volume = entry.volume,
					m_fadeInTime = entry.fadeInTime,
					m_alwaysFadeout = entry.alwaysFadeOut,
					m_loop = entry.loop,
					m_resume = entry.resume,
					m_ambientMusic = entry.ambientMusic,
					m_enabled = true
				};
				int num = list.FindIndex((NamedMusic m) => m.m_name == entry.name);
				if (num >= 0)
				{
					list[num] = val2;
				}
				else
				{
					list.Add(val2);
				}
			}
			Dictionary<int, NamedMusic> dictionary = (Dictionary<int, NamedMusic>)AccessTools.Field(typeof(MusicMan), "m_musicHashes").GetValue(manager);
			Dictionary<int, NamedMusic> dictionary2 = new Dictionary<int, NamedMusic>();
			foreach (NamedMusic item2 in list)
			{
				if (item2.m_clips != null && item2.m_clips.Length != 0 && Object.op_Implicit((Object)(object)item2.m_clips[0]))
				{
					int stableHashCode = StringExtensionMethods.GetStableHashCode(item2.m_name);
					if (dictionary2.ContainsKey(stableHashCode))
					{
						applied = manager;
						PrimeSwampRevivalPlugin.Instance.ReportError("PRIME_MUSIC_CONFLICT duplicate music identity " + item2.m_name + "; native table retained.");
						return;
					}
					dictionary2.Add(stableHashCode, item2);
				}
			}
			manager.m_music = list;
			dictionary.Clear();
			foreach (KeyValuePair<int, NamedMusic> item3 in dictionary2)
			{
				dictionary.Add(item3.Key, item3.Value);
			}
			applied = manager;
			PrimeSwampRevivalPlugin.Instance.Note("PRIME_MUSIC_READY entries=" + entries.Length + "; native clips, unchanged release settings; native selection retained.");
		}
	}
	[HarmonyPatch(typeof(MusicMan), "Awake")]
	internal static class PrimeMusicInitialized
	{
		[HarmonyPriority(0)]
		private static void Postfix(MusicMan __instance)
		{
			PrimeNativeMusic.Apply(__instance);
		}
	}
	internal static class PrimeSceneryRegistry
	{
		private static string[] names;

		internal static bool Ready;

		internal static void Install()
		{
			Ready = false;
			string text = Path.Combine(Path.GetDirectoryName(typeof(PrimeSceneryRegistry).Assembly.Location), "Data", "PrimeScenery.json");
			names = JsonConvert.DeserializeObject<string[]>(File.ReadAllText(text));
			if (names == null || names.Length == 0 || names.Any(string.IsNullOrWhiteSpace) || names.Distinct<string>(StringComparer.Ordinal).Count() != names.Length)
			{
				throw new InvalidDataException("Invalid Prime scenery catalog: " + text);
			}
			PrefabManager.OnPrefabsRegistered += Register;
		}

		internal static void Uninstall()
		{
			PrefabManager.OnPrefabsRegistered -= Register;
			Ready = false;
		}

		private static void Register()
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return;
			}
			Ready = false;
			Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(instance);
			List<string> list = new List<string>();
			int num = 0;
			string[] array = names;
			foreach (string text in array)
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode(text);
				if (dictionary.TryGetValue(stableHashCode, out var value))
				{
					if (!Object.op_Implicit((Object)(object)value) || ((Object)value).name != text)
					{
						list.Add(text + " (prefab hash collision)");
					}
					continue;
				}
				if (text.StartsWith("Prime", StringComparison.Ordinal))
				{
					list.Add(text + " (Prime provider did not register)");
					continue;
				}
				GameObject prefab = PrefabManager.Instance.GetPrefab(text);
				if (Object.op_Implicit((Object)(object)prefab) && !(((Object)prefab).name != text))
				{
					Scene scene = prefab.scene;
					if (!((Scene)(ref scene)).IsValid())
					{
						dictionary.Add(stableHashCode, prefab);
						List<GameObject> list2 = (Object.op_Implicit((Object)(object)prefab.GetComponent<ZNetView>()) ? instance.m_prefabs : instance.m_nonNetViewPrefabs);
						if (!list2.Contains(prefab))
						{
							list2.Add(prefab);
						}
						num++;
						continue;
					}
				}
				list.Add(text);
			}
			if (list.Count > 0)
			{
				PrimeSwampRevivalPlugin.Instance.ReportError("PRIME_SCENERY_MISSING " + string.Join(", ", list) + "; do not use this installation on your only world copy.");
				return;
			}
			Ready = true;
			PrimeSwampRevivalPlugin.Instance.Note("PRIME_SCENERY_READY checked=" + names.Length + " registered=" + num + "; native objects only; no build or planting menus added.");
		}
	}
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.prime.swamprevival", "Prime Swamp Revival", "0.1.13")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[BepInDependency("com.prime.swampnpcs", "0.1.9")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("com.primeswamp.trees", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class PrimeSwampRevivalPlugin : BaseUnityPlugin
	{
		internal const string Id = "com.prime.swamprevival";

		internal static PrimeSwampRevivalPlugin Instance;

		internal static long sequenceStart;

		private ZRoutedRpc routed;

		private ZNet world;

		private Harmony harmony;

		private static readonly Func<ZRoutedRpc, long> Server = AccessTools.MethodDelegate<Func<ZRoutedRpc, long>>(AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null), (object)null, true);

		internal static readonly Dictionary<ZDOID, long> BossOwners = new Dictionary<ZDOID, long>();

		internal static string Key => PrimeSwampNPCsPlugin.RestorationStateKey;

		internal static bool Active
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZoneSystem.instance))
				{
					return ZoneSystem.instance.GetGlobalKey(Key);
				}
				return false;
			}
		}

		internal static bool GenerationAllowed => ActivationPolicy.Ready(Active, sequenceStart, Now, 160000000L, Cinematic.Visible, Time.frameCount, Cinematic.ReleasedFrame);

		internal static bool VisualReady => GenerationAllowed;

		internal static bool ContentReady
		{
			get
			{
				if (PrimeSceneryRegistry.Ready && GenerationAllowed && ActivationPipeline.Ready)
				{
					return Integration.ContentApplied;
				}
				return false;
			}
		}

		internal static long Now
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return 0L;
				}
				return ZNet.instance.GetTime().Ticks;
			}
		}

		internal static bool Playing
		{
			get
			{
				if (sequenceStart > 0 && Now >= sequenceStart)
				{
					return Now < sequenceStart + 160000000;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			CinematicSafety.RadiusSetting = ((BaseUnityPlugin)this).Config.Bind<float>("Cinematic", "HostileCleanupRadius", 100f, new ConfigDescription("Server-authoritative one-time hostile cleanup radius around each player receiving the cinematic, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 250f), Array.Empty<object>()));
			Instance = this;
			PrimeSceneryRegistry.Install();
			PrimeNativeMusic.Load();
			harmony = new Harmony("com.prime.swamprevival");
			harmony.PatchAll();
			Integration.Install(harmony);
			BiomeState.Install(harmony);
			FutureGeneration.Install(harmony);
			TextureCompatibility.Install(harmony);
			SimpleDiagnostics.Install();
			if (Object.op_Implicit((Object)(object)MusicMan.instance))
			{
				PrimeNativeMusic.Apply(MusicMan.instance);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"0.1.13 Nexus dependency reduction: Prime tree textures, native scenery registration and native music; no building/planting system.");
		}

		internal void Note(string message)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)message);
		}

		internal void ReportError(string message)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)message);
		}

		internal void EnsureRpc()
		{
			if (ZRoutedRpc.instance == null || routed == ZRoutedRpc.instance)
			{
				return;
			}
			routed = ZRoutedRpc.instance;
			routed.Register<ZDOID>("PrimeSwamp_BonemassDeath", (Action<long, ZDOID>)DeathRequest);
			routed.Register<ZDOID>("PrimeSwamp_BonemassDying", (Action<long, ZDOID>)delegate(long sender, ZDOID id)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
				{
					ZDOMan instance = ZDOMan.instance;
					ZDO val = ((instance != null) ? instance.GetZDO(id) : null);
					if (val != null && val.GetPrefab() == StringExtensionMethods.GetStableHashCode("Bonemass") && val.GetOwner() == sender)
					{
						BossOwners[id] = sender;
					}
				}
			});
			routed.Register<long>("PrimeSwamp_Revival", (Action<long, long>)BeginSequence);
			routed.Register<ZPackage>("PrimeSwamp_CinematicSafety", (Action<long, ZPackage>)delegate(long sender, ZPackage packet)
			{
				if (sender == Server(routed))
				{
					CinematicSafety.Receive(packet);
				}
			});
		}

		private void Update()
		{
			EnsureRpc();
			if ((Object)(object)world != (Object)(object)ZNet.instance)
			{
				world = ZNet.instance;
				sequenceStart = 0L;
				BossOwners.Clear();
				CinematicSafety.Reset();
			}
			ActivationPipeline.Step();
		}

		internal void ReportDeath(ZDOID id)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			EnsureRpc();
			if (routed == null)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				if (BossOwners.TryGetValue(id, out var value))
				{
					DeathRequest(value, id);
				}
			}
			else
			{
				routed.InvokeRoutedRPC(Server(routed), "PrimeSwamp_BonemassDeath", new object[1] { id });
			}
		}

		internal void ObserveDeath(ZDOID id, long owner)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			BossOwners[id] = owner;
			EnsureRpc();
			if (Object.op_Implicit((Object)(object)ZNet.instance

BepInEx/plugins/PrimeSwampTrees/PrimeSwampTrees.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeSwampTrees")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.1.0")]
[assembly: AssemblyInformationalVersion("0.4.1")]
[assembly: AssemblyProduct("PrimeSwampTrees")]
[assembly: AssemblyTitle("PrimeSwampTrees")]
[assembly: AssemblyVersion("0.4.1.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 PrimeSwampTrees
{
	[BepInPlugin("com.primeswamp.trees", "Prime Swamp Trees", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class PrimeSwampTreesPlugin : BaseUnityPlugin
	{
		private static class SceneReady
		{
			private static void Postfix(ZNetScene __instance)
			{
				Guard("ZNetScene.Awake", delegate(PrimeSwampTreesPlugin p)
				{
					p.PrepareScene(__instance);
				});
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class VegetationReady
		{
			[HarmonyPrefix]
			[HarmonyPriority(0)]
			private static void Prefix(ZoneSystem __instance)
			{
				Guard("ZoneSystem.Start", delegate(PrimeSwampTreesPlugin p)
				{
					p.PrepareVegetation(__instance);
				});
			}
		}

		[HarmonyPatch(typeof(TreeBase), "Awake")]
		private static class StandingCreated
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(TreeBase __instance)
			{
				Guard("TreeBase.Awake", delegate(PrimeSwampTreesPlugin p)
				{
					if (p.IsTarget(((Component)__instance).gameObject))
					{
						p.PrepareGraph(__instance.m_logPrefab);
						p.PrepareGraph(__instance.m_stubPrefab);
						p.OnCreated(((Component)__instance).gameObject, "TreeBase.Awake");
					}
				});
			}
		}

		[HarmonyPatch(typeof(TreeLog), "Awake")]
		private static class LogCreated
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(TreeLog __instance)
			{
				Guard("TreeLog.Awake", delegate(PrimeSwampTreesPlugin p)
				{
					if (p.IsTarget(((Component)__instance).gameObject))
					{
						p.PrepareGraph(__instance.m_subLogPrefab);
						p.OnCreated(((Component)__instance).gameObject, "TreeLog.Awake");
					}
				});
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "CreateObject", new Type[] { typeof(ZDO) })]
		private static class NetworkCreated
		{
			[HarmonyPrefix]
			private static void Prefix(ZNetScene __instance, ZDO __0, out bool __state)
			{
				bool target = false;
				Guard("ZNetScene.CreateObject prefix", delegate(PrimeSwampTreesPlugin p)
				{
					GameObject prefab = __instance.GetPrefab(__0.GetPrefab());
					target = p.IsTarget(prefab);
					if (target)
					{
						p.PrepareGraph(prefab);
					}
				});
				__state = target;
			}

			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(GameObject __result, bool __state)
			{
				if (__state)
				{
					Guard("ZNetScene.CreateObject postfix", delegate(PrimeSwampTreesPlugin p)
					{
						p.OnCreated(__result, "ZNetScene.CreateObject");
					});
				}
			}
		}

		public const string PluginId = "com.primeswamp.trees";

		public const string CustomTexturesId = "cjayride.CustomTextures";

		internal static PrimeSwampTreesPlugin Instance;

		public static Func<bool> RestorationGate;

		private Harmony harmony;

		private ConfigEntry<bool> verbose;

		private readonly Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<Material, Material> replacements = new Dictionary<Material, Material>();

		private readonly HashSet<Material> owned = new HashSet<Material>();

		private readonly HashSet<GameObject> prepared = new HashSet<GameObject>();

		private readonly HashSet<int> targetHashes = new HashSet<int>();

		private readonly HashSet<string> messages = new HashSet<string>();

		private readonly HashSet<string> matchedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<int, WeakReference<GameObject>> liveRoots = new Dictionary<int, WeakReference<GameObject>>();

		private readonly List<Texture2D> retiredTextures = new List<Texture2D>();

		private int creationChecks;

		private string TextureDirectory => Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Textures");

		private void Awake()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			Instance = this;
			verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "VerboseCoverage", true, "Log each prefab hierarchy, LOD renderer and material slot once. No recurring scene scans.");
			LoadTextures(mossOnly: false);
			if (textures.Count == 0)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"No usable textures loaded; no patches installed and vanilla materials left intact.");
				return;
			}
			harmony = new Harmony("com.primeswamp.trees");
			harmony.PatchAll(typeof(PrimeSwampTreesPlugin).Assembly);
			InstallPrefabHook();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Prime Swamp Trees 0.4.1 restoration-gated build: prefab preparation + creation safeguards; no periodic renderer scan.");
		}

		private void InstallPrefabHook()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null);
			HashSet<string> hashSet = new HashSet<string> { "cjayride.CustomTextures" };
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo != null)
			{
				foreach (Patch postfix in patchInfo.Postfixes)
				{
					if (postfix.PatchMethod.DeclaringType.Assembly.GetName().Name == "CustomTextures")
					{
						hashSet.Add(postfix.owner);
					}
				}
			}
			string[] array = new string[hashSet.Count];
			hashSet.CopyTo(array);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(SceneReady), "Postfix", (Type[])null, (Type[])null))
			{
				priority = 0,
				after = array
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Prefab hook ordered after CustomTextures owners: " + string.Join(", ", array)));
		}

		private void LoadTextures(bool mossOnly)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			if (!Directory.Exists(TextureDirectory))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Missing adjacent Textures folder: " + TextureDirectory));
				return;
			}
			List<Texture2D> list = new List<Texture2D>();
			string[] files = Directory.GetFiles(TextureDirectory, mossOnly ? "*MossTex.png" : "*.png");
			foreach (string text in files)
			{
				Texture2D val = null;
				try
				{
					val = new Texture2D(2, 2, (TextureFormat)4, true);
					if (!ImageConversion.LoadImage(val, File.ReadAllBytes(text)))
					{
						throw new InvalidDataException("Unity rejected PNG data");
					}
					string key = (((Object)val).name = Path.GetFileNameWithoutExtension(text));
					if (textures.TryGetValue(key, out var value))
					{
						list.Add(value);
					}
					textures[key] = val;
				}
				catch (Exception ex)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						Object.Destroy((Object)(object)val);
					}
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot load " + text + ": " + ex.Message));
				}
			}
			foreach (Material item in owned)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					ApplyTextures(item);
				}
			}
			retiredTextures.AddRange(list);
			if (mossOnly)
			{
				ReapplyTrackedRoots();
			}
			files = TextureRules.ExpectedFiles;
			foreach (string text2 in files)
			{
				if (!textures.ContainsKey(Path.GetFileNameWithoutExtension(text2)))
				{
					WarnOnce("missing:" + text2, "Missing/unreadable baseline texture: " + text2);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded " + textures.Count + " tree texture files" + (mossOnly ? " (moss reload)" : "") + "."));
		}

		private void Update()
		{
			if (harmony != null && Input.GetKeyDown((KeyCode)289))
			{
				LoadTextures(mossOnly: true);
			}
		}

		internal static void Guard(string context, Action<PrimeSwampTreesPlugin> action)
		{
			PrimeSwampTreesPlugin instance = Instance;
			if (!Object.op_Implicit((Object)(object)instance) || instance.harmony == null || RestorationGate == null || !RestorationGate())
			{
				return;
			}
			try
			{
				action(instance);
			}
			catch (Exception ex)
			{
				instance.WarnOnce("exception:" + context, context + " failed (gameplay continues): " + ex);
			}
		}

		private void WarnOnce(string key, string message)
		{
			if (messages.Add(key))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)message);
			}
		}

		private void TraceOnce(string key, string message)
		{
			if (verbose.Value && messages.Add(key))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
			}
		}

		private bool HasMapping(Material material)
		{
			string normalizedMaterial = TextureRules.Normalize(((Object)material).name);
			foreach (string key in textures.Keys)
			{
				if (TextureRules.TryParse(key, out var material2, out var _) && TextureRules.Matches(normalizedMaterial, material2))
				{
					return true;
				}
			}
			return false;
		}

		private int ApplyTextures(Material material)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			string text = TextureRules.Normalize(((Object)material).name);
			int num = 0;
			foreach (KeyValuePair<string, Texture2D> texture in textures)
			{
				if (!TextureRules.TryParse(texture.Key, out var material2, out var suffix) || !TextureRules.Matches(text, material2))
				{
					continue;
				}
				bool flag = false;
				if (suffix.Equals("mosstex", StringComparison.OrdinalIgnoreCase))
				{
					string[] mossProperties = TextureRules.MossProperties;
					foreach (string text2 in mossProperties)
					{
						if (material.HasProperty(text2))
						{
							material.SetTexture(text2, (Texture)(object)texture.Value);
							flag = true;
						}
					}
					if (flag)
					{
						if (material.HasProperty("_MossColor"))
						{
							material.SetColor("_MossColor", Color.white);
						}
						if (material.HasProperty("_MossTint"))
						{
							material.SetColor("_MossTint", Color.white);
						}
					}
				}
				else
				{
					string text3 = TextureRules.Property(suffix);
					if (material.HasProperty(text3))
					{
						material.SetTexture(text3, (Texture)(object)texture.Value);
						flag = true;
					}
				}
				if (flag)
				{
					num++;
					matchedFiles.Add(texture.Key);
					TraceOnce("texture:" + text + ":" + texture.Key + ":" + ((Object)material.shader).name, "Applied " + texture.Key + " to " + text + " shader=" + ((Object)material.shader).name);
				}
				else
				{
					WarnOnce("property:" + text + ":" + suffix + ":" + ((Object)material.shader).name, "No supported property for " + texture.Key + " on " + text + " shader=" + ((Object)material.shader).name + "; left unchanged.");
				}
			}
			return num;
		}

		private Material Replacement(Material original)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)original))
			{
				return original;
			}
			if (owned.Contains(original))
			{
				ApplyTextures(original);
				return original;
			}
			if (replacements.TryGetValue(original, out var value) && Object.op_Implicit((Object)(object)value))
			{
				ApplyTextures(value);
				return value;
			}
			if (!HasMapping(original))
			{
				if (TextureRules.IsSwampTree(((Object)original).name))
				{
					WarnOnce("unmapped:" + ((Object)original).name, "Unmapped tree material '" + ((Object)original).name + "'; preserving it (no guessed texture).");
				}
				return original;
			}
			Material val = new Material(original)
			{
				name = ((Object)original).name
			};
			if (ApplyTextures(val) == 0)
			{
				Object.Destroy((Object)(object)val);
				return original;
			}
			replacements[original] = val;
			owned.Add(val);
			TraceOnce("copy:" + ((Object)original).GetInstanceID(), "Material copy: " + ((Object)original).name + " shader=" + ((Object)original.shader).name + " source=" + ((Object)original).GetInstanceID() + " replacement=" + ((Object)val).GetInstanceID());
			return val;
		}

		private void ApplyHierarchy(GameObject root, string context, bool inventory)
		{
			int num = 0;
			int num2 = 0;
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					Material val3 = Replacement(val2);
					num++;
					if (inventory)
					{
						TraceOnce("slot:" + ((Object)val).GetInstanceID() + ":" + j, context + " renderer=" + PathOf(root.transform, ((Component)val).transform) + " slot=" + j + " activeSelf=" + ((Component)val).gameObject.activeSelf + " enabled=" + val.enabled + " material=" + (Object.op_Implicit((Object)(object)val2) ? ((Object)val2).name : "<null>") + " coverage=" + ((Object.op_Implicit((Object)(object)val3) && owned.Contains(val3)) ? "custom" : "unchanged"));
					}
					if ((Object)(object)val3 != (Object)(object)val2)
					{
						sharedMaterials[j] = val3;
						flag = true;
						num2++;
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
			InstanceRenderer[] componentsInChildren2 = root.GetComponentsInChildren<InstanceRenderer>(true);
			foreach (InstanceRenderer val4 in componentsInChildren2)
			{
				Material val5 = Replacement(val4.m_material);
				if ((Object)(object)val5 != (Object)(object)val4.m_material)
				{
					val4.m_material = val5;
					num2++;
				}
				if (inventory)
				{
					TraceOnce("instanced:" + ((Object)val4).GetInstanceID(), context + " InstanceRenderer=" + PathOf(root.transform, ((Component)val4).transform) + " material=" + (Object.op_Implicit((Object)(object)val5) ? ((Object)val5).name : "<null>"));
				}
			}
			if (!inventory)
			{
				return;
			}
			LODGroup[] componentsInChildren3 = root.GetComponentsInChildren<LODGroup>(true);
			foreach (LODGroup val6 in componentsInChildren3)
			{
				LOD[] lODs = val6.GetLODs();
				for (int k = 0; k < lODs.Length; k++)
				{
					componentsInChildren = lODs[k].renderers;
					foreach (Renderer val7 in componentsInChildren)
					{
						if (Object.op_Implicit((Object)(object)val7))
						{
							TraceOnce("lod:" + ((Object)val6).GetInstanceID() + ":" + k + ":" + ((Object)val7).GetInstanceID(), context + " LOD=" + k + " threshold=" + lODs[k].screenRelativeTransitionHeight + " renderer=" + PathOf(root.transform, ((Component)val7).transform));
							if ((Object)(object)((Component)val7).transform != (Object)(object)root.transform && !((Component)val7).transform.IsChildOf(root.transform))
							{
								WarnOnce("external-lod:" + ((Object)val7).GetInstanceID(), "LOD references renderer outside target hierarchy: " + ((Object)val7).name);
							}
						}
					}
				}
			}
			TraceOnce("hierarchy:" + ((Object)root).GetInstanceID(), context + " slots=" + num + " reassigned=" + num2);
		}

		private static string PathOf(Transform root, Transform child)
		{
			string text = ((Object)child).name;
			while ((Object)(object)child != (Object)(object)root && Object.op_Implicit((Object)(object)child.parent))
			{
				child = child.parent;
				text = ((Object)child).name + "/" + text;
			}
			return text;
		}

		private void PrepareGraph(GameObject prefab)
		{
			if (Object.op_Implicit((Object)(object)prefab) && !prepared.Contains(prefab))
			{
				PrepareGraph(prefab, new HashSet<GameObject>());
			}
		}

		private void PrepareGraph(GameObject prefab, HashSet<GameObject> visiting)
		{
			if (Object.op_Implicit((Object)(object)prefab) && !prepared.Contains(prefab) && visiting.Add(prefab))
			{
				ApplyHierarchy(prefab, "prefab=" + ((Object)prefab).name, inventory: true);
				targetHashes.Add(StringExtensionMethods.GetStableHashCode(((Object)prefab).name));
				TreeBase[] componentsInChildren = prefab.GetComponentsInChildren<TreeBase>(true);
				foreach (TreeBase val in componentsInChildren)
				{
					TraceOnce("chain:" + ((Object)prefab).GetInstanceID(), "Chain " + ((Object)prefab).name + " -> log=" + (Object.op_Implicit((Object)(object)val.m_logPrefab) ? ((Object)val.m_logPrefab).name : "<none>") + " stump=" + (Object.op_Implicit((Object)(object)val.m_stubPrefab) ? ((Object)val.m_stubPrefab).name : "<none>"));
					PrepareGraph(val.m_logPrefab, visiting);
					PrepareGraph(val.m_stubPrefab, visiting);
				}
				TreeLog[] componentsInChildren2 = prefab.GetComponentsInChildren<TreeLog>(true);
				foreach (TreeLog val2 in componentsInChildren2)
				{
					TraceOnce("sublog:" + ((Object)prefab).GetInstanceID(), "Chain " + ((Object)prefab).name + " -> split=" + (Object.op_Implicit((Object)(object)val2.m_subLogPrefab) ? ((Object)val2.m_subLogPrefab).name : "<none>"));
					PrepareGraph(val2.m_subLogPrefab, visiting);
				}
				prepared.Add(prefab);
			}
		}

		private void PrepareScene(ZNetScene scene)
		{
			foreach (GameObject prefab in scene.m_prefabs)
			{
				if (Object.op_Implicit((Object)(object)prefab) && TextureRules.IsSwampTree(((Object)prefab).name))
				{
					PrepareGraph(prefab);
				}
			}
			foreach (GameObject nonNetViewPrefab in scene.m_nonNetViewPrefabs)
			{
				if (Object.op_Implicit((Object)(object)nonNetViewPrefab) && TextureRules.IsSwampTree(((Object)nonNetViewPrefab).name))
				{
					PrepareGraph(nonNetViewPrefab);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Prefab coverage: roots/references=" + prepared.Count + " cached materials=" + owned.Count + "; creation safeguards enabled."));
			foreach (string key in textures.Keys)
			{
				if (!matchedFiles.Contains(key))
				{
					WarnOnce("unused:" + key, "Texture not yet applied to a supported prefab material: " + key + " (check missing shader properties/late assets).");
				}
			}
		}

		private void PrepareVegetation(ZoneSystem zone)
		{
			foreach (ZoneVegetation item in zone.m_vegetation)
			{
				if (Object.op_Implicit((Object)(object)item.m_prefab) && TextureRules.IsSwampTree(((Object)item.m_prefab).name))
				{
					PrepareGraph(item.m_prefab);
				}
			}
		}

		private void OnCreated(GameObject root, string reason)
		{
			if (Object.op_Implicit((Object)(object)root))
			{
				ApplyHierarchy(root, reason + "=" + ((Object)root).name, inventory: false);
				liveRoots[((Object)root).GetInstanceID()] = new WeakReference<GameObject>(root);
				creationChecks++;
				if ((creationChecks & 0xFF) == 0)
				{
					PruneTrackedRoots();
				}
				TraceOnce("creation:" + reason + ":" + ((Object)root).name, "Creation safeguard " + reason + " for " + ((Object)root).name + "; checked before first rendering; cached materials=" + owned.Count);
			}
		}

		private void PruneTrackedRoots()
		{
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, WeakReference<GameObject>> liveRoot in liveRoots)
			{
				if (!liveRoot.Value.TryGetTarget(out var target) || !Object.op_Implicit((Object)(object)target))
				{
					list.Add(liveRoot.Key);
				}
			}
			foreach (int item in list)
			{
				liveRoots.Remove(item);
			}
		}

		private void ReapplyTrackedRoots()
		{
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, WeakReference<GameObject>> liveRoot in liveRoots)
			{
				if (!liveRoot.Value.TryGetTarget(out var target) || !Object.op_Implicit((Object)(object)target))
				{
					list.Add(liveRoot.Key);
				}
				else
				{
					ApplyHierarchy(target, "manual-moss-reload=" + ((Object)target).name, inventory: false);
				}
			}
			foreach (int item in list)
			{
				liveRoots.Remove(item);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Moss reapplied to tracked tree roots=" + liveRoots.Count + "; no scene enumeration."));
		}

		private bool IsTarget(GameObject root)
		{
			if (!Object.op_Implicit((Object)(object)root))
			{
				return false;
			}
			if (!TextureRules.IsSwampTree(((Object)root).name))
			{
				return targetHashes.Contains(StringExtensionMethods.GetStableHashCode(((Object)root).name.Replace("(Clone)", "").Trim()));
			}
			return true;
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Prime Swamp Trees stopped; creation checks=" + creationChecks + ". Restart the game to unload visual resources safely."));
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	internal static class TextureRules
	{
		internal static readonly string[] MossProperties = new string[3] { "_MossTex", "_MossTexture", "_MossMap" };

		internal static readonly string[] ExpectedFiles = new string[10] { "mat_swamptree_log_MainTex.png", "mat_swamptree_log_MossTex.png", "mat_swamptree1_bark_MainTex.png", "mat_swamptree1_bark_MossTex.png", "mat_swamptree1_branch_MainTex.png", "mat_swamptree2_bark_MainTex.png", "mat_swamptree2_bark_MossTex.png", "mat_swamptree2_branch_MainTex.png", "mat_swamptree2_log_MainTex.png", "mat_swamptree2_log_MossTex.png" };

		internal static string Normalize(string name)
		{
			return (name ?? "").Replace(" (Instance)", "").Replace(" (Clone)", "").Trim()
				.ToLowerInvariant();
		}

		internal static bool IsSwampTree(string name)
		{
			return (name ?? "").IndexOf("swamptree", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		internal static bool Matches(string normalizedMaterial, string key)
		{
			if (!normalizedMaterial.Equals(key, StringComparison.OrdinalIgnoreCase))
			{
				return normalizedMaterial.StartsWith(key + " ", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		internal static bool TryParse(string filename, out string material, out string suffix)
		{
			string text = Path.GetFileNameWithoutExtension(filename).ToLowerInvariant();
			int num = text.LastIndexOf('_');
			material = (suffix = "");
			if (num <= 4)
			{
				return false;
			}
			material = text.Substring(4, num - 4);
			suffix = text.Substring(num + 1);
			return true;
		}

		internal static string Property(string suffix)
		{
			if (!suffix.Equals("maintex", StringComparison.OrdinalIgnoreCase))
			{
				return "_" + suffix.ToLowerInvariant();
			}
			return "_MainTex";
		}
	}
}

BepInEx/plugins/PrimeWildLife/PrimeWildlife.dll

Decompiled 4 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PrimeWildlife")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PrimeWildlife")]
[assembly: AssemblyTitle("PrimeWildlife")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PrimeWildlife
{
	[BepInPlugin("com.prime.wildlife", "Prime Wildlife", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PrimeWildlifePlugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			_harmony = new Harmony("com.prime.wildlife");
			_harmony.PatchAll(typeof(PrimeWildlifePlugin).Assembly);
			PrefabManager.OnVanillaPrefabsAvailable += RegisterWildlife;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Prime Wildlife 0.2 loaded.");
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= RegisterWildlife;
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void RegisterWildlife()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= RegisterWildlife;
			RegisterClone("Boar", "PrimeBoar");
			RegisterClone("Neck", "PrimeNeck");
		}

		private void RegisterClone(string original, string custom)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = PrefabManager.Instance.CreateClonedPrefab(custom, original);
				if ((Object)(object)val == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)(custom + ": source prefab not found: " + original));
					return;
				}
				Character component = val.GetComponent<Character>();
				if ((Object)(object)component == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)(custom + ": Character component missing."));
					return;
				}
				component.m_faction = (Faction)3;
				PrefabManager.Instance.AddPrefab(val);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("REGISTERED " + custom + " (Undead faction; vanilla AI retained)."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)(custom + " registration failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
	{
		typeof(Character),
		typeof(Character)
	})]
	internal static class MatchingWildlifeNeutrality
	{
		private static bool Prefix(Character a, Character b, ref bool __result)
		{
			if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
			{
				return true;
			}
			string a2 = CleanName(((Object)((Component)a).gameObject).name);
			string b2 = CleanName(((Object)((Component)b).gameObject).name);
			if (IsPair(a2, b2, "Boar", "PrimeBoar") || IsPair(a2, b2, "Neck", "PrimeNeck"))
			{
				__result = false;
				return false;
			}
			return true;
		}

		private static bool IsPair(string a, string b, string vanilla, string prime)
		{
			return (a == vanilla && b == prime) || (a == prime && b == vanilla);
		}

		private static string CleanName(string name)
		{
			return name.Replace("(Clone)", "").Trim();
		}
	}
}