Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TerrainMistile v1.0.1
TerrainMistile.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Managers; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TerrainMistile")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("TerrainMistile")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] [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 TerrainMistile { [BepInPlugin("sighsorry.TerrainMistile", "TerrainMistile", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class TerrainMistilePlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } internal const string ModName = "TerrainMistile"; internal const string ModVersion = "1.0.1"; internal const string Author = "sighsorry"; internal const string DefaultDisplayName = "Earth Warden"; private const string ModGUID = "sighsorry.TerrainMistile"; private static string ConfigFileName = "sighsorry.TerrainMistile.cfg"; private static string ConfigFileFullPath; private static string SpawnRulesFileName; internal static string SpawnRulesFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("sighsorry.TerrainMistile"); public static readonly ManualLogSource TerrainMistileLogger; private static readonly ConfigSync ConfigSync; private FileSystemWatcher _watcher; private FileSystemWatcher _spawnRulesWatcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private DateTime _lastSpawnRulesReloadTime; private const long RELOAD_DELAY = 10000000L; private static ConfigEntry<Toggle> _serverConfigLocked; private static ConfigEntry<string> _displayName; internal static CustomSyncedValue<string> SpawnRulesYaml; internal static string DisplayName { get { string text = (_displayName?.Value ?? "").Trim(); if (text.Length != 0) { return text; } return "Earth Warden"; } } public void Awake() { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); _displayName = config("2 - Display", "Display Name", "Earth Warden", "In-game name shown to players for TerrainMistile."); TerrainMistileSpawnRules.Initialize(TerrainMistileLogger); TerrainMistileSpawnRules.EnsureFileExists(SpawnRulesFileFullPath); SpawnRulesYaml = new CustomSyncedValue<string>(ConfigSync, "SpawnRulesYaml", string.Empty); SpawnRulesYaml.ValueChanged += OnSyncedSpawnRulesYamlChanged; ConfigSync.SourceOfTruthChanged += OnSourceOfTruthChanged; TerrainMistileSpawnRules.LoadYamlText(File.ReadAllText(SpawnRulesFileFullPath), "local fallback"); TerrainMistilePrefab.RegisterPrefabHook(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); TerrainMistileExternalTerrainCompat.Initialize(TerrainMistileLogger, _harmony); SetupWatcher(); if (ConfigSync.IsSourceOfTruth) { PushLocalSpawnRulesYamlToSync(); } ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { TerrainMistilePrefab.UnregisterPrefabHook(); SpawnRulesYaml.ValueChanged -= OnSyncedSpawnRulesYamlChanged; ConfigSync.SourceOfTruthChanged -= OnSourceOfTruthChanged; SaveWithRespectToConfigSet(); _watcher?.Dispose(); _spawnRulesWatcher?.Dispose(); } private void Update() { TerrainMistileSystem.UpdateResetEffectRpcRegistration(); TerrainMistileExternalTerrainCompat.Update(); TerrainMistileSystem.UpdatePersistentTerrainSpawns(); } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); _watcher.Changed += ReadConfigValues; _watcher.Created += ReadConfigValues; _watcher.Renamed += ReadConfigValues; _watcher.IncludeSubdirectories = true; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; _spawnRulesWatcher = new FileSystemWatcher(Paths.ConfigPath, SpawnRulesFileName); _spawnRulesWatcher.Changed += ReadSpawnRulesValues; _spawnRulesWatcher.Created += ReadSpawnRulesValues; _spawnRulesWatcher.Renamed += ReadSpawnRulesValues; _spawnRulesWatcher.IncludeSubdirectories = false; _spawnRulesWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _spawnRulesWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { DateTime now = DateTime.Now; if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { TerrainMistileLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { TerrainMistileLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); TerrainMistileLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { TerrainMistileLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } _lastConfigReloadTime = now; } private void ReadSpawnRulesValues(object sender, FileSystemEventArgs e) { DateTime now = DateTime.Now; if (now.Ticks - _lastSpawnRulesReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(SpawnRulesFileFullPath)) { TerrainMistileLogger.LogWarning((object)"TerrainMistile spawn rules YAML does not exist. Skipping reload."); return; } if (!ConfigSync.IsSourceOfTruth) { TerrainMistileLogger.LogDebug((object)"Ignoring local TerrainMistile spawn rules YAML change while server data is authoritative."); return; } try { PushLocalSpawnRulesYamlToSync(); TerrainMistileLogger.LogInfo((object)"TerrainMistile spawn rules YAML reload complete."); } catch (Exception ex) { TerrainMistileLogger.LogError((object)("Error reloading TerrainMistile spawn rules YAML: " + ex.Message)); } } _lastSpawnRulesReloadTime = now; } private void PushLocalSpawnRulesYamlToSync() { TerrainMistileSpawnRules.EnsureFileExists(SpawnRulesFileFullPath); string text = File.ReadAllText(SpawnRulesFileFullPath); if (TerrainMistileSpawnRules.LoadYamlText(text, "local file")) { SpawnRulesYaml.Value = text; } } private void OnSyncedSpawnRulesYamlChanged() { TerrainMistileSpawnRules.LoadYamlText(SpawnRulesYaml.Value ?? string.Empty, ConfigSync.IsSourceOfTruth ? "local sync" : "server sync"); } private void OnSourceOfTruthChanged(bool isSourceOfTruth) { if (isSourceOfTruth) { PushLocalSpawnRulesYamlToSync(); } else { TerrainMistileSpawnRules.LoadYamlText(SpawnRulesYaml.Value ?? string.Empty, "server sync"); } } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static TerrainMistilePlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; SpawnRulesFileName = "TerrainMistile.yml"; string configPath2 = Paths.ConfigPath; directorySeparatorChar = Path.DirectorySeparatorChar; SpawnRulesFileFullPath = configPath2 + directorySeparatorChar + SpawnRulesFileName; ConnectionError = ""; TerrainMistileLogger = Logger.CreateLogSource("TerrainMistile"); ConfigSync = new ConfigSync("sighsorry.TerrainMistile") { DisplayName = "TerrainMistile", CurrentVersion = "1.0.1", MinimumRequiredVersion = "1.0.1" }; _serverConfigLocked = null; _displayName = null; SpawnRulesYaml = null; } } public class TerrainMistileBehaviour : MonoBehaviour { internal const string SelfDestructZdoKey = "TerrainMistileSelfDestruct"; internal const string TerrainMistileZdoKey = "TerrainMistile"; internal const string TerrainSourceZdoKey = "TerrainMistileSource"; internal const string TerrainSourceSetZdoKey = "TerrainMistileSourceSet"; internal const string ResetRadiusZdoKey = "TerrainMistileResetRadius"; internal const string HealthZdoKey = "TerrainMistileHealth"; internal const string VisualColorZdoKey = "TerrainMistileVisualColor"; internal const string VisualColorSetZdoKey = "TerrainMistileVisualColorSet"; private const float TerrainImpactDistance = 1.25f; private const float TerrainImpactHeight = 0.85f; private const float TerrainTargetGroundOffset = 0.15f; private const float VisualSyncRetryInterval = 0.25f; private Character _character; private MonsterAI _monsterAI; private ZNetView _nview; private Vector3 _terrainTarget; private float _resetRadius = 8f; private bool _hasTerrainTarget; private bool _selfDestructTriggered; private bool _terrainResetDone; private bool _visualColorApplied; private float _nextVisualSyncTime; private void Awake() { _character = ((Component)this).GetComponent<Character>(); _monsterAI = ((Component)this).GetComponent<MonsterAI>(); _nview = ((Component)this).GetComponent<ZNetView>(); TryApplySyncedVisualColor(); ApplyIdentity(); ConfigureTerrainSeeker(); TerrainMistilePrefab.MakeCollidersNonBlocking(((Component)this).gameObject); TerrainMistileSystem.RegisterActiveTerrainMistile(this); if (Object.op_Implicit((Object)(object)_character)) { Character character = _character; character.m_onDeath = (Action)Delegate.Combine(character.m_onDeath, new Action(OnDeath)); } } private void OnDestroy() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_character)) { Character character = _character; character.m_onDeath = (Action)Delegate.Remove(character.m_onDeath, new Action(OnDeath)); } if (_hasTerrainTarget) { TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); } TerrainMistileSystem.UnregisterActiveTerrainMistile(this); } private void FixedUpdate() { TryApplySyncedVisualColor(); if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner() && Object.op_Implicit((Object)(object)_character) && !_character.IsDead() && !_terrainResetDone) { ApplyIdentity(); ConfigureTerrainSeeker(); if (TryLoadTerrainTarget()) { MoveTowardTerrainTarget(); } } } internal void Initialize(Player target, Vector3 terrainOperationPoint, float resetRadius, float health) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) ApplyIdentity(); ConfigureTerrainSeeker(); ApplyHealth(health); SetTerrainTarget(terrainOperationPoint, resetRadius); if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("TerrainMistile", true); } } internal void MarkSelfDestruct(string reason = "self-destruct") { _selfDestructTriggered = true; if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("TerrainMistileSelfDestruct", true); } TerrainMistilePlugin.TerrainMistileLogger.LogDebug((object)("Marked TerrainMistile self-destruct from " + reason + ".")); } private void ApplyIdentity() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_character)) { _character.m_name = TerrainMistilePlugin.DisplayName; _character.m_faction = (Faction)10; _character.m_aiSkipTarget = true; _character.m_flying = true; } } private void ApplyHealth(float health) { if (Object.op_Implicit((Object)(object)_character) && Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { health = Mathf.Max(1f, health); _character.SetMaxHealth(health); _character.SetHealth(health); ZDO zDO = _nview.GetZDO(); if (zDO != null) { zDO.Set("TerrainMistileHealth", health); } } } private void ApplyVisualColor(Color color, bool syncToZdo) { //IL_0006: 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_005a: 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_0066: Unknown result type (might be due to invalid IL or missing references) TerrainMistilePrefab.ApplyVisuals(((Component)this).gameObject, color); _visualColorApplied = true; if (syncToZdo && Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { zDO.Set("TerrainMistileVisualColor", new Vector3(color.r, color.g, color.b)); zDO.Set("TerrainMistileVisualColorSet", true); } } } private void ApplyVisualColorForTarget(Vector3 target) { //IL_0000: 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) ApplyVisualColor(TerrainMistileSpawnRules.GetRule(TerrainMistileSpawnRules.GetBiomeKey(target)).VisualColor, syncToZdo: true); } private void TryApplySyncedVisualColor() { //IL_0066: 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_0070: 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_0078: 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_0089: Unknown result type (might be due to invalid IL or missing references) if (_visualColorApplied || Time.time < _nextVisualSyncTime) { return; } _nextVisualSyncTime = Time.time + 0.25f; if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid()) { ZDO zDO = _nview.GetZDO(); if (zDO != null && zDO.GetBool("TerrainMistileVisualColorSet", false)) { Vector3 vec = zDO.GetVec3("TerrainMistileVisualColor", Vector3.zero); ApplyVisualColor(new Color(vec.x, vec.y, vec.z, 1f), syncToZdo: false); } } } private void ConfigureTerrainSeeker() { if (Object.op_Implicit((Object)(object)_monsterAI)) { _monsterAI.m_enableHuntPlayer = false; _monsterAI.m_attackPlayerObjects = false; ((BaseAI)_monsterAI).m_aggravatable = false; _monsterAI.m_targetCreature = null; _monsterAI.m_targetStatic = null; if (Object.op_Implicit((Object)(object)((BaseAI)_monsterAI).m_nview) && ((BaseAI)_monsterAI).m_nview.IsValid()) { ((BaseAI)_monsterAI).SetHuntPlayer(false); ((BaseAI)_monsterAI).SetAlerted(false); } else { ((BaseAI)_monsterAI).m_huntPlayer = false; ((BaseAI)_monsterAI).m_alerted = false; } ((Behaviour)_monsterAI).enabled = false; } } private void SetTerrainTarget(Vector3 terrainOperationPoint, float resetRadius) { //IL_0014: 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_0033: 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_0009: 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) if (_hasTerrainTarget) { TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); } _terrainTarget = terrainOperationPoint; _resetRadius = Mathf.Max(0.1f, resetRadius); _hasTerrainTarget = true; TerrainMistileSystem.ReserveTerrainTarget(_terrainTarget, _resetRadius); ApplyVisualColorForTarget(_terrainTarget); if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("TerrainMistileSource", terrainOperationPoint); _nview.GetZDO().Set("TerrainMistileSourceSet", true); _nview.GetZDO().Set("TerrainMistileResetRadius", _resetRadius); } } private bool TryLoadTerrainTarget() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) if (!TryGetTerrainTarget(out var terrainTarget, out var resetRadius)) { return false; } if (!_hasTerrainTarget) { _terrainTarget = terrainTarget; _resetRadius = resetRadius; _hasTerrainTarget = true; TerrainMistileSystem.ReserveTerrainTarget(_terrainTarget, _resetRadius); } return true; } internal bool TryGetTerrainTarget(out Vector3 terrainTarget) { float resetRadius; return TryGetTerrainTarget(out terrainTarget, out resetRadius); } internal bool TryGetTerrainTarget(out Vector3 terrainTarget, out float resetRadius) { //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_0039: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (_hasTerrainTarget) { terrainTarget = _terrainTarget; resetRadius = _resetRadius; return true; } if (!Object.op_Implicit((Object)(object)_nview) || !_nview.IsValid()) { terrainTarget = default(Vector3); resetRadius = _resetRadius; return false; } ZDO zDO = _nview.GetZDO(); if (zDO == null || !zDO.GetBool("TerrainMistileSourceSet", false)) { terrainTarget = default(Vector3); resetRadius = _resetRadius; return false; } terrainTarget = zDO.GetVec3("TerrainMistileSource", ((Component)this).transform.position); resetRadius = zDO.GetFloat("TerrainMistileResetRadius", 0f); return true; } private void MoveTowardTerrainTarget() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_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_0013: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_003f: 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_0068: 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_00ad: 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_00c6: 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_00db: 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) Vector3 position = ((Component)this).transform.position; Vector3 terrainTarget = _terrainTarget; if (TerrainMistileSystem.TryGetGroundHeight(terrainTarget, out var height)) { terrainTarget.y = height + 0.15f; } Vector3 val = terrainTarget - position; Vector2 val2 = new Vector2(val.x, val.z); bool num = ((Vector2)(ref val2)).magnitude <= 1.25f || ((Vector3)(ref val)).sqrMagnitude <= 1.5625f; float height2; bool flag = TerrainMistileSystem.TryGetGroundHeight(position, out height2) && position.y <= height2 + 0.85f; if (num && flag) { DetonateOnTerrain(); return; } if (((Vector3)(ref val)).sqrMagnitude <= 0.01f) { DetonateOnTerrain(); return; } Vector3 normalized = ((Vector3)(ref val)).normalized; _character.SetRun(true); _character.SetMoveDir(normalized); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(normalized.x, 0f, normalized.z); if (((Vector3)(ref val3)).sqrMagnitude > 0.001f) { _character.SetLookDir(((Vector3)(ref val3)).normalized, 0f); } } private void DetonateOnTerrain() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //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_006c: Unknown result type (might be due to invalid IL or missing references) if (!_terrainResetDone && Object.op_Implicit((Object)(object)_character) && !_character.IsDead() && !TryRetargetOrDespawnFromEmptyImpact()) { MarkSelfDestruct("terrain impact"); TryResetTerrain("terrain impact"); HitData val = new HitData(); val.m_point = ((Component)this).transform.position; val.m_damage.m_damage = 9999999f; val.m_hitType = (HitType)14; _character.ApplyDamage(val, false, true, (DamageModifier)0); if (!_character.IsDead() && Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)this).gameObject); } } } private bool TryRetargetOrDespawnFromEmptyImpact() { //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_0037: 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_0050: 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_006b: 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) TryLoadTerrainTarget(); if (!_hasTerrainTarget) { return false; } if (TerrainMistileSystem.HasModifiedTerrainAround(_terrainTarget, _resetRadius)) { return false; } TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); if (TerrainMistileSystem.TryFindReplacementTerrainTarget(((Component)this).transform.position, out var modifiedPoint)) { TerrainMistilePlugin.TerrainMistileLogger.LogDebug((object)$"TerrainMistile target at {_terrainTarget} was already reset; retargeting to {modifiedPoint}."); SetTerrainTarget(modifiedPoint, TerrainMistileSystem.GetResetRadiusForPoint(modifiedPoint)); return true; } TerrainMistilePlugin.TerrainMistileLogger.LogDebug((object)$"TerrainMistile target at {_terrainTarget} was already reset and no replacement target was found; destroying without terrain reset."); DestroyWithoutTerrainReset(); return true; } private void DestroyWithoutTerrainReset() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) _terrainResetDone = true; if (_hasTerrainTarget) { TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); } if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void OnDeath() { TryResetTerrain("death"); } internal void TryResetTerrain(string reason) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00bf: 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_00aa: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid()) { if (!_nview.IsOwner()) { return; } _selfDestructTriggered |= _nview.GetZDO().GetBool("TerrainMistileSelfDestruct", false); } if (_terrainResetDone) { return; } if (!_selfDestructTriggered) { TerrainMistilePlugin.TerrainMistileLogger.LogDebug((object)("Skipping TerrainMistile terrain reset on " + reason + "; self-destruct was not detected.")); return; } _terrainResetDone = true; TryLoadTerrainTarget(); Vector3 val = (_hasTerrainTarget ? _terrainTarget : ((Component)this).transform.position); if (_hasTerrainTarget) { TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); } TerrainMistilePlugin.TerrainMistileLogger.LogInfo((object)$"TerrainMistile terrain reset triggered by {reason} at {val}."); TerrainMistileSystem.ResetTerrainAround(val, _resetRadius, resetPaint: true); } } public static class TerrainMistileCompat { public static void RegisterIgnoredTerrainArea(Vector3 center, float radius, string source) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) TerrainMistileSystem.RegisterExternalTerrainIgnoreArea(center, radius, source); } } internal static class TerrainMistileExternalTerrainCompat { private const string ExpandWorldDataLocationTypeName = "ExpandWorldData.LocationObjectDataAndSwap"; private const string ExpandWorldDataLocationDataTypeName = "ExpandWorldData.LocationData"; private const string ExpandWorldDataLocationLoadingTypeName = "ExpandWorldData.LocationLoading"; private const string ExpandWorldDataNoBuildManagerTypeName = "ExpandWorldData.NoBuildManager"; private const string BlueprintProtectedSourcePrefix = "Expand World Data blueprint terrain"; private const float PatchRetryInterval = 2f; private static ManualLogSource? _logger; private static Harmony? _harmony; private static bool _terrainPatched; private static bool _protectionSyncPatched; private static float _nextPatchAttemptTime; public static void Initialize(ManualLogSource logger, Harmony harmony) { _logger = logger; _harmony = harmony; TryPatch(); } public static void Update() { if ((!_terrainPatched || !_protectionSyncPatched) && !(Time.time < _nextPatchAttemptTime)) { _nextPatchAttemptTime = Time.time + 2f; TryPatch(); } } private static void TryPatch() { if (_harmony != null) { TryPatchTerrainHandler(); TryPatchBlueprintProtectionSync(); } } private static void TryPatchTerrainHandler() { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown if (_terrainPatched || _harmony == null) { return; } Type type = FindLoadedType("ExpandWorldData.LocationObjectDataAndSwap"); Type type2 = FindLoadedType("ExpandWorldData.LocationData"); if (type == null || type2 == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "HandleTerrain", new Type[4] { typeof(Vector3), typeof(float), typeof(bool), type2 }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(TerrainMistileExternalTerrainCompat), "HandleTerrainPrefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogDebug((object)"Expand World Data terrain compat skipped: HandleTerrain was not found."); } return; } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _terrainPatched = true; ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)"Expand World Data terrain compat initialized."); } } private static void TryPatchBlueprintProtectionSync() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown if (_protectionSyncPatched || _harmony == null) { return; } Type type = FindLoadedType("ExpandWorldData.NoBuildManager"); if (type == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "UpdateData", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(TerrainMistileExternalTerrainCompat), "BlueprintProtectionSyncPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogDebug((object)"Expand World Data noBuild compat skipped: NoBuildManager.UpdateData was not found."); } return; } _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _protectionSyncPatched = true; ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)"Expand World Data blueprint terrain protection initialized."); } } private static Type? FindLoadedType(string fullName) { foreach (PluginInfo value in Chainloader.PluginInfos.Values) { Type type = ((object)value.Instance)?.GetType().Assembly.GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } private static void HandleTerrainPrefix(Vector3 pos, float radius, bool isBlueprint, object data) { //IL_002e: 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_00fb: Unknown result type (might be due to invalid IL or missing references) string text = GetString(data, "prefab"); string text2 = GetString(data, "noBuild").Trim(); float terrainRadius = GetTerrainRadius(radius, isBlueprint, data); if (terrainRadius > 0f) { TerrainMistileSystem.RegisterExternalTerrainIgnoreArea(pos, terrainRadius, "Expand World Data location terrain", 10f); } float noBuildRadius = GetNoBuildRadius(data, Mathf.Max(GetFloat(data, "exteriorRadius"), radius)); float num = Mathf.Max(new float[4] { terrainRadius, radius, GetFloat(data, "exteriorRadius"), noBuildRadius }) + 5f; ManualLogSource? logger = _logger; if (logger != null) { logger.LogDebug((object)($"EWD terrain compat HandleTerrain prefab='{text}', isBlueprint={isBlueprint}, pos={TerrainMistileSystem.FormatPoint(pos)}, inputRadius={radius:0.##}, " + $"terrainRadius={terrainRadius:0.##}, noBuild='{text2}', noBuildRadius={noBuildRadius:0.##}, protectedRadius={num:0.##}.")); } if (isBlueprint) { TerrainMistileSystem.RegisterProtectedTerrainArea(pos, num, "Expand World Data blueprint terrain " + text); } } private static void BlueprintProtectionSyncPostfix() { SyncBlueprintProtectedAreas(); } private static void SyncBlueprintProtectedAreas() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0087: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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) IDictionary locationDataLookup = GetLocationDataLookup(); IDictionary blueprintLookup = GetBlueprintLookup(); ZoneSystem instance = ZoneSystem.instance; if (blueprintLookup == null || !Object.op_Implicit((Object)(object)instance)) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogDebug((object)$"EWD blueprint protected terrain sync skipped. HasBlueprints={blueprintLookup != null}, HasZoneSystem={(Object)(object)instance != (Object)null}."); } return; } TerrainMistileSystem.ClearProtectedTerrainAreas("Expand World Data blueprint terrain"); int num = 0; int num2 = 0; foreach (LocationInstance value in instance.m_locationInstances.Values) { if (value.m_location != null) { string prefabName = value.m_location.m_prefabName; if (!string.IsNullOrWhiteSpace(prefabName) && blueprintLookup.Contains(prefabName)) { num++; object obj = ((locationDataLookup != null && locationDataLookup.Contains(prefabName)) ? locationDataLookup[prefabName] : null); float num3 = ((obj == null) ? 0f : GetTerrainRadius(value.m_location.m_exteriorRadius, isBlueprint: true, obj)); float num4 = ((obj == null) ? 0f : GetNoBuildRadius(obj, value.m_location.m_exteriorRadius)); float radius = Mathf.Max(new float[3] { num3, value.m_location.m_exteriorRadius, num4 }) + 5f; TerrainMistileSystem.RegisterProtectedTerrainArea(value.m_position, radius, "Expand World Data blueprint terrain " + prefabName); num2++; } } } ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogDebug((object)$"EWD blueprint protected terrain sync complete. BlueprintData={blueprintLookup.Count}, LocationData={locationDataLookup?.Count ?? 0}, matchedLocations={num}, protectedRegistered={num2}."); } } private static IDictionary? GetLocationDataLookup() { Type type = FindLoadedType("ExpandWorldData.LocationLoading"); if (type == null) { return null; } return AccessTools.Field(type, "LocationData")?.GetValue(null) as IDictionary; } private static IDictionary? GetBlueprintLookup() { Type type = FindLoadedType("ExpandWorldData.LocationLoading"); if (type == null) { return null; } return AccessTools.Field(type, "Objects")?.GetValue(null) as IDictionary; } private static float GetTerrainRadius(float exteriorRadius, bool isBlueprint, object data) { string text = GetString(data, "levelArea"); string text2 = GetString(data, "paint"); bool num = ((text.Length == 0) ? isBlueprint : (!text.Equals("false", StringComparison.OrdinalIgnoreCase))); float num2 = 0f; if (num) { float num3 = GetFloat(data, "levelRadius"); float num4 = GetFloat(data, "levelBorder"); num2 = Mathf.Max(num2, (num3 == 0f && num4 == 0f) ? exteriorRadius : (num3 + num4)); } if (text2.Length > 0) { float num5 = GetNullableFloat(data, "paintRadius") ?? exteriorRadius; float num6 = GetNullableFloat(data, "paintBorder") ?? 5f; num2 = Mathf.Max(num2, num5 + num6); } return num2; } private static float GetNoBuildRadius(object data, float exteriorRadius) { string text = GetString(data, "noBuild").Trim(); if (text.Length == 0 || text.Equals("false", StringComparison.OrdinalIgnoreCase)) { return 0f; } if (text.Equals("true", StringComparison.OrdinalIgnoreCase)) { return exteriorRadius; } if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return 0f; } return Mathf.Max(0f, result); } private static string GetString(object data, string fieldName) { return (GetField(data, fieldName)?.GetValue(data) as string) ?? ""; } private static float GetFloat(object data, string fieldName) { object obj = GetField(data, fieldName)?.GetValue(data); if (obj is float) { return (float)obj; } return 0f; } private static float? GetNullableFloat(object data, string fieldName) { object obj = GetField(data, fieldName)?.GetValue(data); if (!(obj is float)) { return null; } return (float)obj; } private static FieldInfo? GetField(object data, string fieldName) { return data.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } [HarmonyPatch(typeof(ZoneSystem), "SpawnLocation", new Type[] { typeof(ZoneLocation), typeof(int), typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List<GameObject>) })] internal static class ZoneSystemSpawnLocationPatch { private static void Prefix(ZoneLocation location, Vector3 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) TerrainMistileSystem.RegisterLocationTerrainLoadGrace(location, pos); } } [HarmonyPatch(typeof(Attack), "Stop")] internal static class AttackStopPatch { private static void Prefix(Attack __instance) { if (__instance != null && __instance.m_attackKillsSelf && !__instance.m_attackDone && Object.op_Implicit((Object)(object)__instance.m_character)) { TerrainMistileBehaviour component = ((Component)__instance.m_character).GetComponent<TerrainMistileBehaviour>(); if (Object.op_Implicit((Object)(object)component)) { component.MarkSelfDestruct(); } } } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class CharacterApplyDamagePatch { private static void Prefix(Character __instance, HitData hit) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)__instance) && hit != null && (int)hit.m_hitType == 14) { TerrainMistileBehaviour component = ((Component)__instance).GetComponent<TerrainMistileBehaviour>(); if (Object.op_Implicit((Object)(object)component)) { component.MarkSelfDestruct(); } } } } [HarmonyPatch(typeof(Humanoid), "OnAttackTrigger")] internal static class HumanoidOnAttackTriggerPatch { private const string MistileKamikazePrefabName = "Mistile_kamikaze"; private static void Prefix(Humanoid __instance) { if (!Object.op_Implicit((Object)(object)__instance) || !((Character)__instance).m_nview.IsValid() || !((Character)__instance).m_nview.IsOwner()) { return; } TerrainMistileBehaviour component = ((Component)__instance).GetComponent<TerrainMistileBehaviour>(); if (Object.op_Implicit((Object)(object)component)) { ItemData currentWeapon = __instance.GetCurrentWeapon(); if (currentWeapon != null && IsMistileKamikaze(currentWeapon)) { component.MarkSelfDestruct("Mistile_kamikaze"); } } } private static bool IsMistileKamikaze(ItemData weapon) { if (Object.op_Implicit((Object)(object)weapon.m_dropPrefab) && string.Equals(((Object)weapon.m_dropPrefab).name, "Mistile_kamikaze", StringComparison.OrdinalIgnoreCase)) { return true; } return string.Equals(weapon.m_shared.m_name, "Mistile_kamikaze", StringComparison.OrdinalIgnoreCase); } } [HarmonyPatch(typeof(ZNetScene), "Destroy", new Type[] { typeof(GameObject) })] internal static class ZNetSceneDestroyPatch { private static void Prefix(object[] __args) { if (__args.Length == 0) { return; } object obj = __args[0]; GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null && Object.op_Implicit((Object)(object)val)) { TerrainMistileBehaviour component = val.GetComponent<TerrainMistileBehaviour>(); if (Object.op_Implicit((Object)(object)component)) { component.TryResetTerrain("destroy"); } } } } internal static class TerrainMistilePrefab { internal const string PrefabName = "TerrainMistile"; private const string SourcePrefabName = "Mistile"; private static bool _hooked; private static bool _registered; private static GameObject? _registeredPrefab; internal static void RegisterPrefabHook() { if (!_hooked) { PrefabManager.OnVanillaPrefabsAvailable += CreateTerrainMistilePrefab; _hooked = true; } } internal static void UnregisterPrefabHook() { if (_hooked) { PrefabManager.OnVanillaPrefabsAvailable -= CreateTerrainMistilePrefab; _hooked = false; } } private static void CreateTerrainMistilePrefab() { //IL_0052: 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) if (_registered) { return; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("TerrainMistile", "Mistile"); if (!Object.op_Implicit((Object)(object)val)) { TerrainMistilePlugin.TerrainMistileLogger.LogError((object)"Could not clone vanilla prefab 'Mistile'."); return; } Character component = val.GetComponent<Character>(); if (Object.op_Implicit((Object)(object)component)) { component.m_name = TerrainMistilePlugin.DisplayName; component.m_faction = (Faction)10; component.m_aiSkipTarget = true; } MonsterAI component2 = val.GetComponent<MonsterAI>(); if (Object.op_Implicit((Object)(object)component2)) { component2.m_enableHuntPlayer = false; component2.m_attackPlayerObjects = false; ((BaseAI)component2).m_aggravatable = false; component2.m_alertRange = 0f; ((BaseAI)component2).m_viewRange = 0f; ((BaseAI)component2).m_hearRange = 0f; } Humanoid component3 = val.GetComponent<Humanoid>(); if (Object.op_Implicit((Object)(object)component3)) { component3.m_defaultItems = (GameObject[])(object)new GameObject[0]; } if (!Object.op_Implicit((Object)(object)val.GetComponent<TerrainMistileBehaviour>())) { val.AddComponent<TerrainMistileBehaviour>(); } MakeCollidersNonBlocking(val); ApplyVisuals(val, TerrainMistileSpawnRules.DefaultVisualColor); PrefabManager.Instance.AddPrefab(val); _registeredPrefab = val; _registered = true; TerrainMistilePlugin.TerrainMistileLogger.LogInfo((object)"Registered 'TerrainMistile' prefab from 'Mistile'."); } internal static void RefreshRegisteredPrefabVisuals() { //IL_0011: 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) if (Object.op_Implicit((Object)(object)_registeredPrefab)) { ApplyVisuals(_registeredPrefab, TerrainMistileSpawnRules.DefaultVisualColor); return; } GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("TerrainMistile") : null); if (Object.op_Implicit((Object)(object)val)) { ApplyVisuals(val, TerrainMistileSpawnRules.DefaultVisualColor); } } internal static void ApplyVisuals(GameObject root, Color color) { //IL_000a: 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_0018: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)root)) { ApplyLightColor(root, color); ApplyParticleColor(root, color); ApplyMaterialColor(root, color); } } internal static void MakeCollidersNonBlocking(GameObject root) { if (!Object.op_Implicit((Object)(object)root)) { return; } Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val)) { val.isTrigger = true; } } } private static void ApplyLightColor(GameObject root, Color color) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) Light[] componentsInChildren = root.GetComponentsInChildren<Light>(true); foreach (Light val in componentsInChildren) { val.color = WithAlpha(color, val.color.a); } } private static void ApplyParticleColor(GameObject root, Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem obj in componentsInChildren) { MainModule main = obj.main; ((MainModule)(ref main)).startColor = Recolor(((MainModule)(ref main)).startColor, color); ColorOverLifetimeModule colorOverLifetime = obj.colorOverLifetime; if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled) { ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = Recolor(((ColorOverLifetimeModule)(ref colorOverLifetime)).color, color); } } } private static MinMaxGradient Recolor(MinMaxGradient source, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown //IL_0023: 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_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_003a: 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_008a: 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_003d: 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_004a: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_00a6: 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_00b1: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) ParticleSystemGradientMode mode = ((MinMaxGradient)(ref source)).mode; return (MinMaxGradient)((int)mode switch { 0 => new MinMaxGradient(WithAlpha(color, ((MinMaxGradient)(ref source)).color.a)), 2 => new MinMaxGradient(WithAlpha(ScaleRgb(color, 0.65f), ((MinMaxGradient)(ref source)).colorMin.a), WithAlpha(ScaleRgb(color, 1.15f), ((MinMaxGradient)(ref source)).colorMax.a)), 1 => new MinMaxGradient(CreateGradient(((MinMaxGradient)(ref source)).gradient, color)), 3 => new MinMaxGradient(CreateGradient(((MinMaxGradient)(ref source)).gradientMin, color), CreateGradient(((MinMaxGradient)(ref source)).gradientMax, color)), _ => new MinMaxGradient(color), }); } private static Gradient CreateGradient(Gradient source, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0023: 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_002e: 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: 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_0057: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00a5: 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_00cb: Unknown result type (might be due to invalid IL or missing references) Gradient val = new Gradient(); GradientColorKey[] array = source.colorKeys; GradientAlphaKey[] array2 = source.alphaKeys; if (array == null || array.Length == 0) { array = (GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(color, 0f), new GradientColorKey(color, 1f) }; } GradientColorKey[] array3 = (GradientColorKey[])(object)new GradientColorKey[array.Length]; for (int i = 0; i < array.Length; i++) { array3[i] = new GradientColorKey(GetGradientShade(color, i, array.Length), array[i].time); } if (array2 == null || array2.Length == 0) { array2 = (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(color.a, 0f), new GradientAlphaKey(0f, 1f) }; } val.SetKeys(array3, array2); val.mode = source.mode; return val; } private static Color GetGradientShade(Color color, int index, int count) { //IL_0013: 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) float num = ((count <= 1) ? 0f : ((float)index / (float)(count - 1))); return ScaleRgb(color, Mathf.Lerp(1.3f, 0.7f, num)); } private static void ApplyMaterialColor(GameObject root, Color color) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) 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]; if (Object.op_Implicit((Object)(object)val2) && ShouldColorMaterial(val, val2)) { Material val3 = Object.Instantiate<Material>(val2); ApplyMaterialProperties(val3, color); sharedMaterials[j] = val3; flag = true; } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static bool ShouldColorMaterial(Renderer renderer, Material material) { string value = (Object.op_Implicit((Object)(object)((Component)renderer).gameObject) ? ((Object)((Component)renderer).gameObject).name : ""); string value2 = (Object.op_Implicit((Object)(object)material) ? ((Object)material).name : ""); if (!ContainsAny(value, "flame", "flare", "spark", "ember")) { return ContainsAny(value2, "flame", "spark", "glow", "pixel_unlit"); } return true; } private static void ApplyMaterialProperties(Material material, Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) SetMaterialColor(material, "_TintColor", color, preserveIntensity: false); SetMaterialColor(material, "_Color", color, preserveIntensity: false); SetMaterialColor(material, "_EmissionColor", color, preserveIntensity: true); } private static void SetMaterialColor(Material material, string property, Color color, bool preserveIntensity) { //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_002c: 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_003e: 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_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_005a: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(property)) { Color color2 = material.GetColor(property); float scale = (preserveIntensity ? Mathf.Max(new float[4] { 1f, color2.r, color2.g, color2.b }) : 1f); material.SetColor(property, WithAlpha(ScaleRgb(color, scale), color2.a)); } } private static bool ContainsAny(string value, params string[] needles) { foreach (string value2 in needles) { if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static Color ScaleRgb(Color color, float scale) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_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) return new Color(color.r * scale, color.g * scale, color.b * scale, color.a); } private static Color WithAlpha(Color color, float alpha) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) color.a = alpha; return color; } } internal static class TerrainMistileSpawnRules { private sealed class TerrainMistileSpawnRuleValues { public float? Interval { get; set; } public float? PlayerSearchRadius { get; set; } public float? SpawnChance { get; set; } public float? MaxDeformationSpawnChanceBonus { get; set; } public int? MaxSpawn { get; set; } public bool? PerPlayerSpawn { get; set; } public int? PlayerBaseValue { get; set; } public float? BaseCheckRadius { get; set; } public string? SpawnRadius { get; set; } public float? SpawnAltitude { get; set; } public float? ResetRadius { get; set; } public float? Health { get; set; } public string? VisualColor { get; set; } } private const float DefaultInterval = 60f; private const float DefaultPlayerSearchRadius = 32f; private const float DefaultSpawnChance = 0.25f; private const float DefaultMaxDeformationSpawnChanceBonus = 0.25f; private const bool DefaultScaleSpawnsWithNearbyPlayers = true; private const int DefaultIgnorePlayerBaseBaseValue = 1; private const float DefaultBaseCheckRadius = 24f; private const int DefaultMaxActiveTerrainMistilesPerArea = 3; private const float DefaultSpawnRadiusMin = 16f; private const float DefaultSpawnRadiusMax = 32f; private const float DefaultSpawnAltitude = 8f; private const float DefaultResetRadius = 8f; private const float DefaultHealth = 1f; internal const string DefaultVisualColorHex = "#45FF5A"; private static readonly Color FallbackVisualColor = new Color(0.27f, 1f, 0.353f, 1f); private static readonly string[] DefaultPlayerBasePrefabNames = new string[40] { "ashwood_bed", "bed", "blackforge", "blastfurnace", "BogWitch_Fire_Pit", "bonfire", "charcoal_kiln", "charred_shieldgenerator", "dverger_guardstone", "eitrrefinery", "fermenter", "fire_pit", "fire_pit_haldor", "fire_pit_hildir", "fire_pit_iron", "forge", "guard_stone", "hearth", "piece_artisanstation", "piece_bed02", "piece_brazierceiling01", "piece_brazierfloor01", "piece_brazierfloor02", "piece_groundtorch", "piece_groundtorch_blue", "piece_groundtorch_green", "piece_groundtorch_mist", "piece_groundtorch_wood", "piece_magetable", "piece_oven", "piece_shieldgenerator", "piece_spinningwheel", "piece_stonecutter", "piece_walltorch", "piece_workbench", "portal", "portal_stone", "portal_wood", "smelter", "windmill" }; private static readonly IDeserializer Deserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); private static readonly Dictionary<int, TerrainMistileBiomeSpawnRule> BiomeRules = new Dictionary<int, TerrainMistileBiomeSpawnRule>(); private static TerrainMistileBiomeSpawnRule _defaultRule = CreateDefaultRule(); private static HashSet<string> _playerBasePrefabNames = CreateDefaultPlayerBasePrefabNames(); private static float _maxPlayerSearchRadius = 32f; private static float _maxResetRadius = 8f; private static bool _hasEnabledRules = true; private static ManualLogSource? _logger; internal static float MaxPlayerSearchRadius => _maxPlayerSearchRadius; internal static float MaxResetRadius => _maxResetRadius; internal static bool HasEnabledRules => _hasEnabledRules; internal static Color DefaultVisualColor => _defaultRule.VisualColor; internal static bool IsPlayerBasePrefabName(string prefabName) { return _playerBasePrefabNames.Contains(prefabName); } internal static void Initialize(ManualLogSource logger) { _logger = logger; } internal static void EnsureFileExists(string path) { if (!File.Exists(path)) { string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrWhiteSpace(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllText(path, BuildDefaultYaml()); } } internal static bool LoadYamlText(string yaml, string source) { if (!TryParseYaml(yaml, out TerrainMistileBiomeSpawnRule defaultRule, out Dictionary<int, TerrainMistileBiomeSpawnRule> parsedRules, out HashSet<string> playerBasePrefabNames, out string error)) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogError((object)("Failed to parse TerrainMistile spawn rules from " + source + ": " + error)); } return false; } _defaultRule = defaultRule; _playerBasePrefabNames = playerBasePrefabNames; BiomeRules.Clear(); foreach (KeyValuePair<int, TerrainMistileBiomeSpawnRule> item in parsedRules) { BiomeRules[item.Key] = item.Value; } RecalculateRuntimeState(); ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)$"Loaded TerrainMistile spawn rules from {source}. Default={_defaultRule}; overrides={BiomeRules.Count}; playerBasePrefabs={_playerBasePrefabNames.Count}; enabled={_hasEnabledRules}."); } TerrainMistileSystem.ClearSpawnUnitRollState(); TerrainMistilePrefab.RefreshRegisteredPrefabVisuals(); return true; } internal static bool TryGetEnabledRule(int biome, out TerrainMistileBiomeSpawnRule rule) { rule = GetRule(biome); if (biome != 0) { return rule.Enabled; } return false; } internal static TerrainMistileBiomeSpawnRule GetRule(int biome) { if (!BiomeRules.TryGetValue(biome, out var value)) { return _defaultRule; } return value; } internal static int GetBiomeKey(Vector3 point) { //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_0007: Expected I4, but got Unknown return (int)Heightmap.FindBiome(point); } internal static string GetBiomeName(int biome) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (TerrainMistileExpandWorldDataBiomeCompat.TryGetDisplayName(biome, out string name)) { return name; } string text = ((object)(Biome)biome/*cast due to .constrained prefix*/).ToString(); if (!string.IsNullOrWhiteSpace(text)) { return text; } return biome.ToString(CultureInfo.InvariantCulture); } private static bool TryParseYaml(string yaml, out TerrainMistileBiomeSpawnRule defaultRule, out Dictionary<int, TerrainMistileBiomeSpawnRule> parsedRules, out HashSet<string> playerBasePrefabNames, out string error) { defaultRule = CreateDefaultRule(); parsedRules = new Dictionary<int, TerrainMistileBiomeSpawnRule>(); playerBasePrefabNames = CreateDefaultPlayerBasePrefabNames(); error = ""; if (string.IsNullOrWhiteSpace(yaml)) { return true; } Dictionary<object, object> dictionary; try { dictionary = Deserializer.Deserialize<Dictionary<object, object>>(yaml); } catch (Exception ex) { error = ex.Message; return false; } if (dictionary == null) { return true; } TerrainMistileSpawnRuleValues terrainMistileSpawnRuleValues = null; foreach (KeyValuePair<object, object> item in dictionary) { string yamlKey = GetYamlKey(item.Key); if (yamlKey.Equals("defaults", StringComparison.OrdinalIgnoreCase)) { terrainMistileSpawnRuleValues = CreateValues(item.Value); } else if (yamlKey.Equals("playerBasePrefabs", StringComparison.OrdinalIgnoreCase)) { playerBasePrefabNames = CreatePlayerBasePrefabNames(item.Value); } } if (terrainMistileSpawnRuleValues != null) { defaultRule = CreateRule(terrainMistileSpawnRuleValues, defaultRule); } foreach (KeyValuePair<object, object> item2 in dictionary) { string yamlKey2 = GetYamlKey(item2.Key); if (yamlKey2.Equals("defaults", StringComparison.OrdinalIgnoreCase) || yamlKey2.Equals("playerBasePrefabs", StringComparison.OrdinalIgnoreCase)) { continue; } string text = NormalizeBiomeName(yamlKey2); if (text.Length == 0 || text.Equals("None", StringComparison.OrdinalIgnoreCase)) { continue; } if (!TryResolveBiomeKey(yamlKey2, out var biome)) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Ignoring unknown biome '" + yamlKey2 + "' in TerrainMistile spawn rules.")); } } else { parsedRules[biome] = CreateRule(CreateValues(item2.Value), defaultRule); } } return true; } private static string GetYamlKey(object? key) { return key?.ToString()?.Trim() ?? ""; } private static TerrainMistileSpawnRuleValues? CreateValues(object? value) { if (value == null) { return null; } if (!(value is IDictionary<object, object> dictionary)) { return null; } TerrainMistileSpawnRuleValues terrainMistileSpawnRuleValues = new TerrainMistileSpawnRuleValues(); foreach (KeyValuePair<object, object> item in dictionary) { switch (NormalizeFieldName(GetYamlKey(item.Key))) { case "interval": { if (TryGetFloat(item.Value, out var result11)) { terrainMistileSpawnRuleValues.Interval = result11; } break; } case "playersearchradius": { if (TryGetFloat(item.Value, out var result7)) { terrainMistileSpawnRuleValues.PlayerSearchRadius = result7; } break; } case "spawnchance": { if (TryGetFloat(item.Value, out var result3)) { terrainMistileSpawnRuleValues.SpawnChance = result3; } break; } case "maxdeformationspawnchancebonus": { if (TryGetFloat(item.Value, out var result2)) { terrainMistileSpawnRuleValues.MaxDeformationSpawnChanceBonus = result2; } break; } case "maxspawn": { if (TryGetInt(item.Value, out var result10)) { terrainMistileSpawnRuleValues.MaxSpawn = result10; } break; } case "perplayerspawn": { if (TryGetBool(item.Value, out var result9)) { terrainMistileSpawnRuleValues.PerPlayerSpawn = result9; } break; } case "playerbasevalue": { if (TryGetInt(item.Value, out var result5)) { terrainMistileSpawnRuleValues.PlayerBaseValue = result5; } break; } case "basecheckradius": { if (TryGetFloat(item.Value, out var result)) { terrainMistileSpawnRuleValues.BaseCheckRadius = result; } break; } case "spawnradius": terrainMistileSpawnRuleValues.SpawnRadius = item.Value?.ToString(); break; case "spawnaltitude": { if (TryGetFloat(item.Value, out var result8)) { terrainMistileSpawnRuleValues.SpawnAltitude = result8; } break; } case "resetradius": { if (TryGetFloat(item.Value, out var result6)) { terrainMistileSpawnRuleValues.ResetRadius = result6; } break; } case "health": { if (TryGetFloat(item.Value, out var result4)) { terrainMistileSpawnRuleValues.Health = result4; } break; } case "visualcolor": terrainMistileSpawnRuleValues.VisualColor = item.Value?.ToString(); break; } } return terrainMistileSpawnRuleValues; } private static HashSet<string> CreatePlayerBasePrefabNames(object? value) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (value is string value2) { AddPlayerBasePrefabNames(value2, hashSet); return hashSet; } if (value is IEnumerable<object> enumerable) { { foreach (object item in enumerable) { AddPlayerBasePrefabNames(item?.ToString(), hashSet); } return hashSet; } } ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)"Ignoring invalid playerBasePrefabs value in TerrainMistile spawn rules. Use a YAML list or comma-separated string."); } return hashSet; } private static HashSet<string> CreateDefaultPlayerBasePrefabNames() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] defaultPlayerBasePrefabNames = DefaultPlayerBasePrefabNames; for (int i = 0; i < defaultPlayerBasePrefabNames.Length; i++) { AddPlayerBasePrefabNames(defaultPlayerBasePrefabNames[i], hashSet); } return hashSet; } private static void AddPlayerBasePrefabNames(string? value, HashSet<string> names) { string text = value?.Trim(); if (text == null || text.Length == 0) { return; } string[] array = text.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0) { names.Add(text2); } } } private static string NormalizeFieldName(string value) { return value.Trim().Replace(" ", "").Replace("_", "") .Replace("-", "") .ToLowerInvariant(); } private static bool TryGetFloat(object? value, out float result) { if (!(value is float num)) { if (!(value is double num2)) { if (!(value is decimal num3)) { if (!(value is int num4)) { if (!(value is long num5)) { if (value is string value2) { return TryParseFloat(value2, out result); } result = 0f; return false; } result = num5; return true; } result = num4; return true; } result = (float)num3; return true; } result = (float)num2; return true; } result = num; return true; } private static bool TryGetInt(object? value, out int result) { if (!(value is int num)) { if (!(value is long num2)) { if (!(value is float num3)) { if (!(value is double a)) { if (value is string text) { return int.TryParse(text.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result); } result = 0; return false; } result = (int)Math.Round(a); return true; } result = Mathf.RoundToInt(num3); return true; } result = (int)num2; return true; } result = num; return true; } private static bool TryGetBool(object? value, out bool result) { if (!(value is bool flag)) { if (value is string text) { return bool.TryParse(text.Trim(), out result); } result = false; return false; } result = flag; return true; } private static bool TryResolveBiomeKey(string value, out int biome) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected I4, but got Unknown string text = value.Trim(); string text2 = NormalizeBiomeName(text); if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out biome)) { return true; } if (uint.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { biome = (int)result; return true; } if (Enum.TryParse<Biome>(text2, ignoreCase: true, out Biome result2)) { biome = (int)result2; return true; } if (TerrainMistileExpandWorldDataBiomeCompat.TryGetBiome(text, out biome)) { return true; } if (!string.Equals(text, text2, StringComparison.Ordinal)) { return TerrainMistileExpandWorldDataBiomeCompat.TryGetBiome(text2, out biome); } return false; } private static TerrainMistileBiomeSpawnRule CreateRule(TerrainMistileSpawnRuleValues? values, TerrainMistileBiomeSpawnRule fallback) { //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0311: 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_0212: Unknown result type (might be due to invalid IL or missing references) if (values == null) { return fallback; } float num = values.Interval ?? fallback.Interval; float num2 = values.PlayerSearchRadius ?? fallback.PlayerSearchRadius; float num3 = values.SpawnChance ?? fallback.SpawnChance; float num4 = values.MaxDeformationSpawnChanceBonus ?? fallback.MaxDeformationSpawnChanceBonus; bool scaleSpawnsWithNearbyPlayers = values.PerPlayerSpawn ?? fallback.ScaleSpawnsWithNearbyPlayers; int num5 = values.PlayerBaseValue ?? fallback.IgnorePlayerBaseBaseValue; float num6 = values.BaseCheckRadius ?? fallback.BaseCheckRadius; int num7 = values.MaxSpawn ?? fallback.MaxActiveTerrainMistilesPerArea; float minRadius = fallback.SpawnRadiusMin; float maxRadius = fallback.SpawnRadiusMax; string spawnRadius = values.SpawnRadius; if (spawnRadius != null && !string.IsNullOrWhiteSpace(spawnRadius) && !TryParseSpawnRadius(spawnRadius, out minRadius, out maxRadius)) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Ignoring invalid spawnRadius '" + spawnRadius + "' in TerrainMistile spawn rules. Use a number like '24' or a range like '16~32'.")); } minRadius = fallback.SpawnRadiusMin; maxRadius = fallback.SpawnRadiusMax; } float num8 = values.SpawnAltitude ?? fallback.SpawnAltitude; float num9 = values.ResetRadius ?? fallback.ResetRadius; float num10 = values.Health ?? fallback.Health; Color visualColor = fallback.VisualColor; string visualColor2 = values.VisualColor; if (visualColor2 != null && !string.IsNullOrWhiteSpace(visualColor2)) { if (TryParseVisualColor(visualColor2, out var color)) { visualColor = color; } else { ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Ignoring invalid visualColor '" + visualColor2 + "' in TerrainMistile spawn rules. Use an HTML hex color like '#45FF5A' or '45FF5A'.")); } } } float interval = Mathf.Clamp(num, 0f, 3600f); num2 = Mathf.Clamp(num2, 0f, 512f); num3 = Mathf.Clamp01(num3); num4 = Mathf.Clamp01(num4); num5 = Mathf.Clamp(num5, 0, 10); num6 = Mathf.Clamp(num6, 0f, 128f); num7 = Mathf.Clamp(num7, 0, 50); minRadius = Mathf.Clamp(minRadius, 1f, 256f); maxRadius = Mathf.Clamp(maxRadius, 1f, 256f); num8 = Mathf.Clamp(num8, 1f, 64f); num9 = Mathf.Clamp(num9, 1f, 64f); num10 = Mathf.Clamp(num10, 1f, 10000f); if (minRadius > maxRadius) { float num11 = maxRadius; maxRadius = minRadius; minRadius = num11; } return new TerrainMistileBiomeSpawnRule(interval, num2, num3, num4, scaleSpawnsWithNearbyPlayers, num5, num6, num7, minRadius, maxRadius, num8, num9, num10, visualColor); } private static void RecalculateRuntimeState() { _maxPlayerSearchRadius = (_defaultRule.Enabled ? _defaultRule.PlayerSearchRadius : 0f); _maxResetRadius = _defaultRule.ResetRadius; _hasEnabledRules = _defaultRule.Enabled; foreach (TerrainMistileBiomeSpawnRule value in BiomeRules.Values) { _maxResetRadius = Mathf.Max(_maxResetRadius, value.ResetRadius); if (value.Enabled) { _hasEnabledRules = true; _maxPlayerSearchRadius = Mathf.Max(_maxPlayerSearchRadius, value.PlayerSearchRadius); } } } private static TerrainMistileBiomeSpawnRule CreateDefaultRule() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) return new TerrainMistileBiomeSpawnRule(60f, 32f, 0.25f, 0.25f, scaleSpawnsWithNearbyPlayers: true, 1, 24f, 3, 16f, 32f, 8f, 8f, 1f, FallbackVisualColor); } private static bool TryParseSpawnRadius(string value, out float minRadius, out float maxRadius) { minRadius = 0f; maxRadius = 0f; string[] array = value.Split(new char[1] { '~' }); if (array.Length == 1) { if (!TryParseFloat(array[0], out minRadius)) { return false; } maxRadius = minRadius; return true; } if (array.Length != 2 || !TryParseFloat(array[0], out minRadius) || !TryParseFloat(array[1], out maxRadius)) { return false; } return true; } private static bool TryParseFloat(string value, out float result) { return float.TryParse(value.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result); } private static bool TryParseVisualColor(string value, out Color color) { string text = value.Trim(); if (text.Length > 0 && text[0] != '#') { text = "#" + text; } return ColorUtility.TryParseHtmlString(text, ref color); } private static string NormalizeBiomeName(string value) { return value.Trim().Replace(" ", "").Replace("_", "") .Replace("-", ""); } private static string BuildDefaultPlayerBasePrefabsYaml() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# TerrainMistile base prefabs used by playerBaseValue. Only instances with ZDO longs.creator != 0 are counted."); stringBuilder.AppendLine("playerBasePrefabs:"); string[] defaultPlayerBasePrefabNames = DefaultPlayerBasePrefabNames; foreach (string value in defaultPlayerBasePrefabNames) { stringBuilder.Append(" - ").AppendLine(value); } return stringBuilder.ToString(); } private static string BuildDefaultYaml() { return "# Expand World Data custom biomes can use their custom biome name or numeric biome value.\n# defaults and playerBasePrefabs are reserved. Every other top-level key is treated as a biome rule.\n\ndefaults:\n interval: 60 # Seconds between spawn rolls for one 32m terrain unit. 0 disables that biome.\n playerSearchRadius: 32 # Players within this horizontal radius of a changed terrain unit activate its rolls.\n spawnChance: 0.25 # Base chance used when the unit interval is ready and at least one player is nearby.\n maxDeformationSpawnChanceBonus: 0.25 # Added to spawnChance when the largest height deformation in the 32m terrain unit reaches the 8m cap. Scales linearly from 0m to 8m.\n maxSpawn: 3 # Maximum active TerrainMistiles with targets within 32m of the target. 0 disables that biome.\n perPlayerSpawn: true # If true, one successful roll can spawn up to one TerrainMistile per nearby player, capped by maxSpawn and available targets.\n playerBaseValue: 1 # playerBaseValue N skips spawn checks when at least N unique listed player-placed base prefab types are within baseCheckRadius meters horizontally of the changed terrain. 0 disables the PlayerBase check.\n baseCheckRadius: 24 # Horizontal radius used by playerBaseValue to count listed player-placed base prefab types.\n spawnRadius: 16~32 # Horizontal spawn distance from the selected nearby player. Use 24 for fixed distance or 16~32 for a random range.\n spawnAltitude: 8 # Height above solid ground where TerrainMistile spawns.\n resetRadius: 8 # Radius of terrain height and paint reset when TerrainMistile detonates.\n health: 1 # Maximum and current health applied when TerrainMistile spawns. Biome rules can override it.\n visualColor: \"#45FF5A\" # HTML hex color used for TerrainMistile flames, sparks, and light. Biome rules can override it.\nMeadows:\n interval: 120\n spawnChance: 0.1\n resetRadius: 4\n visualColor: \"#7CFF6B\"\nBlackForest:\n interval: 120\n resetRadius: 6\n visualColor: \"#2ED36F\"\nSwamp:\n playerBaseValue: 2\n visualColor: \"#8FBF3F\"\nMountain:\n interval: 120\n playerBaseValue: 2\n resetRadius: 6\n visualColor: \"#8FE8FF\"\nPlains:\n interval: 120\n playerBaseValue: 3\n resetRadius: 6\n visualColor: \"#FFD15C\"\nMistlands:\n interval: 120\n playerBaseValue: 3\n resetRadius: 6\n visualColor: \"#B58CFF\"\nAshLands:\n playerBaseValue: 4\n visualColor: \"#FF5A2E\"\nDeepNorth:\n playerBaseValue: 4\n visualColor: \"#BFEFFF\"\nOcean:\n visualColor: \"#3EA7FF\"\n\n" + BuildDefaultPlayerBasePrefabsYaml(); } } internal static class TerrainMistileExpandWorldDataBiomeCompat { private sealed class ExpandWorldDataBiomeYaml { public string Biome { get; set; } = ""; } private const int FirstCustomBiomeBase = 512; private static readonly Dictionary<string, int> OriginalBiomes = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { ["None"] = 0, ["Meadows"] = 1, ["Swamp"] = 2, ["Mountain"] = 4, ["BlackForest"] = 8, ["Plains"] = 16, ["AshLands"] = 32, ["DeepNorth"] = 64, ["Ocean"] = 256, ["Mistlands"] = 512 }; private static readonly IDeserializer ExpandWorldDataBiomeDeserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); private static readonly Dictionary<string, int> FileNameToBiome = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<int, string> FileBiomeToName = new Dictionary<int, string>(); private static bool _fileMappingLoaded; private static MethodInfo? _tryGetBiomeMethod; private static MethodInfo? _tryGetDisplayNameMethod; internal static bool TryGetBiome(string name, out int biome) { biome = 0; if (string.IsNullOrWhiteSpace(name)) { return false; } if (TryGetBiomeFromExpandWorldData(name.Trim(), out biome)) { return true; } EnsureFileMappingLoaded(); if (!FileNameToBiome.TryGetValue(name.Trim(), out biome)) { return FileNameToBiome.TryGetValue(NormalizeName(name), out biome); } return true; } internal static bool TryGetDisplayName(int biome, out string name) { if (TryGetDisplayNameFromExpandWorldData(biome, out name)) { return true; } EnsureFileMappingLoaded(); return FileBiomeToName.TryGetValue(biome, out name); } private static bool TryGetBiomeFromExpandWorldData(string name, out int biome) { biome = 0; EnsureReflectionMethods(); if (_tryGetBiomeMethod == null) { return false; } ParameterInfo[] parameters = _tryGetBiomeMethod.GetParameters(); object[] array = new object[2] { name, Enum.ToObject(parameters[1].ParameterType.GetElementType() ?? parameters[1].ParameterType, 0) }; try { object obj = _tryGetBiomeMethod.Invoke(null, array); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { biome = Convert.ToInt32(array[1], CultureInfo.InvariantCulture); return true; } } catch { _tryGetBiomeMethod = null; } return false; } private static bool TryGetDisplayNameFromExpandWorldData(int biome, out string name) { name = ""; EnsureReflectionMethods(); if (_tryGetDisplayNameMethod == null) { return false; } Type parameterType = _tryGetDisplayNameMethod.GetParameters()[0].ParameterType; object[] array = new object[2] { Enum.ToObject(parameterType, biome), "" }; try { object obj = _tryGetDisplayNameMethod.Invoke(null, array); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0 && array[1] is string text && !string.IsNullOrWhiteSpace(text)) { name = text; return true; } } catch { _tryGetDisplayNameMethod = null; } return false; } private static void EnsureReflectionMethods() { if (_tryGetBiomeMethod != null && _tryGetDisplayNameMethod != null) { return; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { AssemblyName name; try { name = assembly.GetName(); } catch { continue; } if (!string.Equals(name.Name, "ExpandWorldData", StringComparison.OrdinalIgnoreCase)) { continue; } Type type = assembly.GetType("ExpandWorldData.BiomeManager", throwOnError: false); if (!(type == null)) { if ((object)_tryGetBiomeMethod == null) { _tryGetBiomeMethod = type.GetMethod("TryGetBiome", BindingFlags.Static | BindingFlags.Public); } if ((object)_tryGetDisplayNameMethod == null) { _tryGetDisplayNameMethod = type.GetMethod("TryGetDisplayName", BindingFlags.Static | BindingFlags.Public); } break; } } } private static void EnsureFileMappingLoaded() { if (_fileMappingLoaded) { return; } _fileMappingLoaded = true; foreach (KeyValuePair<string, int> originalBiome in OriginalBiomes) { AddFileBiomeName(originalBiome.Key, originalBiome.Value); } string path = Path.Combine(Paths.ConfigPath, "expand_world"); if (!Directory.Exists(path)) { return; } string[] files; try { files = Directory.GetFiles(path, "expand_biomes*.yaml"); } catch { return; } Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); int biome = 512; string[] array = files; foreach (string path2 in array) { List<ExpandWorldDataBiomeYaml> list; try { list = ExpandWorldDataBiomeDeserializer.Deserialize<List<ExpandWorldDataBiomeYaml>>(File.ReadAllText(path2)); } catch { continue; } if (list == null) { continue; } foreach (ExpandWorldDataBiomeYaml item in list) { string text = item.Biome.Trim(); if (text.Length != 0 && !FileNameToBiome.ContainsKey(text)) { biome = NextBiome(biome); AddFileBiomeName(text, biome); } } } } private static int NextBiome(int biome) { return biome switch { 128 => 128, int.MinValue => 128, _ => 2 * biome, }; } private static void AddFileBiomeName(string name, int biome) { FileNameToBiome[name] = biome; string text = NormalizeName(name); if (!string.Equals(name, text, StringComparison.OrdinalIgnoreCase)) { FileNameToBiome[text] = biome; } FileBiomeToName[biome] = name; } private static string NormalizeName(string value) { return value.Trim().Replace(" ", "").Replace("_", "") .Replace("-", ""); } } internal readonly struct TerrainMistileBiomeSpawnRule { public float Interval { get; } public float PlayerSearchRadius { get; } public float SpawnChance { get; } public float MaxDeformationSpawnChanceBonus { get; } public bool ScaleSpawnsWithNearbyPlayers { get; } public int IgnorePlayerBaseBaseValue { get; } public float BaseCheckRadius { get; } public int MaxActiveTerrainMistilesPerArea { get; } public float SpawnRadiusMin { get; } public float SpawnRadiusMax { get; } public float SpawnAltitude { get; } public float ResetRadius { get; } public float Health { get; } public Color VisualColor { get; } public bool Enabled { get { if (Interval > 0f && PlayerSearchRadius > 0f && (SpawnChance > 0f || MaxDeformationSpawnChanceBonus > 0f)) { return MaxActiveTerrainMistilesPerArea > 0; } return false; } } public TerrainMistileBiomeSpawnRule(float interval, float playerSearchRadius, float spawnChance, float maxDeformationSpawnChanceBonus, bool scaleSpawnsWithNearbyPlayers, int ignorePlayerBaseBaseValue, float baseCheckRadius, int maxActiveTerrainMistilesPerArea, float spawnRadiusMin, float spawnRadiusMax, float spawnAltitude, float resetRadius, float health, Color visualColor) { //IL_0066: 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) Interval = interval; PlayerSearchRadius = playerSearchRadius; SpawnChance = spawnChance; MaxDeformationSpawnChanceBonus = maxDeformationSpawnChanceBonus; ScaleSpawnsWithNearbyPlayers = scaleSpawnsWithNearbyPlayers; IgnorePlayerBaseBaseValue = ignorePlayerBaseBaseValue; BaseCheckRadius = baseCheckRadius; MaxActiveTerrainMistilesPerArea = maxActiveTerrainMistilesPerArea; SpawnRadiusMin = spawnRadiusMin; SpawnRadiusMax = spawnRadiusMax; SpawnAltitude = spawnAltitude; ResetRadius = resetRadius; Health = health; VisualColor = visualColor; } public float GetEffectiveSpawnChance(float deformationPressure) { return Mathf.Clamp01(SpawnChance + MaxDeformationSpawnChanceBonus * Mathf.Clamp01(deformationPressure)); } public override string ToString() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) return $"interval={Interval:0.##}, playerSearchRadius={PlayerSearchRadius:0.##}, spawnChance={SpawnChance:0.###}, maxDeformationSpawnChanceBonus={MaxDeformationSpawnChanceBonus:0.###}, maxActive={MaxActiveTerrainMistilesPerArea}, playerBaseValue={IgnorePlayerBaseBaseValue}, baseCheckRadius={BaseCheckRadius:0.##}, spawnRadius={SpawnRadiusMin:0.##}~{SpawnRadiusMax:0.##}, resetRadius={ResetRadius:0.##}, health={Health:0.##}, visualColor=#{ColorUtility.ToHtmlStringRGB(VisualColor)}"; } } internal static class TerrainMistileSystem { private sealed class TargetReservation { public Vector3 Point; public float Radius; public float ExpireTime; } private sealed class ExternalTerrainIgnoreArea { public Vector3 Center; public float Radius; public string Source = ""; public float ExpireTime; } private readonly struct PlayerBasePiece { public string PrefabName { get; } public Vector3 Position { get; } public PlayerBasePiece(string prefabName, Vector3 position) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) PrefabName = prefabName; Position = position; } } private readonly struct PlayerBasePieceBucketKey : IEquatable<PlayerBasePieceBucketKey> { public int X { get; } public int Z { get; } public PlayerBasePieceBucketKey(int x, int z) { X = x; Z = z; } public bool Equals(PlayerBasePieceBucketKey other) { if (X == other.X) { return Z == other.Z; } return false; } public override bool Equals(object? obj) { if (obj is PlayerBasePieceBucketKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (X * 397) ^ Z; } } private readonly struct NoModifiedTerrainCompCache { public int Operations { get; } public float ExpireTime { get; } public NoModifiedTerrainCompCache(int operations, float expireTime) { Operations = operations; ExpireTime = expireTime; } } private readonly struct SpawnUnitKey : IEquatable<SpawnUnitKey> { public int X { get; } public int Z { get; } public int Biome { get; } public SpawnUnitKey(int x, int z, int biome) { X = x; Z = z; Biome = biome; } public bool Equals(SpawnUnitKey other) { if (X == other.X && Z == other.Z) { return Biome == other.Biome; } return false; } public override bool Equals(object? obj) { if (obj is SpawnUnitKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (((X * 397) ^ Z) * 397) ^ Biome; } public override string ToString() { return $"{TerrainMistileSpawnRules.GetBiomeName(Biome)}@{X},{Z}"; } } private sealed class ModifiedTerrainUnitCandidate { public SpawnUnitKey Key; public int Biome; public Vector3 TargetPoint; public float BestScore; public float MaxDeformationPressure; public int ModifiedCellCount; } private const string ResetEffectsRpcName = "TerrainMistile_ResetEffects"; private const float ResetEffectGroundOffset = 0.1f; private const float FallbackEffectDestroyDelay = 20f; private const float ActiveTerrainMistileAreaRadius = 32f; private const float SpawnUnitSize = 32f; private const float TerrainHeightDeformationCap = 8f; private const float SpawnUnitScanInterval = 1f; private const float SpawnUnitRollStateRetention = 600f; private const float NoModifiedTerrainCompRetention = 3f; private const float PlayerBasePieceBucketRefreshInterval = 2f; private const float TargetReservationDuration = 60f; private const float ExternalTerrainIgnoreMergeDistance = 0.25f; internal const float LocationTerrainProtectionPadding = 5f; internal const float LocationTerrainIgnoreDuration = 10f; private const string ResetVfxPrefabName = "fx_greenroots_projectile_hit"; private const string ResetSfxPrefabName = "sfx_staff_elder_grow"; private static readonly Dictionary<SpawnUnitKey, float> LastSpawnRollTimeByUnit = new Dictionary<SpawnUnitKey, float>(); private static readonly Dictionary<TerrainComp, NoModifiedTerrainCompCache> NoModifiedTerrainComps = new Dictionary<TerrainComp, NoModifiedTerrainCompCache>(); private static readonly Dictionary<SpawnUnitKey, ModifiedTerrainUnitCandidate> ModifiedTerrainUnits = new Dictionary<SpawnUnitKey, ModifiedTerrainUnitCandidate>(); private static readonly List<SpawnUnitKey> TempSpawnUnitKeys = new List<SpawnUnitKey>(); private static readonly HashSet<SpawnUnitKey> TempCooldownSpawnUnitKeys = new HashSet<SpawnUnitKey>(); private static readonly List<TerrainComp> TempNoModifiedTerrainComps = new List<TerrainComp>(); private static readonly List<TerrainMistileBehaviour> ActiveTerrainMistiles = new List<TerrainMistileBehaviour>(); private static readonly List<Player> TempPlayers = new List<Player>(); private static readonly List<Player> TempNearbyPlayers = new List<Player>(); private static readonly List<Heightmap> TempHeightmaps = new List<Heightmap>(); private static readonly List<TargetReservation> TargetReservations = new List<TargetReservation>(); private static readonly List<ExternalTerrainIgnoreArea> ExternalTerrainIgnoreAreas = new List<ExternalTerrainIgnoreArea>(); private static readonly List<ExternalTerrainIgnoreArea> ProtectedTerrainAreas = new List<ExternalTerrainIgnoreArea>(); private static readonly Dictionary<PlayerBasePieceBucketKey, List<PlayerBasePiece>> PlayerBasePiecesByBucket = new Dictionary<PlayerBasePieceBucketKey, List<PlayerBasePiece>>(); private static readonly HashSet<string> TempPlayerBasePrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static bool _playerBasePieceBucketsBuilt; private static float _nextPlayerBasePieceBucketRefreshTime; private static bool _resettingTerrain; private static float _nextSpawnUnitScanTime; private static bool _resetEffectsRpcRegistered; internal static void UpdatePersistentTerrainSpawns() { if (_resettingTerrain || !TerrainMistileSpawnRules.HasEnabledRules || !Object.op_Implicit((Object)(object)ZNetScene.instance) || Time.time < _nextSpawnUnitScanTime) { return; } _nextSpawnUnitScanTime = Time.time + 1f; CollectEligiblePlayers(); if (TempPlayers.Count == 0) { return; } CollectModifiedTerrainUnits(); CleanupSpawnUnitRollState(); foreach (ModifiedTerrainUnitCandidate value in ModifiedTerrainUnits.Values) { TryRollSpawnForTerrainUnit(value); } } internal static void UpdateResetEffectRpcRegistration() { if (!_resetEffectsRpcRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<ZPackage>("TerrainMistile_ResetEffects", (Action<long, ZPackage>)RPC_ResetEffects); _resetEffectsRpcRegistered = true; } } i