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.1.0
TerrainMistile.dll
Decompiled 2 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.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; 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.1.0")] [assembly: InternalsVisibleTo("TerrainMistile.Tests")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.1.0.0")] 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; } } } namespace TerrainMistile { [BepInPlugin("sighsorry.TerrainMistile", "TerrainMistile", "1.1.0")] public class TerrainMistilePlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } private static class ConfigPersistence { public static void Save(ConfigFile config, bool reload = false) { bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { if (reload) { config.Reload(); } config.Save(); } finally { config.SaveOnConfigSet = saveOnConfigSet; } } } internal const string ModName = "TerrainMistile"; internal const string ModVersion = "1.1.0"; internal const string Author = "sighsorry"; internal const string DisplayNameToken = "$terrainmistile_creature_name"; internal const string EnforcerDisplayNameToken = "$terrainmistile_enforcer_name"; internal const string CompendiumTopicToken = "$terrainmistile_compendium_topic"; internal const string CheckCompendiumMessageToken = "$terrainmistile_message_check_compendium"; private const string ModGUID = "sighsorry.TerrainMistile"; private const string ConfigFileName = "sighsorry.TerrainMistile.cfg"; private const string SpawnRulesFileName = "TerrainMistile.yml"; private static readonly string ConfigFileFullPath = Path.Combine(Paths.ConfigPath, "sighsorry.TerrainMistile.cfg"); private static readonly string SpawnRulesFileFullPath = Path.Combine(Paths.ConfigPath, "TerrainMistile.yml"); private readonly Harmony _harmony = new Harmony("sighsorry.TerrainMistile"); private bool _initialized; public static readonly ManualLogSource TerrainMistileLogger = Logger.CreateLogSource("TerrainMistile"); private static readonly ConfigSync ConfigSync = new ConfigSync("sighsorry.TerrainMistile") { DisplayName = "TerrainMistile", CurrentVersion = "1.1.0", MinimumRequiredVersion = "1.1.0", ModRequired = true }; private FileSystemWatcher _watcher; private FileSystemWatcher _spawnRulesWatcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private DateTime _lastSpawnRulesReloadTime; private string? _lastConfigFileText; private string? _appliedSpawnRulesYamlText; private const long RELOAD_DELAY = 10000000L; private static ConfigEntry<Toggle> _terrainMistileEnabled = null; private static ConfigEntry<Toggle> _serverConfigLocked = null; private static CustomSyncedValue<string> SpawnRulesYaml = null; internal static bool SpawningEnabled { get { ConfigEntry<Toggle> terrainMistileEnabled = _terrainMistileEnabled; if (terrainMistileEnabled == null) { return true; } return terrainMistileEnabled.Value != Toggle.Off; } } public void Awake() { TerrainMistileLocalization.Load(TerrainMistileLogger); TerrainCompAccess.Initialize(); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { _terrainMistileEnabled = config("1 - General", "Enable TerrainMistile", Toggle.On, "Globally enables new TerrainMistile spawns. Existing TerrainMistiles are not removed when disabled."); _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); RemoveObsoleteDisplayNameConfig(); TerrainMistileSpawnRules.Initialize(TerrainMistileLogger); TerrainMistileSpawnRules.EnsureFileExists(SpawnRulesFileFullPath); SpawnRulesYaml = new CustomSyncedValue<string>(ConfigSync, "SpawnRulesYaml", string.Empty); SpawnRulesYaml.ValueChanged += OnSyncedSpawnRulesYamlChanged; ConfigSync.SourceOfTruthChanged += OnSourceOfTruthChanged; ApplySpawnRulesYaml(File.ReadAllText(SpawnRulesFileFullPath), "local fallback"); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); TerrainMistileLocalization.ApplyToCurrentLanguage(); TerrainMistileExternalTerrainCompat.Initialize(TerrainMistileLogger, _harmony); SetupWatcher(); if (ConfigSync.IsSourceOfTruth) { PushLocalSpawnRulesYamlToSync(); } ((BaseUnityPlugin)this).Config.Save(); _lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath); _initialized = true; } catch { Cleanup(); throw; } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { try { if (_initialized) { ConfigPersistence.Save(((BaseUnityPlugin)this).Config); } } finally { Cleanup(); } } private void Cleanup() { _initialized = false; try { if (SpawnRulesYaml != null) { SpawnRulesYaml.ValueChanged -= OnSyncedSpawnRulesYamlChanged; } ConfigSync.SourceOfTruthChanged -= OnSourceOfTruthChanged; try { _harmony.UnpatchSelf(); } finally { TerrainMistilePrefab.ReleasePrefabs(); } } finally { try { _watcher?.Dispose(); } finally { _spawnRulesWatcher?.Dispose(); } } } private void Update() { if (_initialized) { TerrainMistileSystem.UpdateResetEffectRpcRegistration(); TerrainMistileSystem.UpdateProtectedTerrainAreaSync(); TerrainMistileExternalTerrainCompat.Update(); if (TerrainMistileExternalTerrainCompat.ConsumeBiomeMappingRefreshRequest() && _appliedSpawnRulesYamlText != null) { ApplySpawnRulesYaml(_appliedSpawnRulesYamlText, "Expand World Data biome refresh"); } TerrainMistileSystem.UpdatePersistentTerrainSpawns(); } } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, "sighsorry.TerrainMistile.cfg"); _watcher.Changed += ReadConfigValues; _watcher.Created += ReadConfigValues; _watcher.Renamed += ReadConfigValues; _watcher.IncludeSubdirectories = true; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; _spawnRulesWatcher = new FileSystemWatcher(Paths.ConfigPath, "TerrainMistile.yml"); _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 { string b = File.ReadAllText(ConfigFileFullPath); if (string.Equals(_lastConfigFileText, b, StringComparison.Ordinal)) { return; } ConfigPersistence.Save(((BaseUnityPlugin)this).Config, reload: true); _lastConfigFileText = ReadFileTextIfExists(ConfigFileFullPath); 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) { 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 ((!string.Equals(_appliedSpawnRulesYamlText, text, StringComparison.Ordinal) || !string.Equals(SpawnRulesYaml.Value ?? string.Empty, text, StringComparison.Ordinal)) && ApplySpawnRulesYaml(text, "local file") && !string.Equals(SpawnRulesYaml.Value ?? string.Empty, text, StringComparison.Ordinal)) { SpawnRulesYaml.Value = text; } } private void OnSyncedSpawnRulesYamlChanged() { string text = SpawnRulesYaml.Value ?? string.Empty; if (!string.Equals(_appliedSpawnRulesYamlText, text, StringComparison.Ordinal)) { ApplySpawnRulesYaml(text, ConfigSync.IsSourceOfTruth ? "local sync" : "server sync"); } } private void OnSourceOfTruthChanged(bool isSourceOfTruth) { if (isSourceOfTruth) { PushLocalSpawnRulesYamlToSync(); return; } string text = SpawnRulesYaml.Value ?? string.Empty; if (!string.Equals(_appliedSpawnRulesYamlText, text, StringComparison.Ordinal)) { ApplySpawnRulesYaml(text, "server sync"); } } private bool ApplySpawnRulesYaml(string yaml, string source) { TerrainMistileExpandWorldDataBiomeCompat.InvalidateFileMapping(); if (!TerrainMistileSpawnRules.LoadYamlText(yaml, source)) { return false; } _appliedSpawnRulesYamlText = yaml; TerrainMistileSystem.InvalidateSpawnRuleState(); TerrainMistilePrefab.RefreshRegisteredPrefabVisuals(); return true; } private static string? ReadFileTextIfExists(string path) { if (!File.Exists(path)) { return null; } return File.ReadAllText(path); } private void RemoveObsoleteDisplayNameConfig() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition("2 - Display", "Display Name"); ((BaseUnityPlugin)this).Config.Bind<string>(val, string.Empty, (ConfigDescription)null); ((BaseUnityPlugin)this).Config.Remove(val); } 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); } } internal static class TerrainCompAccess { private delegate void SaveTerrainComp(TerrainComp terrainComp, bool paintOnly); private sealed class Bindings { internal readonly FieldInfo Instances = RequireField("s_instances", typeof(List<TerrainComp>), isStatic: true); internal readonly FieldInfo Heightmap = RequireField("m_hmap", typeof(Heightmap)); internal readonly FieldInfo Operations = RequireField("m_operations", typeof(int)); internal readonly FieldInfo ModifiedHeight = RequireField("m_modifiedHeight", typeof(bool[])); internal readonly FieldInfo LevelDelta = RequireField("m_levelDelta", typeof(float[])); internal readonly FieldInfo SmoothDelta = RequireField("m_smoothDelta", typeof(float[])); internal readonly FieldInfo ModifiedPaint = RequireField("m_modifiedPaint", typeof(bool[])); internal readonly FieldInfo PaintMask = RequireField("m_paintMask", typeof(Color[])); internal readonly FieldInfo LastOperationPoint = RequireField("m_lastOpPoint", typeof(Vector3)); internal readonly FieldInfo LastOperationRadius = RequireField("m_lastOpRadius", typeof(float)); internal readonly MethodInfo Save = RequireMethod("Save"); } internal readonly struct ScanData { internal readonly Heightmap Heightmap; internal readonly int VertexWidth; internal readonly int Operations; internal readonly bool[] ModifiedHeight; internal readonly float[] LevelDelta; internal readonly float[] SmoothDelta; internal ScanData(Heightmap heightmap, int vertexWidth, int operations, bool[] modifiedHeight, float[] levelDelta, float[] smoothDelta) { Heightmap = heightmap; VertexWidth = vertexWidth; Operations = operations; ModifiedHeight = modifiedHeight; LevelDelta = levelDelta; SmoothDelta = smoothDelta; } } internal readonly struct ResetData { internal readonly ScanData Scan; internal readonly bool[] ModifiedPaint; internal readonly Color[] PaintMask; internal ResetData(ScanData scan, bool[] modifiedPaint, Color[] paintMask) { Scan = scan; ModifiedPaint = modifiedPaint; PaintMask = paintMask; } } private static FieldRef<List<TerrainComp>> _instances; private static FieldRef<TerrainComp, Heightmap> _heightmap; private static FieldRef<TerrainComp, int> _operations; private static FieldRef<TerrainComp, bool[]> _modifiedHeight; private static FieldRef<TerrainComp, float[]> _levelDelta; private static FieldRef<TerrainComp, float[]> _smoothDelta; private static FieldRef<TerrainComp, bool[]> _modifiedPaint; private static FieldRef<TerrainComp, Color[]> _paintMask; private static FieldRef<TerrainComp, Vector3> _lastOperationPoint; private static FieldRef<TerrainComp, float> _lastOperationRadius; private static SaveTerrainComp _save; private static bool _initialized; internal static List<TerrainComp> Instances => _instances.Invoke(); internal static void Initialize() { if (!_initialized) { Bindings bindings = ResolveBindings(); _instances = AccessTools.StaticFieldRefAccess<List<TerrainComp>>(bindings.Instances); _heightmap = AccessTools.FieldRefAccess<TerrainComp, Heightmap>(bindings.Heightmap); _operations = AccessTools.FieldRefAccess<TerrainComp, int>(bindings.Operations); _modifiedHeight = AccessTools.FieldRefAccess<TerrainComp, bool[]>(bindings.ModifiedHeight); _levelDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>(bindings.LevelDelta); _smoothDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>(bindings.SmoothDelta); _modifiedPaint = AccessTools.FieldRefAccess<TerrainComp, bool[]>(bindings.ModifiedPaint); _paintMask = AccessTools.FieldRefAccess<TerrainComp, Color[]>(bindings.PaintMask); _lastOperationPoint = AccessTools.FieldRefAccess<TerrainComp, Vector3>(bindings.LastOperationPoint); _lastOperationRadius = AccessTools.FieldRefAccess<TerrainComp, float>(bindings.LastOperationRadius); _save = AccessTools.MethodDelegate<SaveTerrainComp>(bindings.Save, (object)null, false); _initialized = true; } } internal static bool TryCaptureScanData(TerrainComp terrainComp, out ScanData data) { Heightmap val = _heightmap.Invoke(terrainComp); bool[] array = _modifiedHeight.Invoke(terrainComp); float[] array2 = _levelDelta.Invoke(terrainComp); float[] array3 = _smoothDelta.Invoke(terrainComp); int num = (Object.op_Implicit((Object)(object)val) ? (val.m_width + 1) : 0); long num2 = (long)num * (long)num; if (!Object.op_Implicit((Object)(object)val) || num <= 0 || num2 > int.MaxValue || array == null || array2 == null || array3 == null || array.Length < num2 || array2.Length < num2 || array3.Length < num2) { data = default(ScanData); return false; } data = new ScanData(val, num, _operations.Invoke(terrainComp), array, array2, array3); return true; } internal static bool TryCaptureResetData(TerrainComp terrainComp, bool includePaint, out ResetData data) { if (!TryCaptureScanData(terrainComp, out var data2)) { data = default(ResetData); return false; } if (!includePaint) { data = new ResetData(data2, Array.Empty<bool>(), Array.Empty<Color>()); return true; } bool[] array = _modifiedPaint.Invoke(terrainComp); Color[] array2 = _paintMask.Invoke(terrainComp); int num = data2.VertexWidth * data2.VertexWidth; if (array == null || array2 == null || array.Length < num || array2.Length < num) { data = default(ResetData); return false; } data = new ResetData(data2, array, array2); return true; } internal static void CommitReset(TerrainComp terrainComp, Vector3 center, float radius, bool resetPaint) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) _operations.Invoke(terrainComp)++; _lastOperationPoint.Invoke(terrainComp) = center; _lastOperationRadius.Invoke(terrainComp) = radius; _save(terrainComp, paintOnly: false); Heightmap val = _heightmap.Invoke(terrainComp); val.Poke(0, false); if (resetPaint) { _paintMask.Invoke(terrainComp) = val.GetPaintMask().GetPixels(); } } private static Bindings ResolveBindings() { return new Bindings(); } private static FieldInfo RequireField(string name, Type fieldType, bool isStatic = false) { FieldInfo fieldInfo = typeof(TerrainComp).GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(TerrainComp).FullName, name); if (fieldInfo.FieldType != fieldType || fieldInfo.IsStatic != isStatic) { throw new InvalidOperationException(typeof(TerrainComp).FullName + "." + name + " no longer matches the expected field contract."); } return fieldInfo; } private static MethodInfo RequireMethod(string name) { MethodInfo methodInfo = typeof(TerrainComp).GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null) ?? throw new MissingMethodException(typeof(TerrainComp).FullName, name); if (methodInfo.IsStatic || methodInfo.ReturnType != typeof(void)) { throw new InvalidOperationException(typeof(TerrainComp).FullName + "." + name + " no longer matches the expected method contract."); } return methodInfo; } } public class TerrainMistileBehaviour : MonoBehaviour { internal const string SelfDestructZdoKey = "TerrainMistileSelfDestruct"; internal const string TerrainSourceZdoKey = "TerrainMistileSource"; internal const string TerrainSourceSetZdoKey = "TerrainMistileSourceSet"; internal const string ResetRadiusZdoKey = "TerrainMistileResetRadius"; 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 const float EnforcerTargetSearchInterval = 1f; private const float EnforcerTargetSearchTimeout = 10f; private Character _character; private MonsterAI _monsterAI; private ZNetView _nview; [SerializeField] private bool _enforcer; private Vector3 _terrainTarget; private float _resetRadius = 8f; private bool _hasTerrainTarget; private bool _selfDestructTriggered; private bool _terrainResetDone; private bool _terrainResetInProgress; private bool _visualColorApplied; private float _nextVisualSyncTime; private bool _enforcerTargetSearchInitialized; private float _nextEnforcerTargetSearchTime; private float _enforcerTargetSearchDeadline; private Vector3 _enforcerSpawnPoint; private readonly List<Material> _ownedVisualMaterials = new List<Material>(); private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) _enforcerSpawnPoint = ((Component)this).transform.position; _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() { if (Object.op_Implicit((Object)(object)_character)) { Character character = _character; character.m_onDeath = (Action)Delegate.Remove(character.m_onDeath, new Action(OnDeath)); } TerrainMistilePrefab.ReleaseVisualMaterials(_ownedVisualMaterials); ReleaseCurrentTerrainTarget(); 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 && (TryLoadTerrainTarget() || TryAcquireEnforcerTerrainTarget())) { MoveTowardTerrainTarget(); } } internal void Initialize(Vector3 terrainOperationPoint, float resetRadius, float health) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) ApplyIdentity(); ConfigureTerrainSeeker(); ApplyHealth(health); SetTerrainTarget(terrainOperationPoint, resetRadius); } internal void ConfigureEnforcer(bool enforcer) { _enforcer = enforcer; } internal void MarkSelfDestruct() { _selfDestructTriggered = true; if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("TerrainMistileSelfDestruct", true); } } private void ApplyIdentity() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_character)) { _character.m_name = (_enforcer ? "$terrainmistile_enforcer_name" : "$terrainmistile_creature_name"); _character.m_faction = (Faction)8; _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); } } private void ApplyVisualColor(Color color, bool syncToZdo) { //IL_0006: 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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) TerrainMistilePrefab.ApplyVisuals(((Component)this).gameObject, color, _ownedVisualMaterials); _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; ZNetView component = ((Component)_monsterAI).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { ((BaseAI)_monsterAI).SetHuntPlayer(false); } ((Behaviour)_monsterAI).enabled = false; } } private void SetTerrainTarget(Vector3 terrainOperationPoint, float resetRadius) { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) ReleaseCurrentTerrainTarget(); _terrainTarget = terrainOperationPoint; _resetRadius = NormalizeResetRadius(resetRadius); _hasTerrainTarget = true; TerrainMistileSystem.ReserveTerrainTarget(_terrainTarget, _resetRadius); ApplyVisualColorForTarget(_terrainTarget); if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid() && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); zDO.Set("TerrainMistileSource", terrainOperationPoint); zDO.Set("TerrainMistileResetRadius", _resetRadius); zDO.Set("TerrainMistileSourceSet", true); } } private void ReleaseCurrentTerrainTarget() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (_hasTerrainTarget) { TerrainMistileSystem.ReleaseTerrainTarget(_terrainTarget); _hasTerrainTarget = false; } } 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; } private bool TryAcquireEnforcerTerrainTarget() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!_enforcer) { return false; } if (!_enforcerTargetSearchInitialized) { _enforcerTargetSearchInitialized = true; _nextEnforcerTargetSearchTime = Time.time; _enforcerTargetSearchDeadline = Time.time + 10f; } if (Time.time < _nextEnforcerTargetSearchTime) { return false; } _nextEnforcerTargetSearchTime = Time.time + 1f; if (TerrainMistileSystem.TryFindEnforcerTerrainTarget(_enforcerSpawnPoint, out var modifiedPoint)) { TerrainMistileBiomeSpawnRule rule = TerrainMistileSpawnRules.GetRule(TerrainMistileSpawnRules.GetBiomeKey(modifiedPoint)); Initialize(modifiedPoint, rule.ResetRadius, rule.Health); return true; } if (Time.time >= _enforcerTargetSearchDeadline) { DestroyWithoutTerrainReset(); } return false; } 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) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) 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); if (!TerrainMistileSystem.IsFinite(terrainTarget)) { terrainTarget = default(Vector3); resetRadius = _resetRadius; return false; } resetRadius = NormalizeResetRadius(zDO.GetFloat("TerrainMistileResetRadius", 0f)); return true; } private float NormalizeResetRadius(float resetRadius) { if (float.IsNaN(resetRadius) || float.IsInfinity(resetRadius)) { return _resetRadius; } return Mathf.Clamp(resetRadius, 0.1f, 64f); } 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0048: 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_0065: Unknown result type (might be due to invalid IL or missing references) if (_terrainResetDone || !Object.op_Implicit((Object)(object)_character) || _character.IsDead() || TryRetargetOrDespawnFromEmptyImpact()) { return; } MarkSelfDestruct(); if (TryResetTerrain()) { 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_0049: 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_0058: 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) TryLoadTerrainTarget(); if (!_hasTerrainTarget) { return false; } if (TerrainMistileSystem.HasModifiedTerrainAround(_terrainTarget, _resetRadius)) { return false; } ReleaseCurrentTerrainTarget(); if (_enforcer ? TerrainMistileSystem.TryFindEnforcerTerrainTarget(_enforcerSpawnPoint, out var modifiedPoint) : TerrainMistileSystem.TryFindReplacementTerrainTarget(((Component)this).transform.position, out modifiedPoint)) { SetTerrainTarget(modifiedPoint, TerrainMistileSystem.GetResetRadiusForPoint(modifiedPoint)); return true; } DestroyWithoutTerrainReset(); return true; } private void DestroyWithoutTerrainReset() { _terrainResetDone = true; ReleaseCurrentTerrainTarget(); 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(); } internal bool TryResetTerrain() { //IL_008c: 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) if (Object.op_Implicit((Object)(object)_nview) && _nview.IsValid()) { if (!_nview.IsOwner()) { return false; } _selfDestructTriggered |= _nview.GetZDO().GetBool("TerrainMistileSelfDestruct", false); } if (_terrainResetDone) { return true; } if (_terrainResetInProgress || !_selfDestructTriggered) { return false; } _terrainResetInProgress = true; try { TryLoadTerrainTarget(); if (!TerrainMistileSystem.ResetTerrainAround(_hasTerrainTarget ? _terrainTarget : ((Component)this).transform.position, _resetRadius, resetPaint: true)) { return false; } _terrainResetDone = true; ReleaseCurrentTerrainTarget(); return true; } catch (Exception ex) { TerrainMistilePlugin.TerrainMistileLogger.LogError((object)("TerrainMistile terrain reset failed: " + ex.Message)); return false; } finally { _terrainResetInProgress = false; } } } [HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")] internal static class TerrainMistileCompendium { private readonly struct VanillaBiomeEntry { internal readonly Biome Biome; internal readonly string EnglishName; internal VanillaBiomeEntry(Biome biome, string englishName) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Biome = biome; EnglishName = englishName; } } private readonly struct BiomeDisplayEntry { internal readonly int BiomeKey; internal readonly string DisplayName; internal BiomeDisplayEntry(int biomeKey, string displayName) { BiomeKey = biomeKey; DisplayName = displayName; } } private readonly struct PrefabDisplayEntry { internal readonly string PrefabName; internal readonly string DisplayName; internal PrefabDisplayEntry(string prefabName, string displayName) { PrefabName = prefabName; DisplayName = displayName; } } private const string PageTopic = "$terrainmistile_compendium_topic"; private const string ExplanationToken = "$terrainmistile_compendium_explanation"; private const string ProtectionHeadingToken = "$terrainmistile_compendium_protection_heading"; private const string RequirementToken = "$terrainmistile_compendium_requirement"; private const string MistileDisabledToken = "$terrainmistile_compendium_mistile_disabled"; private const string ProtectionDisabledToken = "$terrainmistile_compendium_protection_disabled"; private const string OtherBiomesToken = "$terrainmistile_compendium_other_biomes"; private const string PiecesHeadingToken = "$terrainmistile_compendium_pieces_heading"; private const string NoPiecesToken = "$terrainmistile_compendium_no_pieces"; private const float GuidanceCooldown = 60f; private static float _nextGuidanceTime; private static readonly VanillaBiomeEntry[] VanillaBiomes = new VanillaBiomeEntry[9] { new VanillaBiomeEntry((Biome)1, "Meadows"), new VanillaBiomeEntry((Biome)8, "Black Forest"), new VanillaBiomeEntry((Biome)2, "Swamp"), new VanillaBiomeEntry((Biome)4, "Mountain"), new VanillaBiomeEntry((Biome)16, "Plains"), new VanillaBiomeEntry((Biome)512, "Mistlands"), new VanillaBiomeEntry((Biome)32, "Ashlands"), new VanillaBiomeEntry((Biome)64, "Deep North"), new VanillaBiomeEntry((Biome)256, "Ocean") }; private static void Postfix(List<TextInfo> ___m_texts) { AddPage(___m_texts); } internal static void ResetGuidanceState() { _nextGuidanceTime = 0f; } internal static void TryShowGuidance(Vector3 center) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || Time.time < _nextGuidanceTime) { return; } TerrainMistileBiomeSpawnRule rule = TerrainMistileSpawnRules.GetRule(TerrainMistileSpawnRules.GetBiomeKey(center)); if (rule.PlayerBaseValue > 0 && !(rule.BaseCheckRadius <= 0f)) { Vector3 position = ((Component)localPlayer).transform.position; float num = position.x - center.x; float num2 = position.z - center.z; if (!(num * num + num2 * num2 > 4096f)) { string text = ((Localization.instance != null) ? Localization.instance.Localize("$terrainmistile_compendium_topic") : "TerrainMistile"); string text2 = ((Localization.instance != null) ? Localization.instance.Localize("$terrainmistile_message_check_compendium", new string[1] { text }) : ("Check the Compendium: " + text)); ((Character)localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false); _nextGuidanceTime = Time.time + 60f; } } } private static void AddPage(List<TextInfo> texts) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (texts != null) { string localizedTopic = LocalizeOrFallback("$terrainmistile_compendium_topic", "TerrainMistile"); texts.RemoveAll((TextInfo text) => string.Equals(text?.m_topic, "$terrainmistile_compendium_topic", StringComparison.Ordinal) || string.Equals(text?.m_topic, localizedTopic, StringComparison.Ordinal)); texts.Add(new TextInfo(localizedTopic, BuildPageText(localizedTopic))); texts.Sort((TextInfo left, TextInfo right) => string.Compare(left?.m_topic, right?.m_topic, StringComparison.OrdinalIgnoreCase)); } } private static string BuildPageText(string localizedTopic) { StringBuilder stringBuilder = new StringBuilder(4096); stringBuilder.Append(LocalizeOrFallback("$terrainmistile_compendium_explanation", "Protection counts different recognized settlement facility types around each altered terrain point. Multiple copies of the same facility count as one type. " + localizedTopic + " spawning is blocked on protected terrain.", localizedTopic)); stringBuilder.Append("\n\n"); AppendBiomeRules(stringBuilder, localizedTopic); stringBuilder.Append("\n\n"); AppendPlayerBasePrefabs(stringBuilder); return stringBuilder.ToString().TrimEnd(Array.Empty<char>()); } private static void AppendBiomeRules(StringBuilder builder, string localizedTopic) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown builder.Append("<color=#FFD27A><b>").Append(LocalizeOrFallback("$terrainmistile_compendium_protection_heading", "Settlement Protection by Biome")).Append("</b></color>\n\n"); HashSet<int> hashSet = new HashSet<int>(); VanillaBiomeEntry[] vanillaBiomes = VanillaBiomes; for (int i = 0; i < vanillaBiomes.Length; i++) { VanillaBiomeEntry biome = vanillaBiomes[i]; int num = (int)biome.Biome; hashSet.Add(num); AppendBiomeRule(builder, GetLocalizedVanillaBiomeName(biome), TerrainMistileSpawnRules.GetRule(num), localizedTopic); } List<BiomeDisplayEntry> list = new List<BiomeDisplayEntry>(); foreach (int item in TerrainMistileSpawnRules.GetConfiguredBiomeKeysSnapshot()) { if (item != 0 && hashSet.Add(item)) { list.Add(new BiomeDisplayEntry(item, GetLocalizedCustomBiomeName(item))); } } list.Sort(delegate(BiomeDisplayEntry left, BiomeDisplayEntry right) { int num2 = string.Compare(left.DisplayName, right.DisplayName, StringComparison.OrdinalIgnoreCase); if (num2 == 0) { int biomeKey = left.BiomeKey; return biomeKey.CompareTo(right.BiomeKey); } return num2; }); foreach (BiomeDisplayEntry item2 in list) { AppendBiomeRule(builder, item2.DisplayName, TerrainMistileSpawnRules.GetRule(item2.BiomeKey), localizedTopic); } AppendBiomeRule(builder, LocalizeOrFallback("$terrainmistile_compendium_other_biomes", "Other biomes (defaults)"), TerrainMistileSpawnRules.DefaultRule, localizedTopic); } private static void AppendBiomeRule(StringBuilder builder, string biomeName, TerrainMistileBiomeSpawnRule rule, string localizedTopic) { builder.Append("<color=orange><b>").Append(biomeName).Append("</b></color>: "); if (!rule.Enabled) { builder.Append(LocalizeOrFallback("$terrainmistile_compendium_mistile_disabled", localizedTopic + " spawning disabled", localizedTopic)); } else if (rule.PlayerBaseValue <= 0 || rule.BaseCheckRadius <= 0f) { builder.Append(LocalizeOrFallback("$terrainmistile_compendium_protection_disabled", "Settlement protection disabled")); } else { string text = rule.PlayerBaseValue.ToString(CultureInfo.InvariantCulture); string text2 = rule.BaseCheckRadius.ToString("0.##", CultureInfo.InvariantCulture); builder.Append(LocalizeOrFallback("$terrainmistile_compendium_requirement", "Required facility types: " + text + " · Check radius: " + text2 + " m", text, text2)); } builder.Append('\n'); } private static void AppendPlayerBasePrefabs(StringBuilder builder) { List<PrefabDisplayEntry> list = new List<PrefabDisplayEntry>(); foreach (string item in TerrainMistileSpawnRules.GetPlayerBasePrefabNamesSnapshot()) { list.Add(new PrefabDisplayEntry(item, GetPrefabDisplayName(item))); } list.Sort(delegate(PrefabDisplayEntry left, PrefabDisplayEntry right) { int num = string.Compare(left.DisplayName, right.DisplayName, StringComparison.OrdinalIgnoreCase); return (num == 0) ? string.Compare(left.PrefabName, right.PrefabName, StringComparison.OrdinalIgnoreCase) : num; }); Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); foreach (PrefabDisplayEntry item2 in list) { dictionary.TryGetValue(item2.DisplayName, out var value); dictionary[item2.DisplayName] = value + 1; } string text = list.Count.ToString(CultureInfo.InvariantCulture); builder.Append("<color=#FFD27A><b>").Append(LocalizeOrFallback("$terrainmistile_compendium_pieces_heading", "Recognized Settlement Facilities (" + text + ")", text)).Append("</b></color>\n\n"); if (list.Count == 0) { builder.Append(LocalizeOrFallback("$terrainmistile_compendium_no_pieces", "No settlement facilities configured.")).Append('\n'); return; } foreach (PrefabDisplayEntry item3 in list) { builder.Append("- ").Append(item3.DisplayName); if (dictionary[item3.DisplayName] > 1 && !string.Equals(item3.DisplayName, item3.PrefabName, StringComparison.OrdinalIgnoreCase)) { builder.Append(" <color=#999999>[").Append(item3.PrefabName).Append("]</color>"); } builder.Append('\n'); } } private static string GetPrefabDisplayName(string prefabName) { GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefabName) : null); if (!Object.op_Implicit((Object)(object)val)) { val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); } Piece val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Piece>() : null); if (!Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val)) { val2 = val.GetComponentInChildren<Piece>(true); } if (!Object.op_Implicit((Object)(object)val2) || string.IsNullOrWhiteSpace(val2.m_name)) { return prefabName; } return LocalizeOrFallback(val2.m_name, prefabName); } private static string GetLocalizedVanillaBiomeName(VanillaBiomeEntry biome) { //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) return LocalizeOrFallback("$biome_" + ((object)biome.Biome/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(), biome.EnglishName); } private static string GetLocalizedCustomBiomeName(int biomeKey) { string biomeName = TerrainMistileSpawnRules.GetBiomeName(biomeKey); if (string.IsNullOrWhiteSpace(biomeName)) { return biomeKey.ToString(CultureInfo.InvariantCulture); } string fallback = ((biomeName[0] == '$') ? biomeName.Substring(1) : biomeName); return LocalizeOrFallback(biomeName, fallback); } private static string LocalizeOrFallback(string value, string fallback, params string[] words) { if (string.IsNullOrWhiteSpace(value) || Localization.instance == null) { return fallback; } string text = Localization.instance.Localize(value, words).Trim(); if (text.Length == 0) { return fallback; } if (value[0] == '$') { string b = "[" + value.Substring(1) + "]"; if (string.Equals(text, b, StringComparison.Ordinal) || text.IndexOf("MISSING KEY", StringComparison.OrdinalIgnoreCase) >= 0) { return fallback; } } return text; } } 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 ExpandWorldDataLocationYamlTypeName = "ExpandWorldData.LocationYaml"; private const string ExpandWorldDataLocationExtraTypeName = "ExpandWorldData.LocationExtra"; private const string ExpandWorldDataBlueprintManagerTypeName = "ExpandWorldData.BlueprintManager"; private const string ExpandWorldDataBlueprintTypeName = "ExpandWorldData.Blueprint"; private const string ExpandWorldDataTerrainTypeName = "ExpandWorldData.Terrain"; private const string ExpandWorldDataNoBuildManagerTypeName = "ExpandWorldData.NoBuildManager"; private const string ExpandWorldDataBiomeManagerTypeName = "ExpandWorldData.BiomeManager"; private const string BlueprintProtectedSourcePrefix = "Expand World Data blueprint terrain"; private const float PatchRetryInterval = 2f; private const float MissingDependencyRetryInterval = 10f; private const int MaxPatchAttempts = 15; private static readonly Dictionary<string, Type> LoadedTypes = new Dictionary<string, Type>(StringComparer.Ordinal); private static readonly Dictionary<Type, Dictionary<string, FieldInfo?>> FieldsByType = new Dictionary<Type, Dictionary<string, FieldInfo>>(); private static readonly Dictionary<Type, PropertyInfo> SnapshotHasValuesProperties = new Dictionary<Type, PropertyInfo>(); private static ManualLogSource? _logger; private static Harmony? _harmony; private static bool _terrainPatched; private static bool _blueprintTerrainPatched; private static bool _protectionSyncPatched; private static bool _biomeMappingRefreshPatched; private static bool _biomeNamesFromFilePatched; private static bool _biomeSetNamesPatched; private static bool _biomeLoadPatched; private static bool _biomeMappingRefreshRequested; private static bool _expandWorldDataDetected; private static bool _blueprintReflectionResolved; private static int _patchAttempts; private static float _nextPatchAttemptTime; private static MethodInfo? _tryGetLocationYamlMethod; private static MethodInfo? _isBlueprintPrefabMethod; private static MethodInfo? _tryGetBlueprintMethod; public static void Initialize(ManualLogSource logger, Harmony harmony) { _logger = logger; _harmony = harmony; bool flag = TryPatch(); _nextPatchAttemptTime = Time.time + (flag ? 2f : 10f); } public static void Update() { if ((!_terrainPatched || !_blueprintTerrainPatched || !_protectionSyncPatched || !_biomeMappingRefreshPatched) && _patchAttempts < 15 && !(Time.time < _nextPatchAttemptTime)) { bool flag = TryPatch(); _nextPatchAttemptTime = Time.time + (flag ? 2f : 10f); } } internal static bool ConsumeBiomeMappingRefreshRequest() { if (!_biomeMappingRefreshRequested) { return false; } _biomeMappingRefreshRequested = false; return true; } private static bool TryPatch() { if (_harmony == null || _patchAttempts >= 15) { return false; } if (FindLoadedType("ExpandWorldData.BiomeManager") == null) { return false; } if (!_expandWorldDataDetected) { _expandWorldDataDetected = true; _biomeMappingRefreshRequested = true; } _patchAttempts++; TryPatchTerrainHandler(); TryPatchBlueprintTerrainHandler(); TryPatchBlueprintProtectionSync(); TryPatchBiomeMappingRefresh(); return true; } private static void TryPatchTerrainHandler() { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown if (_terrainPatched || _harmony == null) { return; } Type type = FindLoadedType("ExpandWorldData.LocationObjectDataAndSwap"); Type type2 = FindLoadedType("ExpandWorldData.LocationYaml"); 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)) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _terrainPatched = true; ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)"Expand World Data terrain compat initialized."); } } } private static void TryPatchBlueprintProtectionSync() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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)) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _protectionSyncPatched = true; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.m_locationInstances.Count > 0) { SyncBlueprintProtectedAreas(); } ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)"Expand World Data blueprint terrain protection initialized."); } } } private static void TryPatchBlueprintTerrainHandler() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown if (_blueprintTerrainPatched || _harmony == null) { return; } Type type = FindLoadedType("ExpandWorldData.Terrain"); Type type2 = FindLoadedType("ExpandWorldData.Blueprint"); if (type == null || type2 == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "ApplyBlueprint", new Type[5] { type2, typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List<GameObject>) }, (Type[])null); if (!(methodInfo == null)) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(TerrainMistileExternalTerrainCompat), "ApplyBlueprintPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _blueprintTerrainPatched = true; ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)"Expand World Data blueprint terrain snapshot protection initialized."); } } } private static void TryPatchBiomeMappingRefresh() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown if (_biomeMappingRefreshPatched || _harmony == null) { return; } Type type = FindLoadedType("ExpandWorldData.BiomeManager"); if (type == null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(TerrainMistileExternalTerrainCompat), "BiomeMappingChangedPostfix", (Type[])null, (Type[])null); if (methodInfo == null) { return; } HarmonyMethod postfix = new HarmonyMethod(methodInfo); List<string> list = new List<string>(); TryPatchBiomeMappingRefreshMethod(type, "NamesFromFile", Type.EmptyTypes, postfix, ref _biomeNamesFromFilePatched, list); TryPatchBiomeMappingRefreshMethod(type, "SetNames", null, postfix, ref _biomeSetNamesPatched, list); TryPatchBiomeMappingRefreshMethod(type, "Load", new Type[1] { typeof(string) }, postfix, ref _biomeLoadPatched, list); _biomeMappingRefreshPatched = _biomeNamesFromFilePatched && _biomeSetNamesPatched && _biomeLoadPatched; if (_biomeMappingRefreshPatched) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogInfo((object)"Expand World Data biome mapping refresh initialized."); } } else if (_patchAttempts >= 15) { ManualLogSource? logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Expand World Data biome mapping refresh is only partially available. Unavailable methods: " + string.Join(", ", list) + ".")); } } } private static void TryPatchBiomeMappingRefreshMethod(Type biomeManagerType, string methodName, Type[]? parameterTypes, HarmonyMethod postfix, ref bool patched, List<string> unavailableMethods) { if (patched || _harmony == null) { return; } try { MethodInfo methodInfo = ((parameterTypes == null) ? AccessTools.Method(biomeManagerType, methodName, (Type[])null, (Type[])null) : AccessTools.Method(biomeManagerType, methodName, parameterTypes, (Type[])null)); if (methodInfo == null) { unavailableMethods.Add(methodName); return; } _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); patched = true; } catch (Exception ex) { unavailableMethods.Add(methodName + " (" + ex.Message + ")"); } } private static void BiomeMappingChangedPostfix() { _biomeMappingRefreshRequested = true; } internal static Type? FindLoadedType(string fullName) { if (LoadedTypes.TryGetValue(fullName, out Type value)) { return value; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type; try { type = assembly.GetType(fullName, throwOnError: false); } catch { continue; } if (type != null) { LoadedTypes[fullName] = type; return type; } } return null; } private static void HandleTerrainPrefix(Vector3 pos, float radius, bool isBlueprint, object data) { //IL_001d: 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) string text = GetString(data, "prefab"); float terrainRadius = GetTerrainRadius(radius, isBlueprint, data); if (terrainRadius > 0f) { TerrainMistileSystem.RegisterExternalTerrainIgnoreArea(pos, terrainRadius, "Expand World Data location terrain", 10f); } try { if (TryGetLoadedBlueprint(text, out object blueprint) && blueprint != null) { float blueprintProtectionRadius = GetBlueprintProtectionRadius(radius, data, blueprint); TerrainMistileSystem.RegisterProtectedTerrainArea(pos, blueprintProtectionRadius, "Expand World Data blueprint terrain " + text); } } catch (Exception ex) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Expand World Data blueprint terrain protection failed: " + ex.Message)); } } } private static void ApplyBlueprintPrefix(object blueprint, Vector3 position) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { float blueprintSnapshotRadius = GetBlueprintSnapshotRadius(blueprint); if (blueprintSnapshotRadius > 0f) { TerrainMistileSystem.RegisterProtectedTerrainArea(position, blueprintSnapshotRadius + 5f, "Expand World Data blueprint terrain " + GetString(blueprint, "Name")); } } catch (Exception ex) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Expand World Data blueprint terrain snapshot protection failed: " + ex.Message)); } } } private static void BlueprintProtectionSyncPostfix() { SyncBlueprintProtectedAreas(); } private static void SyncBlueprintProtectedAreas() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) ZoneSystem instance = ZoneSystem.instance; if (!Object.op_Implicit((Object)(object)instance) || !EnsureBlueprintReflectionMethods()) { return; } List<TerrainMistileSystem.ProtectedTerrainAreaData> list = new List<TerrainMistileSystem.ProtectedTerrainAreaData>(); try { foreach (LocationInstance value in instance.m_locationInstances.Values) { if (value.m_location == null) { continue; } string prefabName = value.m_location.m_prefabName; if (string.IsNullOrWhiteSpace(prefabName)) { continue; } if (!TryGetLoadedBlueprint(prefabName, out object blueprint)) { return; } if (blueprint != null) { object locationYaml; bool flag = TryGetLocationYaml(value.m_location, out locationYaml); if (!flag && _tryGetLocationYamlMethod == null) { return; } object data = (flag ? locationYaml : null); float blueprintProtectionRadius = GetBlueprintProtectionRadius(value.m_location.m_exteriorRadius, data, blueprint); list.Add(new TerrainMistileSystem.ProtectedTerrainAreaData(value.m_position, blueprintProtectionRadius, "Expand World Data blueprint terrain " + prefabName)); } } } catch (Exception ex) { ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Expand World Data blueprint terrain protection refresh failed: " + ex.Message)); } return; } TerrainMistileSystem.ReplaceProtectedTerrainAreas("Expand World Data blueprint terrain", list); } private static bool TryGetLocationYaml(ZoneLocation location, out object? locationYaml) { locationYaml = null; MethodInfo tryGetLocationYamlMethod = _tryGetLocationYamlMethod; if (tryGetLocationYamlMethod == null) { return false; } object[] array = new object[2] { location, null }; try { bool valueOrDefault = tryGetLocationYamlMethod.Invoke(null, array) as bool? == true; locationYaml = array[1]; return valueOrDefault && locationYaml != null; } catch (Exception ex) { _tryGetLocationYamlMethod = null; ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Expand World Data location lookup failed: " + ex.Message)); } return false; } } private static bool TryGetLoadedBlueprint(string prefab, out object? blueprint) { blueprint = null; if (!EnsureBlueprintReflectionMethods()) { return false; } try { if (_isBlueprintPrefabMethod.Invoke(null, new object[1] { prefab }) as bool? != true) { return true; } object[] array = new object[2] { prefab, null }; if (_tryGetBlueprintMethod.Invoke(null, array) as bool? != true || array[1] == null) { return false; } blueprint = array[1]; return true; } catch (Exception ex) { _isBlueprintPrefabMethod = null; _tryGetBlueprintMethod = null; ManualLogSource? logger = _logger; if (logger != null) { logger.LogWarning((object)("Expand World Data blueprint lookup failed: " + ex.Message)); } return false; } } private static bool EnsureBlueprintReflectionMethods() { if (_blueprintReflectionResolved) { if (_tryGetLocationYamlMethod != null && _isBlueprintPrefabMethod != null) { return _tryGetBlueprintMethod != null; } return false; } Type type = FindLoadedType("ExpandWorldData.LocationExtra"); Type type2 = FindLoadedType("ExpandWorldData.LocationYaml"); Type type3 = FindLoadedType("ExpandWorldData.BlueprintManager"); Type type4 = FindLoadedType("ExpandWorldData.Blueprint"); if (type == null || type2 == null || type3 == null || type4 == null) { return false; } _tryGetLocationYamlMethod = AccessTools.Method(type, "TryGetData", new Type[2] { typeof(ZoneLocation), type2.MakeByRefType() }, (Type[])null); _isBlueprintPrefabMethod = AccessTools.Method(type3, "Has", new Type[1] { typeof(string) }, (Type[])null); _tryGetBlueprintMethod = AccessTools.Method(type3, "TryGet", new Type[2] { typeof(string), type4.MakeByRefType() }, (Type[])null); _blueprintReflectionResolved = true; if (_tryGetLocationYamlMethod != null && _isBlueprintPrefabMethod != null) { return _tryGetBlueprintMethod != null; } return false; } internal static float GetBlueprintProtectionRadius(float exteriorRadius, object? data, object blueprint) { float num = Mathf.Max(exteriorRadius, GetBlueprintSnapshotRadius(blueprint)); if (data != null) { float num2 = Mathf.Max(exteriorRadius, GetFloat(data, "exteriorRadius")); bool isBlueprint = GetSnapshotNodeSpacing(GetField(blueprint, "TerrainHeight")?.GetValue(blueprint)) == 0f; num = Mathf.Max(new float[4] { num, num2, GetTerrainRadius(exteriorRadius, isBlueprint, data), GetNoBuildRadius(data, num2) }); } return num + 5f; } internal static float GetBlueprintSnapshotRadius(object blueprint) { float num = Mathf.Max(GetSnapshotNodeSpacing(GetField(blueprint, "TerrainHeight")?.GetValue(blueprint)), GetSnapshotNodeSpacing(GetField(blueprint, "TerrainPaint")?.GetValue(blueprint))); if (num == 0f) { return 0f; } if (!(GetField(blueprint, "Radius")?.GetValue(blueprint) is float num2) || float.IsNaN(num2) || float.IsInfinity(num2) || num2 < 0f || float.IsInfinity(num2 + num)) { throw new InvalidOperationException("Invalid Expand World Data blueprint terrain radius."); } return num2 + num; } private static float GetSnapshotNodeSpacing(object? snapshot) { if (snapshot == null) { return 0f; } Type type = snapshot.GetType(); if (!SnapshotHasValuesProperties.TryGetValue(type, out PropertyInfo value)) { value = type.GetProperty("HasValues", BindingFlags.Instance | BindingFlags.Public) ?? throw new MissingMemberException(type.FullName, "HasValues"); SnapshotHasValuesProperties[type] = value; } object value2 = value.GetValue(snapshot); if (!(value2 is bool) || !(bool)value2) { return 0f; } float num = GetFloat(snapshot, "DistanceBetweenNodes"); if (float.IsNaN(num) || float.IsInfinity(num) || num <= 0f) { throw new InvalidOperationException("Invalid Expand World Data terrain node spacing."); } return num; } internal 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.Ordinal))); 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) { Type type = data.GetType(); if (!FieldsByType.TryGetValue(type, out Dictionary<string, FieldInfo> value)) { value = new Dictionary<string, FieldInfo>(StringComparer.Ordinal); FieldsByType[type] = value; } if (!value.TryGetValue(fieldName, out var value2)) { value2 = (value[fieldName] = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); } return value2; } } 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 TryGetVanillaBiome(string name, out int biome) { return OriginalBiomes.TryGetValue(name, out biome); } 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; try { MethodInfo methodInfo = _tryGetBiomeMethod; if (methodInfo == null) { Type type = TerrainMistileExternalTerrainCompat.FindLoadedType("ExpandWorldData.BiomeManager"); if (type == null) { return false; } methodInfo = (_tryGetBiomeMethod = type.GetMethod("TryGetBiome", BindingFlags.Static | BindingFlags.Public)); } if (methodInfo == null) { return false; } ParameterInfo[] parameters = methodInfo.GetParameters(); Type type2 = ((parameters.Length == 2) ? parameters[1].ParameterType.GetElementType() : null); if (methodInfo.ReturnType != typeof(bool) || parameters.Length != 2 || parameters[0].ParameterType != typeof(string) || !parameters[1].ParameterType.IsByRef || !parameters[1].IsOut || type2 == null || !type2.IsEnum) { _tryGetBiomeMethod = null; return false; } object[] array = new object[2] { name, Enum.ToObject(type2, 0) }; object obj = methodInfo.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 = ""; try { MethodInfo methodInfo = _tryGetDisplayNameMethod; if (methodInfo == null) { Type type = TerrainMistileExternalTerrainCompat.FindLoadedType("ExpandWorldData.BiomeManager"); if (type == null) { return false; } methodInfo = (_tryGetDisplayNameMethod = type.GetMethod("TryGetDisplayName", BindingFlags.Static | BindingFlags.Public)); } if (methodInfo == null) { return false; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (methodInfo.ReturnType != typeof(bool) || parameters.Length != 2 || !parameters[0].ParameterType.IsEnum || !parameters[1].ParameterType.IsByRef || !parameters[1].IsOut || parameters[1].ParameterType.GetElementType() != typeof(string)) { _tryGetDisplayNameMethod = null; return false; } object[] array = new object[2] { Enum.ToObject(parameters[0].ParameterType, biome), "" }; object obj = methodInfo.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 EnsureFileMappingLoaded() { if (_fileMappingLoaded) { return; } string configPath = Paths.ConfigPath; if (!TryBuildFileMapping(string.IsNullOrWhiteSpace(configPath) ? "" : Path.Combine(configPath, "expand_world"), out Dictionary<string, int> nameToBiome, out Dictionary<int, string> biomeToName, out string error)) { _fileMappingLoaded = true; if (error.Length > 0) { TerrainMistilePlugin.TerrainMistileLogger.LogWarning((object)error); } return; } FileNameToBiome.Clear(); foreach (KeyValuePair<string, int> item in nameToBiome) { FileNameToBiome[item.Key] = item.Value; } FileBiomeToName.Clear(); foreach (KeyValuePair<int, string> item2 in biomeToName) { FileBiomeToName[item2.Key] = item2.Value; } _fileMappingLoaded = true; if (error.Length > 0) { TerrainMistilePlugin.TerrainMistileLogger.LogWarning((object)error); } } internal static void InvalidateFileMapping() { _fileMappingLoaded = false; } internal static bool TryBuildFileMappingForTests(string directory, out Dictionary<string, int> mapping, out string error) { Dictionary<int, string> biomeToName; return TryBuildFileMapping(directory, out mapping, out biomeToName, out error); } private static bool TryBuildFileMapping(string directory, out Dictionary<string, int> nameToBiome, out Dictionary<int, string> biomeToName, out string error) { nameToBiome = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); biomeToName = new Dictionary<int, string>(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); error = ""; foreach (KeyValuePair<string, int> originalBiome in OriginalBiomes) { AddFileBiomeName(originalBiome.Key, originalBiome.Value, hashSet, nameToBiome, biomeToName); } if (!Directory.Exists(directory)) { return true; } string[] files; try { files = Directory.GetFiles(directory, "expand_biomes*.yaml", SearchOption.AllDirectories); } catch (Exception ex) { error = "Failed to enumerate Expand World Data biome files: " + ex.Message; return false; } Array.Sort(files, (string left, string right) => StringComparer.OrdinalIgnoreCase.Compare(right, left)); int nextBiome = 512; string[] array = files; foreach (string text in array) { List<ExpandWorldDataBiomeYaml> list; try { list = ExpandWorldDataBiomeDeserializer.Deserialize<List<ExpandWorldDataBiomeYaml>>(File.ReadAllText(text)); } catch (Exception ex2) { string text2 = "Skipping invalid Expand World Data biome file '" + text + "': " + ex2.Message; error = ((error.Length == 0) ? text2 : (error + Environment.NewLine + text2)); continue; } if (list == null) { continue; } foreach (ExpandWorldDataBiomeYaml item in list) { string text3 = item?.Biome?.Trim() ?? ""; if (text3.Length != 0 && !hashSet.Contains(text3)) { if (!TryGetNextBiome(nextBiome, out nextBiome)) { error = "Expand World Data biome limit was exceeded while assigning '" + text3 + "'."; return false; } AddFileBiomeName(text3, nextBiome, hashSet, nameToBiome, biomeToName); } } } return true; } private static bool TryGetNextBiome(int biome, out int nextBiome) { int num; switch (biome) { case 128: nextBiome = 0; return false; default: num = 2 * biome; break; case int.MinValue: num = 128; break; } uint num2 = (uint)num; nextBiome = (int)num2; return true; } private static void AddFileBiomeName(string name, int biome, HashSet<string> exactBiomeNames, Dictionary<string, int> nameToBiome, Dictionary<int, string> biomeToName) { exactBiomeNames.Add(name); nameToBiome[name] = biome; string text = NormalizeName(name); if (!string.Equals(name, text, StringComparison.OrdinalIgnoreCase) && !exactBiomeNames.Contains(text)) { nameToBiome[text] = biome; } biomeToName[biome] = name; } internal static string NormalizeName(string value) { return value.Trim().Replace(" ", "").Replace("_", "") .Replace("-", ""); } } internal static class TerrainMistileLocalization { private static class GameAccess { internal static readonly FieldRef<Localization> Instance = AccessTools.StaticFieldRefAccess<Localization>(AccessTools.Field(typeof(Localization), "m_instance")); internal static readonly FieldRef<Localization, Dictionary<string, string>> Translations = AccessTools.FieldRefAccess<Localization, Dictionary<string, string>>("m_translations"); internal static readonly FieldRef<Localization, LRUCache<string>> Cache = AccessTools.FieldRefAccess<Localization, LRUCache<string>>("m_cache"); } [HarmonyPatch(typeof(Localization), "SetupLanguage", new Type[] { typeof(string) })] private static class SetupLanguagePatch { private static void Postfix(string language, Dictionary<string, string> ___m_translations, LRUCache<string> ___m_cache) { ApplyLanguage(___m_translations, language); ___m_cache.EvictAll(); } } [HarmonyPatch(typeof(Localization), "LoadLanguages")] private static class LoadLanguagesPatch { private static void Postfix(List<string> __result) { AddLanguages(__result); } } private const string FileExtension = ".yml"; private static readonly string FilePrefix = "TerrainMistile."; private static readonly Dictionary<string, Dictionary<string, string>> Languages = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal); private static readonly char[] InvalidTokenCharacters = " (){}[]+-!?/\\&%,.:-=<>\n".ToCharArray(); private static readonly IDeserializer Deserializer = new DeserializerBuilder().IgnoreFields().Build(); internal static void Load(ManualLogSource logger) { Languages.Clear(); bool num = TryLoadEmbeddedYaml("English", logger); TryLoadEmbeddedYaml("Korean", logger); LoadExternalYamlFiles(logger); if (!num) { logger.LogWarning((object)"Embedded English localization was not found or was invalid. External localization files may still provide a fallback."); } } internal static void ApplyToCurrentLanguage() { Localization val = GameAccess.Instance.Invoke(); if (val != null) { AddLanguages(val.GetLanguages()); ApplyLanguage(GameAccess.Translations.Invoke(val), val.GetSelectedLanguage()); GameAccess.Cache.Invoke(val).EvictAll(); } } private static void AddLanguages(List<string> languages) { foreach (string key in Languages.Keys) { if (!languages.Contains(key)) { languages.Add(key); } } } private static void ApplyLanguage(Dictionary<string, string> target, string language) { Languages.TryGetValue("English", out Dictionary<string, string> value); Languages.TryGetValue(language, out Dictionary<string, string> value2); ApplyTranslations(target, value, value2); } internal static void ApplyTranslations(Dictionary<string, string> target, Dictionary<string, string>? english, Dictionary<string, string>? selected) { if (english != null) { foreach (KeyValuePair<string, string> item in english) { target[item.Key] = item.Value; } } if (selected == null || selected == english) { return; } foreach (KeyValuePair<string, string> item2 in selected) { target[item2.Key] = item2.Value; } } private static bool TryLoadEmbeddedYaml(string language, ManualLogSource logger) { string resourceSuffix = ".Translations.TerrainMistile." + language + ".yml"; Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith(resourceSuffix, StringComparison.Ordinal)); if (text == null) { logger.LogWarning((object)("Embedded localization resource not found: Translations/TerrainMistile." + language + ".yml")); return false; } try { using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { logger.LogWarning((object)("Embedded localization resource could not be opened: " + text)); return false; } using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true); return TryAddYamlTranslations(language, streamReader.ReadToEnd(), "embedded TerrainMistile." + language + ".yml", logger); } catch (Exception ex) { logger.LogWarning((object)("Could not load embedded " + language + " localization: " + ex.Message)); return false; } } private static void LoadExternalYamlFiles(ManualLogSource logger) { string bepInExRootPath = Paths.BepInExRootPath; string[] files; try { files = Directory.GetFiles(bepInExRootPath, FilePrefix + "*.yml", SearchOption.AllDirectories); } catch (Exception ex) { logger.LogWarning((object)("Could not search for TerrainMistile localization files: " + ex.Message)); return; } string[] array = files.OrderBy((string path) => IsInsideDirectory(path, Paths.ConfigPath) ? 1 : 0).ThenBy<string, string>((string path) => path, StringComparer.Ordinal).ToArray(); Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); string[] array2 = array; foreach (string text in array2) { if (!TryGetLanguageFromFileName(text, out string language)) { logger.LogWarning((object)("Ignoring localization file with an invalid name: " + text + ". Expected TerrainMistile.<Language>.yml.")); continue; } string yaml; try { yaml = File.ReadAllText(text, Encoding.UTF8); } catch (Exception ex2) { logger.LogWarning((object)("Could not read " + language + " localization from " + text + ": " + ex2.Message)); continue; } if (dictionary.TryGetValue(language, out var value)) { logger.LogWarning((object)("Loading another " + language + " localization file from " + text + ". Its duplicate tokens override values loaded from " + value + ".")); } if (TryAddYamlTranslations(language, yaml, text, logger)) { dictionary[language] = text; } } } private static bool TryAddYamlTranslations(string language, string yaml, string source, ManualLogSource logger) { if (!TryParseYaml(yaml, out Dictionary<string, string> translations, out string error)) { logger.LogWarning((object)("Could not load " + language + " localization from " + source + ": " + error)); return false; } try { if (!Languages.TryGetValue(language, out Dictionary<string, string> value)) { Languages.Add(language, value = new Dictionary<string, string>(StringComparer.Ordinal)); } foreach (KeyValuePair<string, string> item in translations) { string text = item.Key.TrimStart(new char[1] { '$' }); if (text.Length == 0 || text.IndexOfAny(InvalidTokenCharacters) >= 0) { logger.LogWarning((object)("Ignoring invalid localization token '" + item.Key + "' from " + source + ".")); } else { value[text] = item.Value; } } logger.LogInfo((object)$"Loaded {translations.Count} {language} localization entries from {source}."); return true; } catch (Exception ex) { logger.LogWarning((object)("Could not register " + language + " localization from " + source + ": " + ex.Message)); return false; } } internal static bool TryGetLanguageFromFileName(string path, out string language) { language = string.Empty; string fileName = Path.GetFileName(path); if (!fileName.StartsWith(FilePrefix, StringComparison.Ordinal) || !fileName.EndsWith(".yml", StringComparison.Ordinal)) { return false; } int num = fileName.Length - FilePrefix.Length - ".yml".Length; if (num <= 0) { return false; } language = fileName.Substring(FilePrefix.Length, num); if (language.IndexOf('.') >= 0 || !char.IsUpper(language[0])) { language = string.Empty; return false; } return true; } internal static bool TryParseYaml(string yaml, out Dictionary<string, string> translations, out string error) { translations = new Dictionary<string, string>(StringComparer.Ordinal); error = string.Empty; try { Dictionary<string, string> dictionary = Deserializer.Deserialize<Dictionary<string, string>>(yaml); if (dictionary == null || dictionary.Count == 0) { error = "The localization file is empty."; return false; } foreach (KeyValuePair<string, string> item in dictionary) { string text = item.Key?.Trim() ?? string.Empty; if (text.Length == 0) { error = "Localization keys must not be empty."; return false; } if (item.Value == null) { error = "Localization value for '" + text + "' must not be null."; return false; } if (translations.ContainsKey(text)) { error = "Localization key '" + text + "' is duplicated."; return false; } translations.Add(text, item.Value); } return true; } catch (Exception ex) { error = ex.Message; return false; } } private static bool IsInsideDirectory(string path, string directory) { string text = Path.GetFullPath(directory).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); char directorySeparatorChar = Path.DirectorySeparatorChar; string value = text + directorySeparatorChar; return Path.GetFullPath(path).StartsWith(value, StringComparison.OrdinalIgnoreCase); } } [HarmonyPatch(typeof(ZoneSystem), "SpawnLocation", new Type[] { typeof(ZoneLocation), typeof(int), typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List<GameObject>), typeof(bool) })] 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(ZNetScene), "Destroy", new Type[] { typeof(GameObject) })] internal static class ZNetSceneDestroyPatch { private static void Prefix(GameObject __0) { if (Object.op_Implicit((Object)(object)__0)) { TerrainMistileBehaviour component = __0.GetComponent<TerrainMistileBehaviour>(); if (Object.op_Implicit((Object)(object)component)) { component.TryResetTerrain(); } } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class ZNetShutdownPatch { private static void Postfix() { TerrainMistileSystem.ClearWorldState(); } } internal static class TerrainMistilePrefab { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class RegisterPrefabsPatch { private static void Prefix(ZNetScene __instance, Dictionary<int, GameObject> ___m_namedPrefabs) { RegisterPrefabs(__instance, ___m_namedPrefabs); } } [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] private static class ReleasePrefabsPatch { private static void Prefix(ZNetScene __instance) { if (_registeredScene == __instance) { ReleasePrefabs(); } } } internal const string PrefabName = "TerrainMistile"; internal const string EnforcerPrefabName = "TerrainMistileEnforcer"; private const string SourcePrefabName = "Mistile"; private static ZNetScene? _registeredScene; private static GameObject? _container; private static Dictionary<int, GameObject>? _namedPrefabs; private static GameObject? _registeredPrefab; private static GameObject? _registeredEnforcerPrefab; private static readonly List<Material> RegisteredPrefabVisualMaterials = new List<Material>(); private static readonly List<Material> RegisteredEnforcerPrefabVisualMaterials = new List<Material>(); private static void RegisterPrefabs(ZNetScene scene, Dictionary<int, GameObject> namedPrefabs) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown if (_registeredScene == scene) { return; } ReleasePrefabs(); try { GameObject val = null; foreach (GameObject prefab in scene.m_prefabs) { if (Object.op_Implicit((Object)(object)prefab)) { CheckNameConflict(prefab); if (((Object)prefab).name == "Mistile") { val = prefab; } } } foreach (GameObject nonNetViewPrefab in scene.m_nonNetViewPrefabs) { if (Object.op_Implicit((Object)(object)nonNetViewPrefab)) { CheckNameConflict(nonNetViewPrefab); } } if (!Object.op_Implicit((Object)(object)val) || namedPrefabs.ContainsKey(StringExtensionMethods.GetStableHashCode("TerrainMistile")) || namedPrefabs.ContainsKey(StringExtensionMethods.GetStableHashCode("TerrainMistileEnforcer"))) { throw new InvalidOperationException("Mistile source is missing or a TerrainMistile prefab hash is already registered."); } _registeredScene = scene; _namedPrefabs = namedPrefabs; _container = new GameObject("TerrainMistile prefabs"); _container.SetActive(false); _container.transform.SetParent(((Component)scene).transform, false); _registeredPrefab = CreateTerrainMistilePrefab(val, "TerrainMistile", enforcer: false, RegisteredPrefabVisualMaterials); _registeredEnforcerPrefab = CreateTerrainMistilePrefab(val, "TerrainMistileEnforcer", enforcer: true, RegisteredEnforcerPrefabVisualMaterials); scene.m_prefabs.Add(_registeredPrefab); scene.m_prefabs.Add(_registeredEnforcerPrefab); TerrainMistilePlugin.TerrainMistileLogger.LogInfo((object)"Registered TerrainMistile and TerrainMistileEnforcer prefabs."); } catch (Exception arg) { ReleasePrefabs(); TerrainMistilePlugin.TerrainMistileLogger.LogError((object)$"TerrainMistile prefab registration failed: {arg}"); } } private static void CheckNameConflict(GameObject prefab) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (stableHashCode == StringExtensionMethods.GetStableHashCode("TerrainMistile") || stableHashCode == StringExtensionMethods.GetStableHashCode("TerrainMistileEnforcer")) { throw new InvalidOperationException("Prefab '" + ((Object)prefab).name + "' conflicts with a TerrainMistile prefab hash."); } } internal static void ReleasePrefabs() { RemovePrefab(_registeredPrefab); RemovePrefab(_registeredEnforcerPrefab); _registeredPrefab = null; _registeredEnforcerPrefab = null; _registeredScene = null; _namedPrefabs = null; if (Object.op_Implicit((Object)(object)_container)) { Object.Destroy((Object)(object)_container); } _container = null; ReleaseVisualMaterials(RegisteredPrefabVisualMaterials); ReleaseVisualMaterials(RegisteredEnforcerPrefabVisualMaterials); } private static void RemovePrefab(GameObject? prefab) { if (prefab != null) { if (Object.op_Implicit((Object)(object)_registeredScene)) { _registeredScene.m_prefabs.Remove(prefab); } if (Object.op_Implicit((Object)(object)prefab) && _namedPrefabs != null && _namedPrefabs.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)prefab).name), out GameObject value) && value == prefab) { _namedPrefabs.Remove(StringExtensionMethods.GetStableHashCode(((Object)prefab).name)); } } } private static GameObject CreateTerrainMistilePrefab(GameObject source, string prefabName, bool enforcer, List<Material> registeredVisualMaterials) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(source, _container.transform); ((Object)val).name = prefabName; val.SetActive(true); Character component = val.GetComponent<Character>(); if (Object.op_Implicit((Object)(object)component)) { component.m_faction = (Faction)8; 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 = Array.Empty<GameObject>(); } TerrainMistileBehaviour terrainMistileBehaviour = val.GetComponent<TerrainMistileBehaviour>(); if (!Object.op_Implicit((Object)(object)terrainMistileBehaviour)) { terrainM