using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JG224.ModCore.API; using JG224.RegeneratingWorld.Core; using JG224.RegeneratingWorld.Runtime; using Microsoft.CodeAnalysis; using SoftReferenceableAssets; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("RegeneratingWorld")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("RegeneratingWorld")] [assembly: AssemblyTitle("RegeneratingWorld")] [assembly: AssemblyVersion("0.5.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace JG224.RegeneratingWorld { [BepInPlugin("jg224.RegeneratingWorld", "RegeneratingWorld", "0.5.0")] [BepInDependency("com.jg224.modcore", "0.5.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.RegeneratingWorld"; public const string PluginName = "RegeneratingWorld"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("regeneratingworld"); private readonly List _leases = new List(); private Harmony _harmony; private ICoreServices _core; internal static RegenerationRuntime Runtime { get; private set; } private void Awake() { //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore must initialize first."); } _core = ModCoreApi.Services; SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _leases.Add(_core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.RegeneratingWorld", "RegeneratingWorld", val, 1, (ModuleSide)3, (ModuleRequirement)4, 0uL, 1, 1))); Settings settings = new Settings((BaseUnityPlugin)(object)this); _leases.AddRange(settings.Register(_core)); _leases.Add(_core.Namespaces.Register(ModuleId, (NamespaceKind)1, "jg224.rw.", 1, Array.Empty())); _leases.Add(_core.Namespaces.Register(ModuleId, (NamespaceKind)4, "regeneratingworld", 1, Array.Empty())); Runtime = new RegenerationRuntime(settings, _core, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); }); _leases.Add(_core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action)delegate { Runtime?.Stop(); }, 0)); _leases.Add(_core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action)delegate { Runtime?.Stop(); }, 0)); _harmony = new Harmony("jg224.RegeneratingWorld"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); _core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Server restoration scheduler ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"RegeneratingWorld 0.5.0 loaded. Server settings control regeneration."); } catch (Exception ex) { ICoreServices core = _core; if (core != null) { core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } ((BaseUnityPlugin)this).Logger.LogError((object)("RegeneratingWorld failed safely: " + ex)); Shutdown(); throw; } } private void Update() { Runtime?.Tick(); } private void OnDestroy() { Shutdown(); } private void Shutdown() { Runtime?.Stop(); Runtime = null; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; for (int num = _leases.Count - 1; num >= 0; num--) { _leases[num].Dispose(); } _leases.Clear(); } } internal sealed class Settings { private readonly List _entries = new List(); internal readonly ConfigEntry Enabled; internal readonly ConfigEntry Terrain; internal readonly ConfigEntry Locations; internal readonly ConfigEntry Resources; internal readonly ConfigEntry TerrainDays; internal readonly ConfigEntry LocationDays; internal readonly ConfigEntry ResourceDays; internal readonly ConfigEntry StationRadius; internal readonly ConfigEntry PlayerRadius; internal readonly ConfigEntry ScanSeconds; internal Settings(BaseUnityPlugin plugin) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown ConfigFile val = PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(Paths.ConfigPath, "jg224.RegeneratingWorld.cfg"), true, plugin.Info.Metadata)); Enabled = Add(val.Bind("General", "Enabled", true, "Server-owned master switch. Disabling retains restoration records.")); Terrain = Add(val.Bind("Terrain", "Enabled", true, "Restore unprotected digging, raising, flattening and ground paint.")); Locations = Add(val.Bind("Locations", "Enabled", true, "Restore dungeons, Fuling camps, Dvergr sites and Ashlands fortresses.")); Resources = Add(val.Bind("Resources", "Enabled", true, "Regrow tracked natural vegetation and mined resources.")); TerrainDays = Days(val, "Terrain", "ResetDays", 30f); LocationDays = Days(val, "Locations", "ResetDays", 30f); ResourceDays = Days(val, "Resources", "FallbackResetDays", 30f); StationRadius = Add(val.Bind("Protection", "CraftingStationRadius", 40f, new ConfigDescription("Meters protected around every crafting station, including unloaded stations. Independent of crafting range mods.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 200f), Array.Empty()))); PlayerRadius = Add(val.Bind("Protection", "PlayerSafetyRadius", 100f, new ConfigDescription("Additional meters around a reset area in which online players postpone restoration.", (AcceptableValueBase)(object)new AcceptableValueRange(32f, 500f), Array.Empty()))); ScanSeconds = Add(val.Bind("General", "ScanIntervalSeconds", 60, new ConfigDescription("Time between bounded server scans. Timers use world time, including sleep, and survive saves.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 600), Array.Empty()))); } private ConfigEntry Days(ConfigFile file, string section, string key, float value) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return Add(file.Bind(section, key, value, new ConfigDescription("In-game days before this restoration becomes due.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 1000f), Array.Empty()))); } private ConfigEntry Add(ConfigEntry entry) { _entries.Add((ConfigEntryBase)(object)entry); return entry; } internal IEnumerable Register(ICoreServices core) { foreach (ConfigEntryBase entry in _entries) { yield return core.Configuration.Register(new ConfigSettingDescriptor(Plugin.ModuleId, entry.Definition.Section, entry.Definition.Key, (ConfigScope)2, (Func)(() => Convert.ToString(entry.BoxedValue, CultureInfo.InvariantCulture)), 1)); } } } } namespace JG224.RegeneratingWorld.Runtime { [HarmonyPatch(typeof(Container), "Save")] internal static class LocationChestProtection { internal const string DepositKey = "jg224.rw.chest.deposit.v1"; internal static bool IsSensitive(ZDO zdo, GameObject prefab) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_00a7: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || (Object)(object)prefab == (Object)null) { return true; } Container component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return true; } try { ChestInventoryEntry[] array = Read(zdo.GetString(ZDOVars.s_items, "")); if (array.Length == 0) { return false; } if (zdo.GetBool("jg224.rw.chest.deposit.v1", false)) { return true; } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (DropData drop in component.m_defaultItems.m_drops) { if (!((Object)(object)drop.m_item == (Object)null)) { ItemDrop component2 = drop.m_item.GetComponent(); if ((Object)(object)component2 != (Object)null) { dictionary[((Object)drop.m_item).name] = component2.m_itemData; } } } ChestInventoryEntry[] array2 = array; foreach (ChestInventoryEntry chestInventoryEntry in array2) { if (!dictionary.TryGetValue(chestInventoryEntry.Name, out var value) || chestInventoryEntry.HasPlayerMetadata || chestInventoryEntry.Quality != value.m_quality || chestInventoryEntry.Variant != value.m_variant) { return true; } } return false; } catch { return true; } } private static void Prefix(Container __instance) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown ZNetView val = (((Object)(object)__instance.m_rootObjectOverride != (Object)null) ? __instance.m_rootObjectOverride : ((Component)__instance).GetComponent()); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return; } ZDO zDO = val.GetZDO(); if (zDO.GetLong(ZDOVars.s_creator, 0L) != 0L || !zDO.GetBool(ZDOVars.s_addedDefaultItems, false)) { return; } try { ZPackage val2 = new ZPackage(); __instance.GetInventory().Save(val2); ChestInventoryEntry[] array = Read(val2); if (array.Length == 0) { if (zDO.GetBool("jg224.rw.chest.deposit.v1", false)) { zDO.Set("jg224.rw.chest.deposit.v1", false); } } else if (!zDO.GetBool("jg224.rw.chest.deposit.v1", false) && ChestInventoryCodec.HasAdditions(Read(zDO.GetString(ZDOVars.s_items, "")), array)) { zDO.Set("jg224.rw.chest.deposit.v1", true); } } catch { zDO.Set("jg224.rw.chest.deposit.v1", true); } } private static ChestInventoryEntry[] Read(string encoded) { if (string.IsNullOrEmpty(encoded)) { return Array.Empty(); } if (encoded.Length > 4194304) { throw new FormatException("Inventory payload exceeds limit."); } return ChestInventoryCodec.Decode(Convert.FromBase64String(encoded)); } private static ChestInventoryEntry[] Read(ZPackage package) { return ChestInventoryCodec.Decode(package.GetArray()); } } [HarmonyPatch(typeof(ZDOMan), "CreateNewZDO", new Type[] { typeof(Vector3), typeof(int) })] internal static class LocationCreationCapture { private sealed class Scope : IDisposable { public void Dispose() { _created = null; _transaction = null; _maximum = 0; _staged = null; _recording = false; } } private static List _created; private static string _transaction; private static int _maximum; private static HashSet _staged; private static bool _recording; internal static IDisposable Begin(List created, string transaction, int maximum) { if (_created != null) { throw new InvalidOperationException("Location regeneration cannot be nested."); } _created = created; _transaction = transaction; _maximum = maximum; _staged = new HashSet(); _recording = true; return new Scope(); } internal static bool IsStaged(ZDO zdo) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (zdo != null && _staged != null) { return _staged.Contains(zdo.m_uid); } return false; } internal static void FinishGeneration() { _recording = false; } private static void Postfix(ZDO __result) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (_recording && _created != null && __result != null) { _created.Add(__result); _staged.Add(__result.m_uid); __result.Set("jg224.rw.location.transaction.v1", _transaction); if (_created.Count > _maximum) { throw new InvalidOperationException("Location regeneration exceeded the network object limit."); } } } } internal static class LocationLookup { internal static ZoneLocation Find(IEnumerable locations, int hash) { if (locations == null) { return null; } foreach (ZoneLocation location in locations) { if (location != null && location.m_prefab.IsValid && location.Hash == hash) { return location; } } return null; } } internal sealed class LocationRegenerator { private sealed class PrefabState { private readonly Transform _root; private readonly Vector3 _position; private readonly Quaternion _rotation; private readonly Transform _interior; private readonly Vector3 _interiorPosition; private readonly Quaternion _interiorRotation; private readonly Transform _generator; private readonly Vector3 _generatorPosition; private readonly Dictionary _active = new Dictionary(); private readonly bool _randomDamage; internal PrefabState(GameObject prefab) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) _root = prefab.transform; _position = _root.position; _rotation = _root.rotation; Location component = prefab.GetComponent(); _interior = (((Object)(object)component == (Object)null) ? null : component.m_interiorTransform); _generator = (((Object)(object)component == (Object)null || (Object)(object)component.m_generator == (Object)null) ? null : ((Component)component.m_generator).transform); if ((Object)(object)_interior != (Object)null) { _interiorPosition = _interior.localPosition; _interiorRotation = _interior.localRotation; } if ((Object)(object)_generator != (Object)null) { _generatorPosition = _generator.localPosition; } Transform[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { _active[((Component)val).gameObject] = ((Component)val).gameObject.activeSelf; } RandomSpawn[] componentsInChildren2 = prefab.GetComponentsInChildren(true); foreach (RandomSpawn val2 in componentsInChildren2) { if ((Object)(object)val2.m_OffObject != (Object)null) { _active[val2.m_OffObject] = val2.m_OffObject.activeSelf; } } _randomDamage = WearNTear.m_randomInitialDamage; } internal void Restore() { //IL_0007: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) _root.position = _position; _root.rotation = _rotation; if ((Object)(object)_interior != (Object)null) { _interior.localPosition = _interiorPosition; _interior.localRotation = _interiorRotation; } if ((Object)(object)_generator != (Object)null) { _generator.localPosition = _generatorPosition; } foreach (KeyValuePair item in _active) { if ((Object)(object)item.Key != (Object)null) { item.Key.SetActive(item.Value); } } WearNTear.m_randomInitialDamage = _randomDamage; } } internal const string ClockKey = "jg224.rw.location.clock.v1"; internal const string OwnerKey = "jg224.rw.location.owner.v1"; internal const string TransactionKey = "jg224.rw.location.transaction.v1"; private const int MaximumObjects = 20000; private static readonly MethodInfo SpawnLocationMethod = AccessTools.Method(typeof(ZoneSystem), "SpawnLocation", new Type[7] { typeof(ZoneLocation), typeof(int), typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List), typeof(bool) }, (Type[])null); private static readonly MethodInfo SpawnZoneMethod = AccessTools.Method(typeof(ZoneSystem), "SpawnZone", new Type[3] { typeof(Vector2s), typeof(SpawnMode), typeof(GameObject).MakeByRefType() }, (Type[])null); private static readonly MethodInfo SendDestroyedMethod = AccessTools.Method(typeof(ZDOMan), "SendDestroyed", Type.EmptyTypes, (Type[])null); private readonly Func _isProtected; private readonly Func _isSensitive; private readonly Action, string> _backup; private readonly Action _log; private readonly List _discovered = new List(); private readonly Queue _pending = new Queue(); private readonly HashSet _reportedIncomplete = new HashSet(); private readonly Dictionary _supported = new Dictionary(); private int _scanIndex; private bool _blocked; internal LocationRegenerator(Func isProtected, Func isSensitive, Action, string> backupBeforeMutation, Action log) { _isProtected = isProtected ?? throw new ArgumentNullException("isProtected"); _isSensitive = isSensitive ?? throw new ArgumentNullException("isSensitive"); _backup = backupBeforeMutation ?? throw new ArgumentNullException("backupBeforeMutation"); _log = log ?? throw new ArgumentNullException("log"); if (SpawnLocationMethod == null) { throw new MissingMethodException("Valheim ZoneSystem.SpawnLocation signature changed."); } if (SpawnZoneMethod == null) { throw new MissingMethodException("Valheim ZoneSystem.SpawnZone signature changed."); } if (SendDestroyedMethod == null) { throw new MissingMethodException("Valheim ZDOMan.SendDestroyed signature changed."); } } internal void Tick(double now, double delay) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) if (_blocked || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)ZoneSystem.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || !Finite(now) || !Finite(delay) || delay <= 0.0) { return; } if (_pending.Count == 0) { string prefabName = Utils.GetPrefabName(ZoneSystem.instance.m_locationProxyPrefab); if (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefabName, _discovered, ref _scanIndex)) { return; } foreach (ZDO item in _discovered) { if (item.IsValid()) { _pending.Enqueue(item.m_uid); } } _discovered.Clear(); _scanIndex = 0; } for (int i = 0; i < 32; i++) { if (_pending.Count == 0) { break; } ZDO zDO = ZDOMan.instance.GetZDO(_pending.Dequeue()); if (zDO == null || !zDO.IsValid()) { continue; } ZoneLocation val = FindLocation(zDO.GetInt(ZDOVars.s_location, 0)); if (val == null || !Supports(val)) { continue; } string text = zDO.GetString("jg224.rw.location.transaction.v1", ""); if (!string.IsNullOrEmpty(text)) { if (_reportedIncomplete.Add(zDO.m_uid)) { _log("Location " + val.m_prefab.Name + " is paused after an interrupted transaction (" + text + "). Preserve the world and recovery snapshots before investigating."); } } else { long num = zDO.GetLong("jg224.rw.location.clock.v1", -1L); if (num < 0 || (double)num > now * 1000.0) { Own(zDO); zDO.Set("jg224.rw.location.clock.v1", Milliseconds(now)); } else if (!(now - (double)num / 1000.0 < delay) && TryRegenerate(zDO, val, now)) { break; } } } } private bool Supports(ZoneLocation location) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (_supported.TryGetValue(location.Hash, out var value)) { return value; } string name = location.m_prefab.Name; if (name.IndexOf("StartTemple", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Vendor", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Hildir_camp", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("BogWitch", StringComparison.OrdinalIgnoreCase) >= 0) { return _supported[location.Hash] = false; } location.m_prefab.Load(); try { GameObject asset = location.m_prefab.Asset; Location val = (((Object)(object)asset == (Object)null) ? null : asset.GetComponent()); value = (Object)(object)val != (Object)null && (val.m_hasInterior || (Object)(object)val.m_interiorTransform != (Object)null || (Object)(object)val.m_generator != (Object)null || (Object)(object)asset.GetComponentInChildren(true) != (Object)null); value |= name.StartsWith("GoblinCamp", StringComparison.OrdinalIgnoreCase) || name.StartsWith("FulingVillage", StringComparison.OrdinalIgnoreCase) || name.StartsWith("Dvergr", StringComparison.OrdinalIgnoreCase) || name.StartsWith("Fortress", StringComparison.OrdinalIgnoreCase); _supported[location.Hash] = value; return value; } finally { location.m_prefab.Release(); } } private bool TryRegenerate(ZDO proxy, ZoneLocation location, double now) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) using (ResourceRegenerator.SuppressCapture()) { location.m_prefab.Load(); List list = new List(); try { GameObject asset = location.m_prefab.Asset; if ((Object)(object)asset == (Object)null) { return false; } Vector3 position = proxy.GetPosition(); Quaternion rotation = proxy.GetRotation(); List footprint = BuildFootprint(asset, location, position, rotation); if (!SafeFootprint(footprint)) { return false; } if (!PrepareTerrain(footprint, list)) { return false; } List list2 = FindObjects(footprint); if (list2.Count > 20000 || HasSensitiveObject(list2, footprint)) { return false; } string text = proxy.GetString("jg224.rw.location.owner.v1", ""); if (string.IsNullOrEmpty(text)) { text = ((object)Unsafe.As(ref proxy.m_uid)/*cast due to .constrained prefix*/).ToString(); } string text2 = text + ":" + Milliseconds(now); ZDOID uid = proxy.m_uid; _backup(list2, "location-intent:" + text2); Own(proxy); proxy.Set("jg224.rw.location.transaction.v1", text2); List list3 = new List(); List list4 = new List(); State state = Random.state; int forceSeed = DungeonGenerator.m_forceSeed; PrefabState prefabState = new PrefabState(asset); List list5 = new List(); List> list6 = new List>(); IDisposable disposable = null; bool flag = false; bool flag2 = false; try { CaptureRoomStates(asset, list5, list6); disposable = LocationCreationCapture.Begin(list3, text2, 20000); try { DungeonGenerator.m_forceSeed = int.MinValue; SpawnLocationMethod.Invoke(ZoneSystem.instance, new object[7] { location, proxy.GetInt(ZDOVars.s_seed, 0), position, rotation, (object)(SpawnMode)2, list4, false }); } finally { LocationCreationCapture.FinishGeneration(); } ZDO val = ValidateGenerated(list3, proxy, footprint); if (val == null || !SafeFootprint(footprint)) { throw new InvalidOperationException("Generated location failed its identity or footprint checks."); } list2 = FindObjects(footprint); HashSet createdIds = new HashSet(); foreach (ZDO item in list3) { createdIds.Add(item.m_uid); } list2.RemoveAll((ZDO zdo) => createdIds.Contains(zdo.m_uid)); if (list2.Count > 20000 || HasSensitiveObject(list2, footprint)) { throw new InvalidOperationException("A protected object is inside the generated location footprint."); } List list7 = SelectOldObjects(list2, list3, proxy, text, footprint); ValidateDungeonLayouts(list7, list3); if (!list7.Contains(proxy)) { throw new InvalidOperationException("Original location anchor was not selected."); } foreach (ZDO item2 in list3) { Own(item2); item2.Set("jg224.rw.location.owner.v1", text); item2.Set("jg224.rw.location.transaction.v1", text2); } val.Set("jg224.rw.location.clock.v1", Milliseconds(now)); _backup(list3, "location-created:" + text2); _backup(list7, "location-commit:" + text2); flag2 = true; foreach (ZDO item3 in list7) { Destroy(item3); } FlushDestroyed(); _backup(list3, "location-complete:" + text2); foreach (ZDO item4 in list3) { item4.Set("jg224.rw.location.transaction.v1", ""); } flag = true; _log("Regenerated " + location.m_prefab.Name + ": restored " + list3.Count + " native objects and replaced " + list7.Count + " old objects."); return true; } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex); if (!flag2) { try { foreach (ZDO item5 in list3) { Destroy(item5); } FlushDestroyed(); _backup(Array.Empty(), "location-rollback:" + text2); proxy.Set("jg224.rw.location.transaction.v1", ""); proxy.Set("jg224.rw.location.clock.v1", Milliseconds(now)); } catch (Exception ex4) { _blocked = true; _log("Location rollback is incomplete for " + text2 + ": " + ex4.Message); } } else { _blocked = true; } _log("Location " + location.m_prefab.Name + " regeneration " + (flag2 ? "requires recovery" : "was rolled back") + ": " + ex2.Message); return true; } finally { disposable?.Dispose(); ZNetView.FinishGhostInit(); DungeonGenerator.m_forceSeed = forceSeed; foreach (PrefabState item6 in list5) { item6.Restore(); } prefabState.Restore(); Random.state = state; foreach (SoftReference item7 in list6) { item7.Release(); } foreach (GameObject item8 in list4) { if ((Object)(object)item8 != (Object)null) { Object.Destroy((Object)(object)item8); } } if (!flag && flag2) { _reportedIncomplete.Add(uid); } } } finally { foreach (GameObject item9 in list) { if ((Object)(object)item9 != (Object)null) { Object.Destroy((Object)(object)item9); } } location.m_prefab.Release(); } } } private static bool PrepareTerrain(List footprint, List temporary) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); foreach (Bounds item in footprint) { Bounds current = item; Vector2s zone = ZoneSystem.GetZone(((Bounds)(ref current)).min); Vector2s zone2 = ZoneSystem.GetZone(((Bounds)(ref current)).max); if (zone2.x < zone.x || zone2.y < zone.y || zone2.x - zone.x > 8 || zone2.y - zone.y > 8) { throw new InvalidOperationException("Location terrain footprint exceeds supported bounds."); } for (int i = zone.x; i <= zone2.x; i++) { for (int j = zone.y; j <= zone2.y; j++) { hashSet.Add(new Vector2s(i, j)); } } } bool flag = true; foreach (Vector2s item2 in hashSet) { if (!((Object)(object)Heightmap.FindHeightmap(ZoneSystem.GetZonePos(item2)) != (Object)null)) { object[] array = new object[3] { item2, (object)(SpawnMode)1, null }; bool num = (bool)SpawnZoneMethod.Invoke(ZoneSystem.instance, array); object obj = array[2]; GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null) { temporary.Add(val); } if (!num) { flag = false; } } } if (flag) { Physics.SyncTransforms(); } return flag; } private static void CaptureRoomStates(GameObject prefab, List states, List> held) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); DungeonGenerator[] componentsInChildren = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { SoftReference[] availableRoomPrefabs = componentsInChildren[i].GetAvailableRoomPrefabs(); for (int j = 0; j < availableRoomPrefabs.Length; j++) { SoftReference item = availableRoomPrefabs[j]; if (hashSet.Add(item.m_assetID)) { item.Load(); held.Add(item); if ((Object)(object)item.Asset == (Object)null) { throw new InvalidOperationException("A dungeon room asset could not be loaded."); } states.Add(new PrefabState(item.Asset)); } } } } private ZDO ValidateGenerated(List created, ZDO oldProxy, List footprint) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (created.Count < 2 || created.Count > 20000) { return null; } ZDO val = null; foreach (ZDO item in created) { if (item == null || !item.IsValid() || item.GetPrefab() == 0 || !Finite(item.GetPosition().x) || !Finite(item.GetPosition().y) || !Finite(item.GetPosition().z)) { return null; } if (item.GetPrefab() == oldProxy.GetPrefab() && item.GetInt(ZDOVars.s_location, 0) == oldProxy.GetInt(ZDOVars.s_location, 0)) { if (val != null || Vector3.Distance(item.GetPosition(), oldProxy.GetPosition()) > 0.1f) { return null; } val = item; } if (!Inside(footprint, item.GetPosition())) { footprint.Add(new Bounds(item.GetPosition(), Vector3.one * 4f)); } } return val; } private static void ValidateDungeonLayouts(List removed, List created) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) foreach (ZDO item in created) { byte[] byteArray = item.GetByteArray(ZDOVars.s_roomData, (byte[])null); if (byteArray == null || byteArray.Length == 0) { continue; } foreach (ZDO item2 in removed) { if (item2.GetPrefab() != item.GetPrefab() || Vector3.SqrMagnitude(item2.GetPosition() - item.GetPosition()) > 0.01f) { continue; } byte[] array = item2.GetByteArray(ZDOVars.s_roomData, (byte[])null); if (array == null) { int num = item2.GetInt(ZDOVars.s_rooms, 0); if (num < 0 || num > 10000) { throw new InvalidOperationException("Invalid legacy dungeon room count."); } using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(num); for (int i = 0; i < num; i++) { string text = "room" + i; binaryWriter.Write(item2.GetInt(text, 0)); Vector3 vec = item2.GetVec3(text + "_pos", Vector3.zero); Quaternion quaternion = item2.GetQuaternion(text + "_rot", Quaternion.identity); binaryWriter.Write(vec.x); binaryWriter.Write(vec.y); binaryWriter.Write(vec.z); binaryWriter.Write(quaternion.x); binaryWriter.Write(quaternion.y); binaryWriter.Write(quaternion.z); binaryWriter.Write(quaternion.w); } array = memoryStream.ToArray(); } if (array.Length != byteArray.Length) { throw new InvalidOperationException("Native generation changed the saved dungeon layout; existing rooms were preserved."); } for (int j = 0; j < array.Length; j++) { if (array[j] != byteArray[j]) { throw new InvalidOperationException("Native generation changed the saved dungeon layout; existing rooms were preserved."); } } } } } private List SelectOldObjects(List nearby, List created, ZDO proxy, string token, List footprint) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) Dictionary> dictionary = new Dictionary>(); HashSet hashSet = new HashSet(); foreach (ZDO item in created) { if (!dictionary.TryGetValue(item.GetPrefab(), out var value)) { value = (dictionary[item.GetPrefab()] = new List()); } value.Add(item.GetPosition()); GameObject prefab = ZNetScene.instance.GetPrefab(item.GetPrefab()); if ((Object)(object)prefab == (Object)null) { continue; } CreatureSpawner component = prefab.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_creaturePrefab != (Object)null) { hashSet.Add(StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(component.m_creaturePrefab))); } SpawnArea component2 = prefab.GetComponent(); if (!((Object)(object)component2 != (Object)null)) { continue; } foreach (SpawnData prefab4 in component2.m_prefabs) { if ((Object)(object)prefab4.m_prefab != (Object)null) { hashSet.Add(StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(prefab4.m_prefab))); } } } List list2 = new List(); HashSet hashSet2 = new HashSet(); foreach (ZDO item2 in nearby) { if (!Inside(footprint, item2.GetPosition())) { continue; } bool flag = item2 == proxy || item2.GetString("jg224.rw.location.owner.v1", "") == token || hashSet.Contains(item2.GetPrefab()); GameObject prefab2 = ZNetScene.instance.GetPrefab(item2.GetPrefab()); if ((Object)(object)prefab2 == (Object)null) { throw new InvalidOperationException("An unknown network prefab is inside the location."); } if (!flag && dictionary.TryGetValue(item2.GetPrefab(), out var value2)) { flag = (Object)(object)prefab2.GetComponent() != (Object)null; int num = 0; while (!flag && num < value2.Count) { flag = Vector3.SqrMagnitude(item2.GetPosition() - value2[num]) <= 0.5625f; num++; } } if (flag && hashSet2.Add(item2.m_uid)) { list2.Add(item2); } } for (int i = 0; i < list2.Count; i++) { ZDO zDO = ZDOMan.instance.GetZDO(list2[i].GetConnectionZDOID((ConnectionType)3)); if (zDO != null && zDO.IsValid() && !hashSet2.Contains(zDO.m_uid)) { GameObject prefab3 = ZNetScene.instance.GetPrefab(zDO.GetPrefab()); if ((Object)(object)prefab3 == (Object)null || (Object)(object)prefab3.GetComponent() == (Object)null || _isSensitive(zDO) || _isProtected(zDO.GetPosition(), 2f)) { throw new InvalidOperationException("A linked spawned creature is protected or no longer recognized."); } hashSet2.Add(zDO.m_uid); list2.Add(zDO); } } return list2; } private bool HasSensitiveObject(List nearby, List footprint) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) foreach (ZDO item in nearby) { if (Inside(footprint, item.GetPosition()) && _isSensitive(item)) { return true; } } return false; } private bool SafeFootprint(List footprint) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) foreach (Bounds item in footprint) { Bounds current = item; Func isProtected = _isProtected; Vector3 center = ((Bounds)(ref current)).center; Vector3 extents = ((Bounds)(ref current)).extents; if (isProtected(center, ((Vector3)(ref extents)).magnitude)) { return false; } } return true; } private static List BuildFootprint(GameObject prefab, ZoneLocation location, Vector3 position, Quaternion rotation) { //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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(8f, location.m_exteriorRadius); List list = new List { new Bounds(position, Vector3.one * (num * 2f + 4f)) }; PrefabState prefabState = new PrefabState(prefab); try { Location component = prefab.GetComponent(); Vector3 val = (((Object)(object)component != (Object)null && (Object)(object)component.m_generator != (Object)null) ? ((Component)component.m_generator).transform.localPosition : Vector3.zero); Vector3 val2 = (((Object)(object)component != (Object)null && (Object)(object)component.m_interiorTransform != (Object)null) ? component.m_interiorTransform.localPosition : Vector3.zero); prefab.transform.position = Vector3.zero; prefab.transform.rotation = Quaternion.identity; bool flag = (Object)(object)component != (Object)null && component.m_useCustomInteriorTransform && (Object)(object)component.m_generator != (Object)null && (Object)(object)component.m_interiorTransform != (Object)null; if (flag) { ((Component)component.m_generator).transform.localPosition = Vector3.zero; Vector3 val3 = ZoneSystem.GetZonePos(ZoneSystem.GetZone(position)) + val2 + val - position; Vector3 localPosition = Quaternion.Inverse(rotation) * val3; localPosition.y = val2.y; component.m_interiorTransform.localPosition = localPosition; component.m_interiorTransform.localRotation = Quaternion.Inverse(rotation); } ZNetView[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (ZNetView val4 in componentsInChildren) { Vector3 val5 = position + rotation * ((Component)val4).transform.position; DungeonGenerator component2 = ((Component)val4).GetComponent(); if ((Object)(object)component2 != (Object)null) { Vector3 zonePos = ZoneSystem.GetZonePos(ZoneSystem.GetZone(val5)); zonePos.y = val5.y - (flag ? val.y : 0f); list.Add(new Bounds(zonePos, component2.m_zoneSize + Vector3.one * 4f)); } else if (!Inside(list, val5)) { list.Add(new Bounds(val5, Vector3.one * 4f)); } } return list; } finally { prefabState.Restore(); } } private static List FindObjects(List footprint) { //IL_0027: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00f7: Unknown result type (might be due to invalid IL or missing references) List list = new List(); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); List list2 = new List(); Vector2s val = default(Vector2s); foreach (Bounds item in footprint) { Bounds current = item; Vector2s zone = ZoneSystem.GetZone(((Bounds)(ref current)).min); Vector2s zone2 = ZoneSystem.GetZone(((Bounds)(ref current)).max); if (zone2.x < zone.x || zone2.y < zone.y || zone2.x - zone.x > 32 || zone2.y - zone.y > 32) { throw new InvalidOperationException("Location footprint exceeds supported bounds."); } for (int i = zone.x; i <= zone2.x; i++) { for (int j = zone.y; j <= zone2.y; j++) { ((Vector2s)(ref val))..ctor(i, j); if (!hashSet2.Add(val)) { continue; } list2.Clear(); WorldAccess.FindSectorObjects(val, 0, list2); foreach (ZDO item2 in list2) { if (item2.IsValid() && hashSet.Add(item2.m_uid)) { list.Add(item2); } } } } } return list; } private static bool Inside(List bounds, Vector3 position) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) foreach (Bounds bound in bounds) { Bounds current = bound; if (((Bounds)(ref current)).Contains(position)) { return true; } } return false; } private static ZoneLocation FindLocation(int hash) { return LocationLookup.Find(ZoneSystem.instance.m_locations, hash); } private static void Own(ZDO zdo) { zdo.SetOwner(ZDOMan.GetSessionID()); } private static long Milliseconds(double seconds) { return checked((long)(seconds * 1000.0)); } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } private static void Destroy(ZDO zdo) { if (zdo != null && zdo.IsValid()) { Own(zdo); ZNetView val = ZNetScene.instance.FindInstance(zdo); if ((Object)(object)val != (Object)null) { ZNetScene.instance.Destroy(((Component)val).gameObject); } else { ZDOMan.instance.DestroyZDO(zdo); } } } private static void FlushDestroyed() { SendDestroyedMethod.Invoke(ZDOMan.instance, null); } } internal sealed class RegenerationRuntime { private readonly Settings _settings; private readonly ICoreServices _core; private readonly Action _log; private long _world; private bool _started; private bool _faulted; private double _nextScan; private WorldAccess _access; private TerrainRegenerator _terrain; private ResourceRegenerator _resources; private LocationRegenerator _locations; private ZDOID[] _scan; private int _cursor; internal RegenerationRuntime(Settings settings, ICoreServices core, Action log) { _settings = settings; _core = core; _log = log; } internal void Tick() { //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) if (!WorldAccess.Server) { if (_started) { Stop(); } return; } try { long worldUID = ZNet.instance.GetWorldUID(); if (_started && worldUID != _world) { Stop(); } if (!_started) { _world = worldUID; _started = true; _faulted = false; _access = new WorldAccess(_settings, _core, worldUID, _log); _terrain = new TerrainRegenerator(_access, _log); _resources = new ResourceRegenerator(_access, worldUID, _log, () => !_faulted && _settings.Enabled.Value && _settings.Resources.Value); _locations = new LocationRegenerator(_access.Protected, _access.Sensitive, _access.Backup, _log); _resources.Load(); _core.Modules.SetState(Plugin.ModuleId, (ModuleRuntimeState)2, "World restoration records loaded."); _log("Regeneration records loaded for world " + worldUID + ". Default terrain/location cycle: 30 in-game days."); } if (_faulted || !_settings.Enabled.Value) { return; } double now = WorldAccess.Now; if (_resources.HasPendingWork) { if (_settings.Resources.Value) { _resources.RunPending(now, (double)_settings.ResourceDays.Value * WorldAccess.DaySeconds); } else { _resources.CancelPendingWork(); } return; } if (_scan == null) { if (Time.unscaledTimeAsDouble < _nextScan) { return; } _scan = WorldAccess.Objects.Keys.ToArray(); _cursor = 0; if (_settings.Resources.Value) { _resources.PrepareScan(); } } int num = Math.Min(_scan.Length, _cursor + 128); while (_cursor < num) { ZDO zDO = ZDOMan.instance.GetZDO(_scan[_cursor]); if (zDO != null) { if (_settings.Terrain.Value) { _terrain.Visit(zDO, now, (double)_settings.TerrainDays.Value * WorldAccess.DaySeconds); } if (_settings.Resources.Value) { _resources.Observe(zDO); } } _cursor++; } if (_cursor >= _scan.Length) { _scan = null; _nextScan = Time.unscaledTimeAsDouble + (double)_settings.ScanSeconds.Value; if (_settings.Resources.Value) { _resources.Tick(now, (double)_settings.ResourceDays.Value * WorldAccess.DaySeconds); } if (_settings.Locations.Value) { _locations.Tick(now, (double)_settings.LocationDays.Value * WorldAccess.DaySeconds); } } } catch (Exception ex) { _faulted = true; _core.Modules.SetState(Plugin.ModuleId, (ModuleRuntimeState)5, ex.Message); _log("Regeneration paused to preserve world state: " + ex); } } internal void Stop() { try { if (_started && !_faulted) { _resources?.Save(); } } catch (Exception ex) { _log("Could not save regeneration records: " + ex.Message); } _resources?.Dispose(); _scan = null; _terrain = null; _resources = null; _locations = null; _access = null; _started = false; _nextScan = 0.0; } } internal sealed class ResourceRegenerator : IDisposable { private sealed class CaptureScope : IDisposable { private bool _ended; public void Dispose() { if (!_ended) { _ended = true; _suppression--; } } } internal const string PlantedKey = "jg224.rw.player-planted.v1"; internal const string ResourceKey = "jg224.rw.resource.v1"; private readonly WorldAccess _access; private readonly long _world; private readonly Action _log; private readonly Func _trackingEnabled; private static readonly HashSet Active = new HashSet(); private static readonly HashSet MutationIds = new HashSet(); private static readonly MethodInfo SendDestroyed = AccessTools.Method(typeof(ZDOMan), "SendDestroyed", Type.EmptyTypes, (Type[])null) ?? throw new MissingMethodException("ZDOMan.SendDestroyed"); private static int _suppression; private ZDOMan _manager; private Exception _captureFailure; private bool _scanComplete; private bool _disposed; private bool _limitReported; private int _restoredThisCycle; private readonly Dictionary _records = new Dictionary(StringComparer.Ordinal); private readonly Queue _capacityCandidates = new Queue(); private readonly HashSet _untouchedOriginals = new HashSet(StringComparer.Ordinal); private readonly Dictionary _byId = new Dictionary(); private readonly HashSet _natural = new HashSet(); private readonly Dictionary _plants = new Dictionary(); private readonly Dictionary _rockAreas = new Dictionary(); private readonly Dictionary _byPosition = new Dictionary(StringComparer.Ordinal); private IAtomicStore _store; private bool _dirty; private bool _catalogued; private string[] _pendingScan; private int _pendingCursor; internal bool HasPendingWork => _pendingScan != null; internal ResourceRegenerator(WorldAccess access, long world, Action log, Func trackingEnabled = null) { _access = access; _world = world; _log = log; _trackingEnabled = trackingEnabled ?? ((Func)(() => true)); } internal void Load() { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) _store = _access.OpenStore("resources.bin", 33554432); AtomicStoreRecord val = default(AtomicStoreRecord); string error = default(string); if (_store.TryLoad(ref val, ref error)) { if (val.OwnerId != _world || val.SchemaVersion != 1 || !ResourceRecordCodec.TryDecode(val.Payload, out var records, out error)) { throw new InvalidDataException("Resource ledger rejected: " + error); } foreach (ResourceRecord item in records) { _records.Add(item.Key, item); _byId[new ZDOID(item.UserId, item.ObjectId)] = item; _byPosition[PositionKey(item.Prefab, Position(item))] = item; if (ResourceStateRules.IsUntouchedOriginal(item)) { _capacityCandidates.Enqueue(item.Key); _untouchedOriginals.Add(item.Key); } } if (val.RecoveredFromBackup) { _log("Resource records recovered from bounded backup; pending spawns remain guarded."); } } else if (File.Exists(_store.Path) || File.Exists(_store.Path + ".bak")) { throw new InvalidDataException("Resource ledger could not be loaded: " + error); } Catalog(); _manager = ZDOMan.instance; ZDOMan manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Combine(manager.m_onZDODestroyed, new Action(OnNativeDestroyed)); Active.Add(this); } internal void PrepareScan() { if (_captureFailure != null) { throw new InvalidDataException("Resource capture failed; regeneration is paused.", _captureFailure); } _scanComplete = false; Catalog(); } private void Catalog() { if (_catalogued) { return; } foreach (ZoneVegetation item in ZoneSystem.instance.m_vegetation) { if (Object.op_Implicit((Object)(object)item.m_prefab) && Object.op_Implicit((Object)(object)item.m_prefab.GetComponent())) { _natural.Add(StringExtensionMethods.GetStableHashCode(((Object)item.m_prefab).name)); } } foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { Plant val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val)) { continue; } GameObject[] grownPrefabs = val.m_grownPrefabs; foreach (GameObject val2 in grownPrefabs) { if (Object.op_Implicit((Object)(object)val2) && val.m_growTime > 0f && val.m_growTimeMax >= val.m_growTime) { _plants[StringExtensionMethods.GetStableHashCode(((Object)val2).name)] = val; } } } _catalogued = true; } internal void Observe(ZDO zdo, bool destroying = false) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) if (!_natural.Contains(zdo.GetPrefab())) { return; } PrefabInfo prefabInfo = _access.Info(zdo.GetPrefab()); if (!Object.op_Implicit((Object)(object)prefabInfo.Prefab) || (!prefabInfo.Tree && !prefabInfo.Rock && !Object.op_Implicit((Object)(object)prefabInfo.Pickable) && !Object.op_Implicit((Object)(object)prefabInfo.Prefab.GetComponent())) || prefabInfo.Piece || prefabInfo.Character || prefabInfo.Container || prefabInfo.Item || prefabInfo.Terrain || zdo.GetBool("jg224.rw.player-planted.v1", false) || zdo.GetLong(ZDOVars.s_creator, 0L) != 0L || zdo.GetString("jg224.rw.location.owner.v1", "").Length != 0 || zdo.GetString("jg224.rw.location.transaction.v1", "").Length != 0) { return; } if (_byId.TryGetValue(zdo.m_uid, out var value)) { if (destroying) { _untouchedOriginals.Remove(value.Key); } if (!destroying && ResourceStateRules.CanRetireIntact(value, VerifiedPresence(value))) { RetireIntact(value); } return; } string text = zdo.GetString("jg224.rw.resource.v1", ""); ResourceRecord value3; if (text.Length > 0 && _records.TryGetValue(text, out var value2)) { if (!value2.Pending && ZDOMan.instance.GetZDO(new ZDOID(value2.UserId, value2.ObjectId)) == null && value2.Prefab == zdo.GetPrefab() && PositionKey(value2.Prefab, Position(value2)) == PositionKey(zdo.GetPrefab(), zdo.GetPosition())) { Attach(value2, zdo); } } else if (_byPosition.TryGetValue(PositionKey(zdo.GetPrefab(), zdo.GetPosition()), out value3)) { if (!value3.Pending && ZDOMan.instance.GetZDO(new ZDOID(value3.UserId, value3.ObjectId)) == null) { Attach(value3, zdo); } } else { if (!ResourceStateRules.ShouldTrackObservation(destroying ? ResourcePresence.Missing : Presence(zdo), destroying)) { return; } if (!EnsureCapacity()) { if (!_limitReported) { _limitReported = true; _log("Resource ledger holds 100,000 harvested or protected records after intact-original reclamation; additional depleted resources cannot be tracked until capacity is available. Existing records are preserved."); } return; } Vector3 position = zdo.GetPosition(); Quaternion rotation = zdo.GetRotation(); Vector3 vec = zdo.GetVec3(ZDOVars.s_scaleHash, Vector3.one * zdo.GetFloat(ZDOVars.s_scaleScalarHash, 1f)); text = OriginalKey(((ZDOID)(ref zdo.m_uid)).UserID, ((ZDOID)(ref zdo.m_uid)).ID); ResourceRecord resourceRecord = new ResourceRecord { Key = text, UserId = ((ZDOID)(ref zdo.m_uid)).UserID, ObjectId = ((ZDOID)(ref zdo.m_uid)).ID, Prefab = zdo.GetPrefab(), X = position.x, Y = position.y, Z = position.z, RotX = rotation.x, RotY = rotation.y, RotZ = rotation.z, RotW = rotation.w, ScaleX = vec.x, ScaleY = vec.y, ScaleZ = vec.z, GrowSeconds = GrowthTime(zdo), MissingSince = -1.0 }; _records.Add(text, resourceRecord); _byId[zdo.m_uid] = resourceRecord; _byPosition[PositionKey(resourceRecord.Prefab, position)] = resourceRecord; _dirty = true; } } private ResourcePresence VerifiedPresence(ResourceRecord record) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) if (!_untouchedOriginals.Contains(record.Key)) { return ResourcePresence.Unknown; } ZDO zDO = ZDOMan.instance.GetZDO(new ZDOID(record.UserId, record.ObjectId)); if (zDO == null) { return ResourcePresence.Missing; } if (zDO.GetPrefab() != record.Prefab || zDO.GetString("jg224.rw.resource.v1", "").Length != 0 || Vector3.SqrMagnitude(zDO.GetPosition() - Position(record)) > 0.25f) { return ResourcePresence.Unknown; } return Presence(zDO); } private bool EnsureCapacity() { if (_records.Count < 100000) { return true; } if (!ResourceStateRules.TryTakeIntactCandidate(_records, _capacityCandidates, VerifiedPresence, out var retired)) { return false; } RetireIntact(retired); return true; } private void RetireIntact(ResourceRecord record) { //IL_0036: 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) _records.Remove(record.Key); _untouchedOriginals.Remove(record.Key); _byId.Remove(new ZDOID(record.UserId, record.ObjectId)); _byPosition.Remove(PositionKey(record.Prefab, Position(record))); _dirty = true; _limitReported = false; } private double GrowthTime(ZDO zdo) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!_plants.TryGetValue(zdo.GetPrefab(), out var value)) { return 0.0; } State state = Random.state; try { Random.InitState((int)(((ZDOID)(ref zdo.m_uid)).UserID + ((ZDOID)(ref zdo.m_uid)).ID)); return Mathf.Lerp(value.m_growTime, value.m_growTimeMax, Random.value); } finally { Random.state = state; } } private void Attach(ResourceRecord record, ZDO zdo) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) _untouchedOriginals.Remove(record.Key); _byId.Remove(new ZDOID(record.UserId, record.ObjectId)); record.UserId = ((ZDOID)(ref zdo.m_uid)).UserID; record.ObjectId = ((ZDOID)(ref zdo.m_uid)).ID; record.Pending = false; record.MissingSince = -1.0; _byId[zdo.m_uid] = record; _dirty = true; } internal void Tick(double now, double fallbackDelay) { _scanComplete = true; if (_pendingScan != null) { throw new InvalidOperationException("Resource scan cycles cannot overlap."); } _pendingScan = _records.Keys.ToArray(); _pendingCursor = 0; _restoredThisCycle = 0; RunPending(now, fallbackDelay); } internal void CancelPendingWork() { _pendingScan = null; _scanComplete = false; } internal void RunPending(double now, double fallbackDelay) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) if (_captureFailure != null) { throw new InvalidDataException("Resource capture failed; regeneration is paused.", _captureFailure); } if (_pendingScan == null || !_scanComplete || !WorldAccess.Server) { return; } int num = Math.Min(_pendingScan.Length, _pendingCursor + 256); ZDOID key = default(ZDOID); while (_pendingCursor < num) { if (_records.TryGetValue(_pendingScan[_pendingCursor], out var value)) { ZDO val = ZDOMan.instance.GetZDO(new ZDOID(value.UserId, value.ObjectId)); if (val != null && (val.GetPrefab() != value.Prefab || Vector3.SqrMagnitude(val.GetPosition() - Position(value)) > 0.25f)) { val = null; } if (val == null || (!val.GetBool("jg224.rw.player-planted.v1", false) && !_access.Sensitive(val))) { ResourcePresence resourcePresence = Presence(val); if (resourcePresence != ResourcePresence.Unknown) { if (resourcePresence != ResourcePresence.Intact) { _untouchedOriginals.Remove(value.Key); } if (value.Pending) { ReconcilePending(value, val, resourcePresence); } else { if (ResourceStateRules.ObservePresence(value, resourcePresence, now)) { _dirty = true; } double delaySeconds; if (ResourceStateRules.CanRetireIntact(value, VerifiedPresence(value))) { RetireIntact(value); } else if (resourcePresence != ResourcePresence.Intact && _restoredThisCycle < 8 && ResetRules.TryGetResourceDelaySeconds((value.GrowSeconds > 0.0) ? new double?(value.GrowSeconds) : ((double?)null), fallbackDelay, out delaySeconds) && ResetRules.IsDue(now, value.MissingSince, delaySeconds) && !_access.Protected(Position(value), 8f) && (val == null || !val.HasOwner() || val.IsOwner())) { if (FindReplacements(value, val).Count != 0) { value.Pending = true; _dirty = true; Save(); } else { PrefabInfo prefabInfo = _access.Info(value.Prefab); if (Object.op_Implicit((Object)(object)prefabInfo.Prefab)) { List list = OriginalObjects(value, val, prefabInfo); ZDOID[] array = list.Select((ZDO z) => z.m_uid).ToArray(); if (list.Count != 0) { _access.Backup(list, "resource"); } value.Pending = true; _dirty = true; Save(); ZDO val2 = ZDOMan.instance.CreateNewZDO(Position(value), value.Prefab); val2.SetPrefab(value.Prefab); WorldAccess.Own(val2); val2.Persistent = true; ZNetView component = prefabInfo.Prefab.GetComponent(); val2.Type = component.m_type; val2.Distant = component.m_distant; val2.SetRotation(new Quaternion(value.RotX, value.RotY, value.RotZ, value.RotW)); val2.Set(ZDOVars.s_scaleHash, new Vector3(value.ScaleX, value.ScaleY, value.ScaleZ)); val2.Set("jg224.rw.resource.v1", value.Key); DeleteOriginals(list, array); ((ZDOID)(ref key))..ctor(value.UserId, value.ObjectId); if (!ResourceStateRules.TryCompleteReplacement(value, val2.IsValid() && val2.GetPrefab() == value.Prefab && val2.GetString("jg224.rw.resource.v1", "") == value.Key, array.All((ZDOID id) => ZDOMan.instance.GetZDO(id) == null), ((ZDOID)(ref val2.m_uid)).UserID, ((ZDOID)(ref val2.m_uid)).ID)) { throw new InvalidOperationException("Resource replacement could not be verified; reservation retained."); } ZDOID[] array2 = array; foreach (ZDOID key2 in array2) { _byId.Remove(key2); } _byId.Remove(key); _byId[val2.m_uid] = value; _dirty = true; Save(); _restoredThisCycle++; } } } } } } } _pendingCursor++; } if (_pendingCursor >= _pendingScan.Length) { _pendingScan = null; Save(); if (_restoredThisCycle > 0) { _log("Regrew " + _restoredThisCycle + " natural resources."); } } } private List FindReplacements(ResourceRecord record, ZDO current) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) List list = new List(); WorldAccess.FindSectorObjects(ZoneSystem.GetZone(Position(record)), 1, list); return list.Where((ZDO zdo) => zdo != current && zdo.GetPrefab() == record.Prefab && Vector3.SqrMagnitude(zdo.GetPosition() - Position(record)) < 0.25f).ToList(); } private void ReconcilePending(ResourceRecord record, ZDO current, ResourcePresence presence) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) if (_restoredThisCycle >= 8 || _access.Protected(Position(record), 8f) || (current != null && current.HasOwner() && !current.IsOwner())) { return; } List list = FindReplacements(record, current); bool conflictingIdentity = list.Any((ZDO z) => _access.Sensitive(z) || Presence(z) != ResourcePresence.Intact || (z.GetString("jg224.rw.resource.v1", "").Length > 0 && z.GetString("jg224.rw.resource.v1", "") != record.Key) || z.GetString("jg224.rw.location.owner.v1", "").Length > 0 || z.GetString("jg224.rw.location.transaction.v1", "").Length > 0); ResourceRecoveryAction resourceRecoveryAction = ResourceStateRules.PlanPendingRecovery(_scanComplete, presence, list.Count, conflictingIdentity); switch (resourceRecoveryAction) { case ResourceRecoveryAction.Wait: return; case ResourceRecoveryAction.KeepIntactOriginal: case ResourceRecoveryAction.RetryCreation: record.Pending = false; if (resourceRecoveryAction == ResourceRecoveryAction.KeepIntactOriginal) { record.MissingSince = -1.0; } _dirty = true; Save(); return; } ZDO val = list[0]; List list2 = OriginalObjects(record, current, _access.Info(record.Prefab)); ZDOID[] array = list2.Select((ZDO z) => z.m_uid).ToArray(); if (list2.Count > 0) { _access.Backup(list2, "resource-recovery"); } ZDOID key = default(ZDOID); ((ZDOID)(ref key))..ctor(record.UserId, record.ObjectId); DeleteOriginals(list2, array); if (!ResourceStateRules.TryCompleteReplacement(record, val.IsValid() && val.GetPrefab() == record.Prefab, array.All((ZDOID id) => ZDOMan.instance.GetZDO(id) == null), ((ZDOID)(ref val.m_uid)).UserID, ((ZDOID)(ref val.m_uid)).ID)) { throw new InvalidOperationException("Resource recovery could not verify replacement; reservation retained."); } _byId.Remove(key); _byId[val.m_uid] = record; _dirty = true; Save(); _restoredThisCycle++; } private List OriginalObjects(ResourceRecord record, ZDO current, PrefabInfo info) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (current != null) { list.Add(current); } if (!Object.op_Implicit((Object)(object)info.Prefab)) { return list; } TreeBase component = info.Prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.m_stubPrefab)) { return list; } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)component.m_stubPrefab).name); List list2 = new List(); WorldAccess.FindSectorObjects(ZoneSystem.GetZone(Position(record)), 1, list2); foreach (ZDO item in list2) { if (item.GetPrefab() == stableHashCode && Vector3.SqrMagnitude(item.GetPosition() - Position(record)) < 0.25f && !_access.Sensitive(item)) { if (item.HasOwner() && !item.IsOwner()) { throw new InvalidOperationException("A stump changed ownership during resource restoration."); } list.Add(item); } } return list; } private static void DeleteOriginals(List originals, ZDOID[] originalIds) { //IL_0008: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) ZDOID[] array = originalIds; foreach (ZDOID item in array) { MutationIds.Add(item); } try { foreach (ZDO original in originals) { WorldAccess.Destroy(original); } SendDestroyed.Invoke(ZDOMan.instance, null); if (originalIds.Any((ZDOID id) => ZDOMan.instance.GetZDO(id) != null)) { throw new InvalidOperationException("Native resource deletion did not complete; reservation retained."); } } finally { array = originalIds; foreach (ZDOID item2 in array) { MutationIds.Remove(item2); } } } private ResourcePresence Presence(ZDO zdo) { if (zdo == null) { return ResourcePresence.Missing; } PrefabInfo prefabInfo = _access.Info(zdo.GetPrefab()); if (!Object.op_Implicit((Object)(object)prefabInfo.Prefab)) { return ResourcePresence.Unknown; } if (Object.op_Implicit((Object)(object)prefabInfo.Pickable)) { if (!(prefabInfo.Pickable.m_respawnTimeMinutes <= 0f) || !zdo.GetBool(ZDOVars.s_picked, false)) { return ResourcePresence.Intact; } return ResourcePresence.Depleted; } MineRock5 component = prefabInfo.Prefab.GetComponent(); MineRock component2 = prefabInfo.Prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) && !Object.op_Implicit((Object)(object)component2)) { return ResourcePresence.Intact; } if (!_rockAreas.TryGetValue(zdo.GetPrefab(), out var value)) { value = ((Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component2.m_areaRoot)) ? component2.m_areaRoot : prefabInfo.Prefab).GetComponentsInChildren().Length; _rockAreas.Add(zdo.GetPrefab(), value); } if (value < 1 || value > 10000) { return ResourcePresence.Unknown; } bool depleted; if (Object.op_Implicit((Object)(object)component)) { string text = zdo.GetString(ZDOVars.s_health, ""); if (text.Length == 0) { return ResourcePresence.Intact; } if (text.Length > 53340) { return ResourcePresence.Unknown; } try { if (!NativeRockHealth.TryReadMineRock5(Convert.FromBase64String(text), value, out depleted)) { return ResourcePresence.Unknown; } } catch (FormatException) { return ResourcePresence.Unknown; } } else { float[] array = new float[value]; for (int i = 0; i < value; i++) { array[i] = zdo.GetFloat("Health" + i, 1f); } if (!NativeRockHealth.TryGetDepletion(array, out depleted)) { return ResourcePresence.Unknown; } } if (!depleted) { return ResourcePresence.Intact; } return ResourcePresence.Depleted; } internal void Save() { if (_captureFailure != null) { throw new InvalidDataException("Resource capture failed; records preserved for recovery.", _captureFailure); } if (_dirty && _store != null) { _store.Save(1, _world, ResourceRecordCodec.Encode(_records.Values)); _dirty = false; } } private void OnNativeDestroyed(ZDO zdo) { //IL_0015: 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_00ba: 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_0083: Unknown result type (might be due to invalid IL or missing references) if (_disposed || !WorldAccess.Server || MutationIds.Contains(zdo.m_uid)) { return; } try { if (_suppression > 0) { if (_byId.TryGetValue(zdo.m_uid, out var value)) { _untouchedOriginals.Remove(value.Key); _byId.Remove(zdo.m_uid); _records.Remove(value.Key); _byPosition.Remove(PositionKey(value.Prefab, Position(value))); _dirty = true; } } else if (_trackingEnabled()) { Observe(zdo, destroying: true); if (_byId.TryGetValue(zdo.m_uid, out var value2) && !value2.Pending) { value2.MissingSince = WorldAccess.Now; _dirty = true; } } } catch (Exception error) { CaptureFailure(error); } } private void CaptureFailure(Exception error) { if (_captureFailure == null) { _captureFailure = error; _log("Resource capture failed; automatic restoration will pause: " + error.Message); } } internal static void FlushCaptured() { ResourceRegenerator[] array = Active.ToArray(); foreach (ResourceRegenerator resourceRegenerator in array) { if (resourceRegenerator._captureFailure == null) { try { resourceRegenerator.Save(); } catch (Exception error) { resourceRegenerator.CaptureFailure(error); } } } } internal static IDisposable SuppressCapture() { if (_suppression == 0 && WorldAccess.Server) { SendDestroyed.Invoke(ZDOMan.instance, null); } _suppression++; return new CaptureScope(); } public void Dispose() { if (!_disposed) { _disposed = true; if (_manager != null) { ZDOMan manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Remove(manager.m_onZDODestroyed, new Action(OnNativeDestroyed)); } Active.Remove(this); _pendingScan = null; } } private static Vector3 Position(ResourceRecord record) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(record.X, record.Y, record.Z); } private static string OriginalKey(long userId, uint objectId) { return userId.ToString(CultureInfo.InvariantCulture) + ":" + objectId.ToString(CultureInfo.InvariantCulture); } private static string PositionKey(int prefab, Vector3 position) { return prefab.ToString(CultureInfo.InvariantCulture) + ":" + position.x.ToString("R", CultureInfo.InvariantCulture) + ":" + position.y.ToString("R", CultureInfo.InvariantCulture) + ":" + position.z.ToString("R", CultureInfo.InvariantCulture); } } [HarmonyPatch(typeof(ZDOMan), "RPC_DestroyZDO", new Type[] { typeof(long), typeof(ZPackage) })] internal static class ResourceDestructionCapture { private static Exception Finalizer(Exception __exception) { ResourceRegenerator.FlushCaptured(); return __exception; } } [HarmonyPatch(typeof(Plant), "Grow")] internal static class PlayerPlantOwnership { private static void Prefix(Plant __instance, out long __state) { ZNetView component = ((Component)__instance).GetComponent(); __state = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO().GetLong(ZDOVars.s_creator, 0L) : 0); } private static void Postfix(GameObject __result, long __state) { if (!Object.op_Implicit((Object)(object)__result)) { return; } ZNetView component = __result.GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner()) { component.GetZDO().Set("jg224.rw.player-planted.v1", true); if (__state != 0L) { component.GetZDO().Set(ZDOVars.s_creator, __state); } } } } internal sealed class TerrainRegenerator { private const string Stamp = "jg224.rw.terrain.time"; private const string Fingerprint = "jg224.rw.terrain.hash"; private const string Schema = "jg224.rw.terrain.schema"; private readonly WorldAccess _access; private readonly Action _log; private readonly HashSet _reported = new HashSet(); internal TerrainRegenerator(WorldAccess access, Action log) { _access = access; _log = log; } internal unsafe void Visit(ZDO zdo, double now, double delay) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) PrefabInfo prefabInfo = _access.Info(zdo.GetPrefab()); if ((!prefabInfo.Terrain && (!Object.op_Implicit((Object)(object)prefabInfo.LegacyTerrain) || !prefabInfo.LegacyTerrain.m_playerModifiction || prefabInfo.LegacyTerrain.m_useTerrainCompiler)) || (zdo.HasOwner() && !zdo.IsOwner()) || zdo.GetInt("jg224.rw.terrain.schema", 0) > 1) { return; } if (!prefabInfo.Terrain) { if (!StartOrChanged(zdo, now, 1L)) { float num = Math.Max(prefabInfo.LegacyTerrain.m_levelRadius, Math.Max(prefabInfo.LegacyTerrain.m_smoothRadius, prefabInfo.LegacyTerrain.m_paintRadius)); if (prefabInfo.LegacyTerrain.m_square) { num *= (float)Math.Sqrt(2.0); } if (ResetRules.IsDue(now, zdo.GetFloat("jg224.rw.terrain.time", -1f), delay) && !_access.Protected(zdo.GetPosition(), num)) { _access.Backup((IReadOnlyList)(object)new ZDO[1] { zdo }, "legacy-terrain"); WorldAccess.Destroy(zdo); } } return; } byte[] byteArray = zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null); if (byteArray == null || byteArray.Length == 0 || byteArray.Length > 1782842) { return; } long hash = Hash(byteArray); if (StartOrChanged(zdo, now, hash) || !ResetRules.IsDue(now, zdo.GetFloat("jg224.rw.terrain.time", -1f), delay)) { return; } Vector3 center = zdo.GetPosition(); if (!WorldAccess.Finite(center)) { return; } float scale; Func protectedPoint; if (!TerrainPayload.TryInflate(byteArray, out var raw) || !TerrainData.TryDecode(raw, out var data, out var _)) { if (_reported.Add(zdo.m_uid)) { Action log = _log; ZDOID uid = zdo.m_uid; log("Skipping unsupported/corrupt terrain compiler " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + "."); } } else { if (data.PaintStride != data.Width + 1) { return; } if (!TryGetGeometry(center, data.Width, out scale, out var extent, out var cellMargin)) { if (_reported.Add(zdo.m_uid)) { Action log2 = _log; ZDOID uid = zdo.m_uid; log2("Skipping terrain compiler whose geometry differs from the current zone prefab: " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + "."); } } else if (!_access.PlayersNear(center, extent + cellMargin)) { protectedPoint = _access.PointProtection(center, extent, cellMargin); int num2 = data.ClearWhere((int i) => Allowed(i, data.Width + 1), (int i) => Allowed(i, data.PaintStride)); if (num2 != 0) { byte[] array = Utils.Compress(data.Encode()); _access.Backup((IReadOnlyList)(object)new ZDO[1] { zdo }, "terrain"); WorldAccess.Own(zdo); zdo.Set(ZDOVars.s_TCData, array); zdo.Set("jg224.rw.terrain.hash", Hash(array)); zdo.Set("jg224.rw.terrain.time", (float)now); ZDOMan.instance.ForceSendZDO(zdo.m_uid); Action log3 = _log; string[] obj = new string[5] { "Restored ", num2.ToString(), " unprotected terrain cells at ", null, null }; Vector3 val = center; obj[3] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[4] = "."; log3(string.Concat(obj)); } } } bool Allowed(int index, int stride) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Vector3 arg = center + new Vector3(((float)(index % stride) - (float)data.Width / 2f) * scale, 0f, ((float)(index / stride) - (float)data.Width / 2f) * scale); return !protectedPoint(arg); } } private static bool StartOrChanged(ZDO zdo, double now, long hash) { if (zdo.GetInt("jg224.rw.terrain.schema", 0) == 1 && zdo.GetLong("jg224.rw.terrain.hash", 0L) == hash && zdo.GetFloat("jg224.rw.terrain.time", -1f) >= 0f && (double)zdo.GetFloat("jg224.rw.terrain.time", 0f) <= now) { return false; } WorldAccess.Own(zdo); zdo.Set("jg224.rw.terrain.schema", 1); zdo.Set("jg224.rw.terrain.hash", hash); zdo.Set("jg224.rw.terrain.time", (float)now); return true; } private static long Hash(byte[] bytes) { long num = 1469598103934665603L; foreach (byte b in bytes) { num = (num ^ b) * 1099511628211L; } return num; } private static bool TryGetGeometry(Vector3 center, int width, out float scale, out float extent, out float cellMargin) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) scale = 0f; extent = 0f; cellMargin = 0f; GameObject zonePrefab = ZoneSystem.instance.m_zonePrefab; if (!Object.op_Implicit((Object)(object)zonePrefab)) { return false; } Heightmap componentInChildren = zonePrefab.GetComponentInChildren(); if (!Object.op_Implicit((Object)(object)componentInChildren) || componentInChildren.m_width != width || !WorldAccess.IsFinite(componentInChildren.m_scale) || componentInChildren.m_scale <= 0f) { return false; } scale = componentInChildren.m_scale; Heightmap val = Heightmap.FindHeightmap(center); if (Object.op_Implicit((Object)(object)val) && (val.m_width != width || !WorldAccess.IsFinite(val.m_scale) || Math.Abs(val.m_scale - scale) > Math.Max(0.0001f, scale * 1E-05f) || !WorldAccess.Finite(((Component)val).transform.position) || Math.Abs(((Component)val).transform.position.x - center.x) > 0.001f || Math.Abs(((Component)val).transform.position.z - center.z) > 0.001f)) { return false; } extent = (float)((double)width * (double)scale * Math.Sqrt(0.5)); cellMargin = Math.Max(2f, scale * 1.5f); if (WorldAccess.IsFinite(extent) && WorldAccess.IsFinite(cellMargin)) { return WorldAccess.IsFinite(extent + cellMargin); } return false; } } internal sealed class WorldAccess { internal static readonly FieldInfo ObjectsField = AccessTools.Field(typeof(ZDOMan), "m_objectsByID") ?? throw new MissingFieldException("ZDOMan.m_objectsByID"); private readonly Settings _settings; private readonly ICoreServices _core; private readonly long _world; private readonly Action _log; private readonly Dictionary _prefabs = new Dictionary(); private int _backupSequence; private readonly IAtomicStore _journal; internal static Dictionary Objects => (Dictionary)ObjectsField.GetValue(ZDOMan.instance); internal static double Now => ZNet.instance.GetTimeSeconds(); internal static double DaySeconds { get { if (!Object.op_Implicit((Object)(object)EnvMan.instance)) { return 1200.0; } return Math.Max(1L, EnvMan.instance.m_dayLengthSec); } } internal static bool Server { get { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && ZDOMan.instance != null && Object.op_Implicit((Object)(object)ZNetScene.instance)) { return Object.op_Implicit((Object)(object)ZoneSystem.instance); } return false; } } internal WorldAccess(Settings settings, ICoreServices core, long world, Action log) { _settings = settings; _core = core; _world = world; _log = log; _journal = OpenStore("location-journal.bin", 33554432); AtomicStoreRecord val = default(AtomicStoreRecord); string text = default(string); if (_journal.TryLoad(ref val, ref text)) { if (val.RecoveredFromBackup) { throw new InvalidDataException("Location journal required backup recovery; preserve world and records for inspection before regeneration resumes."); } if (val.SchemaVersion != 1 || val.OwnerId != world || val.Payload.Length < 1) { throw new InvalidDataException("Unsupported location transaction journal."); } using MemoryStream memoryStream = new MemoryStream(val.Payload); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (binaryReader.ReadByte() != 0) { throw new InvalidDataException("An interrupted location transaction needs recovery. Preserve the world and world-" + world + "-location-journal.bin before restarting regeneration."); } if (memoryStream.Position != memoryStream.Length) { throw new InvalidDataException("Invalid completed location journal."); } return; } if (File.Exists(_journal.Path) || File.Exists(_journal.Path + ".bak")) { throw new InvalidDataException("Location journal is unreadable: " + text); } } internal IAtomicStore OpenStore(string name, int maxBytes) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) IAtomicStoreFactory stores = _core.Stores; ModuleId moduleId = Plugin.ModuleId; string text = Path.Combine(Paths.ConfigPath, "RegeneratingWorld"); long world = _world; return stores.Open(moduleId, text, "world-" + world + "-" + name, maxBytes); } internal PrefabInfo Info(int hash) { if (_prefabs.TryGetValue(hash, out var value)) { return value; } GameObject prefab = ZNetScene.instance.GetPrefab(hash); if (!Object.op_Implicit((Object)(object)prefab)) { return new PrefabInfo(); } value = new PrefabInfo { Prefab = prefab, Station = Object.op_Implicit((Object)(object)prefab.GetComponentInChildren(true)), Piece = Object.op_Implicit((Object)(object)prefab.GetComponent()), Player = Object.op_Implicit((Object)(object)prefab.GetComponent()), Character = Object.op_Implicit((Object)(object)prefab.GetComponent()), Container = Object.op_Implicit((Object)(object)prefab.GetComponent()), Tombstone = Object.op_Implicit((Object)(object)prefab.GetComponent()), Item = Object.op_Implicit((Object)(object)prefab.GetComponent()), Terrain = Object.op_Implicit((Object)(object)prefab.GetComponent()), LegacyTerrain = prefab.GetComponent(), Tree = Object.op_Implicit((Object)(object)prefab.GetComponent()), Rock = (Object.op_Implicit((Object)(object)prefab.GetComponent()) || Object.op_Implicit((Object)(object)prefab.GetComponent())), Pickable = prefab.GetComponent() }; _prefabs.Add(hash, value); return value; } internal bool Sensitive(ZDO zdo) { PrefabInfo prefabInfo = Info(zdo.GetPrefab()); if (!Object.op_Implicit((Object)(object)prefabInfo.Prefab) || prefabInfo.Player || prefabInfo.Tombstone || prefabInfo.Item || zdo.GetBool(ZDOVars.s_tamed, false) || zdo.GetBool("jg224.rw.player-planted.v1", false) || zdo.GetLong(ZDOVars.s_creator, 0L) != 0L) { return true; } if (prefabInfo.Container && LocationChestProtection.IsSensitive(zdo, prefabInfo.Prefab)) { return true; } return false; } internal bool PlayersNear(Vector3 position, float radius) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) float radius2 = radius + _settings.PlayerRadius.Value; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (!peer.IsReady() || ((ZDOID)(ref peer.m_characterID)).IsNone()) { return true; } ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID); if (zDO == null) { return true; } if (Horizontal(position, zDO.GetPosition(), radius2) || Horizontal(position, peer.m_refPos, radius2)) { return true; } } if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Horizontal(position, ((Component)Player.m_localPlayer).transform.position, radius2)) { return true; } foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (Horizontal(position, allCharacterZDO.GetPosition(), radius2)) { return true; } } return false; } internal bool Protected(Vector3 position, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!Server || !Finite(position) || !IsFinite(radius) || radius < 0f || PlayersNear(position, radius)) { return true; } List list = new List(); float num = radius + _settings.StationRadius.Value + 8f; FindSectorObjects(ZoneSystem.GetZone(position), Mathf.CeilToInt(num / 64f) + 1, list); foreach (ZDO item in list) { if (!LocationCreationCapture.IsStaged(item)) { Vector3 position2 = item.GetPosition(); if (Info(item.GetPrefab()).Station && ResetRules.IsWithinObjectProtection(craftingStation: true, position.x, position.y, position.z, position2.x, position2.y, position2.z, radius, _settings.StationRadius.Value)) { return true; } if (ResetRules.IsWithinObjectProtection(craftingStation: false, position.x, position.y, position.z, position2.x, position2.y, position2.z, radius, _settings.StationRadius.Value) && Sensitive(item)) { return true; } } } return false; } internal Func PointProtection(Vector3 center, float extent, float cellMargin = 2f) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) cellMargin = Math.Max(2f, cellMargin); List list = new List(); FindSectorObjects(ZoneSystem.GetZone(center), Mathf.CeilToInt((extent + _settings.StationRadius.Value + 8f + cellMargin) / 64f) + 1, list); List> circles = new List>(); foreach (ZDO item in list) { if (Info(item.GetPrefab()).Station) { circles.Add(Tuple.Create(item.GetPosition(), _settings.StationRadius.Value + cellMargin)); } else if (Sensitive(item)) { circles.Add(Tuple.Create(item.GetPosition(), 8f + cellMargin)); } } return (Vector3 point) => circles.Any((Tuple circle) => Horizontal(point, circle.Item1, circle.Item2)); } internal static void FindSectorObjects(Vector2s sector, int radius, List objects) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (radius < 0) { throw new ArgumentOutOfRangeException("radius"); } ZDOMan.instance.FindSectorObjects(sector, new SimulationDistance(radius, 0, true), objects, (List)null); } internal static bool Horizontal(Vector3 a, Vector3 b, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return ResetRules.IsProtectedHorizontal(a.x, a.z, b.x, b.z, radius); } internal static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } internal static bool Finite(Vector3 p) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(p.x) && IsFinite(p.y)) { return IsFinite(p.z); } return false; } internal static void Own(ZDO zdo) { if (!Server) { throw new InvalidOperationException("World mutation requires server authority."); } zdo.SetOwner(ZDOMan.GetSessionID()); } internal static void Destroy(ZDO zdo) { Own(zdo); ZDOMan.instance.DestroyZDO(zdo); } internal void Backup(IReadOnlyList objects, string reason) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown if (!Server) { throw new InvalidOperationException("World backup requires server authority."); } if (reason.StartsWith("location-complete:", StringComparison.Ordinal) || reason.StartsWith("location-rollback:", StringComparison.Ordinal)) { _journal.Save(1, _world, new byte[1]); return; } IAtomicStore val = OpenStore("backup-" + _backupSequence++ % 16 + ".bin", 33554432); using (MemoryStream memoryStream = new MemoryStream()) { using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1); binaryWriter.Write(reason); binaryWriter.Write(Now); binaryWriter.Write(objects.Count); foreach (ZDO @object in objects) { binaryWriter.Write(((ZDOID)(ref @object.m_uid)).UserID); binaryWriter.Write(((ZDOID)(ref @object.m_uid)).ID); Vector3 position = @object.GetPosition(); binaryWriter.Write(position.x); binaryWriter.Write(position.y); binaryWriter.Write(position.z); ZPackage val2 = new ZPackage(); @object.Serialize(val2); byte[] array = val2.GetArray(); binaryWriter.Write(array.Length); binaryWriter.Write(array); if (memoryStream.Length > 33554432) { throw new InvalidDataException("Restoration backup exceeds safe bound."); } } byte[] array2 = memoryStream.ToArray(); val.Save(1, _world, array2); if (reason.StartsWith("location-", StringComparison.Ordinal)) { byte[] array3 = new byte[array2.Length + 1]; array3[0] = 1; Buffer.BlockCopy(array2, 0, array3, 1, array2.Length); _journal.Save(1, _world, array3); } } _log("Saved restoration backup " + Path.GetFileName(val.Path) + " (" + objects.Count + " objects, " + reason + ")."); } } internal sealed class PrefabInfo { internal GameObject Prefab; internal bool Station; internal bool Piece; internal bool Player; internal bool Character; internal bool Container; internal bool Tombstone; internal bool Item; internal bool Terrain; internal bool Tree; internal bool Rock; internal TerrainModifier LegacyTerrain; internal Pickable Pickable; } } namespace JG224.RegeneratingWorld.Core { internal static class ChestInventoryCodec { internal const int MaximumBytes = 3145728; internal const int MaximumItems = 1000; internal static ChestInventoryEntry[] Decode(byte[] bytes) { if (bytes == null || bytes.Length < 8 || bytes.Length > 3145728) { throw new InvalidDataException("Inventory payload exceeds supported bounds."); } using MemoryStream memoryStream = new MemoryStream(bytes, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true)); int num = binaryReader.ReadInt32(); int num2 = binaryReader.ReadInt32(); if (num < 100 || num > 106 || num2 < 0 || num2 > 1000) { throw new InvalidDataException("Unsupported inventory format."); } ChestInventoryEntry[] array = new ChestInventoryEntry[num2]; for (int i = 0; i < num2; i++) { ChestInventoryEntry chestInventoryEntry = new ChestInventoryEntry { Name = Text(binaryReader, 512), Stack = binaryReader.ReadInt32() }; if (chestInventoryEntry.Name.Length == 0 || chestInventoryEntry.Stack < 1 || chestInventoryEntry.Stack > 1000000) { throw new InvalidDataException("Invalid inventory item."); } string name = chestInventoryEntry.Name; for (int j = 0; j < name.Length; j++) { if (char.IsControl(name[j])) { throw new InvalidDataException("Invalid item name."); } } float f = binaryReader.ReadSingle(); if (float.IsNaN(f) || float.IsInfinity(f)) { throw new InvalidDataException("Invalid item durability."); } binaryReader.ReadInt32(); binaryReader.ReadInt32(); chestInventoryEntry.Equipped = Boolean(binaryReader); chestInventoryEntry.Quality = ((num < 101) ? 1 : binaryReader.ReadInt32()); chestInventoryEntry.Variant = ((num >= 102) ? binaryReader.ReadInt32() : 0); if (chestInventoryEntry.Quality < 1 || chestInventoryEntry.Quality > 1000 || chestInventoryEntry.Variant < 0 || chestInventoryEntry.Variant > 1000) { throw new InvalidDataException("Invalid item quality or variant."); } if (num >= 103) { chestInventoryEntry.Crafter = binaryReader.ReadInt64(); chestInventoryEntry.CrafterNamed = Text(binaryReader, 1024).Length != 0; } if (num >= 104) { int num3 = binaryReader.ReadInt32(); if (num3 < 0 || num3 > 1024) { throw new InvalidDataException("Invalid custom item data count."); } chestInventoryEntry.Custom = num3 != 0; for (int k = 0; k < num3; k++) { Text(binaryReader, 4096); Text(binaryReader, 65536); } } if (num >= 105) { int num4 = binaryReader.ReadInt32(); if (num4 < 0 || num4 > 255) { throw new InvalidDataException("Invalid item world level."); } } if (num >= 106) { chestInventoryEntry.PickedUp = Boolean(binaryReader); } array[i] = chestInventoryEntry; } if (memoryStream.Position != memoryStream.Length) { throw new InvalidDataException("Trailing inventory data."); } return array; } internal static bool HasAdditions(IReadOnlyList previous, IReadOnlyList current) { if (previous == null || current == null) { throw new ArgumentNullException("Inventory records are required."); } Dictionary dictionary = Counts(previous); foreach (KeyValuePair item in Counts(current)) { dictionary.TryGetValue(item.Key, out var value); if (item.Value > value) { return true; } } return false; } private static Dictionary Counts(IReadOnlyList entries) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ChestInventoryEntry entry in entries) { if (entry == null || string.IsNullOrEmpty(entry.Name) || entry.Stack <= 0) { throw new InvalidDataException("Invalid inventory summary."); } string key = entry.Name + "\n" + entry.Quality + "\n" + entry.Variant + "\n" + entry.Crafter; dictionary.TryGetValue(key, out var value); dictionary[key] = checked(value + entry.Stack); } return dictionary; } private static string Text(BinaryReader reader, int maximum) { string text = reader.ReadString(); if (text.Length > maximum) { throw new InvalidDataException("Inventory text exceeds supported bounds."); } return text; } private static bool Boolean(BinaryReader reader) { byte num = reader.ReadByte(); if (num > 1) { throw new InvalidDataException("Noncanonical inventory flag."); } return num == 1; } } internal sealed class ChestInventoryEntry { internal string Name; internal int Stack; internal int Quality; internal int Variant; internal long Crafter; internal bool CrafterNamed; internal bool Custom; internal bool Equipped; internal bool PickedUp; internal bool HasPlayerMetadata { get { if (Crafter == 0L && !CrafterNamed && !Custom && !Equipped) { return PickedUp; } return true; } } } public static class ResetRules { public static bool IsDue(double now, double last, double delay) { if (IsFinite(now) && IsFinite(last) && IsFinite(delay) && now >= 0.0 && last >= 0.0 && delay >= 0.0 && now >= last) { return now - last >= delay; } return false; } public static bool IsProtectedHorizontal(double x, double z, double stationX, double stationZ, double radius) { if (!IsFinite(x) || !IsFinite(z) || !IsFinite(stationX) || !IsFinite(stationZ) || !IsFinite(radius) || radius < 0.0) { return true; } double num = Math.Abs(x - stationX); double num2 = Math.Abs(z - stationZ); if (num > radius || num2 > radius) { return false; } if (radius == 0.0) { return true; } num /= radius; num2 /= radius; return num * num + num2 * num2 <= 1.0; } public static bool IsProtectedSphere(double x, double y, double z, double centreX, double centreY, double centreZ, double radius) { if (!IsFinite(x) || !IsFinite(y) || !IsFinite(z) || !IsFinite(centreX) || !IsFinite(centreY) || !IsFinite(centreZ) || !IsFinite(radius) || radius < 0.0) { return true; } double num = Math.Abs(x - centreX); double num2 = Math.Abs(y - centreY); double num3 = Math.Abs(z - centreZ); if (num > radius || num2 > radius || num3 > radius) { return false; } if (radius == 0.0) { return true; } num /= radius; num2 /= radius; num3 /= radius; return num * num + num2 * num2 + num3 * num3 <= 1.0; } public static bool IsWithinObjectProtection(bool craftingStation, double x, double y, double z, double objectX, double objectY, double objectZ, double areaRadius, double stationRadius) { if (!IsFinite(areaRadius) || areaRadius < 0.0 || (craftingStation && (!IsFinite(stationRadius) || stationRadius < 0.0))) { return true; } if (craftingStation) { return IsProtectedHorizontal(x, z, objectX, objectZ, areaRadius + stationRadius); } return IsProtectedSphere(x, y, z, objectX, objectY, objectZ, areaRadius + 8.0); } public static bool TryGetResourceDelaySeconds(double? plantedGrowTimeSeconds, double fallbackDelaySeconds, out double delaySeconds) { delaySeconds = 0.0; if (plantedGrowTimeSeconds.HasValue) { double value = plantedGrowTimeSeconds.Value; if (!IsFinite(value) || value <= 0.0 || value > 5.992310449541053E+307) { return false; } delaySeconds = value * 3.0; return true; } if (!IsFinite(fallbackDelaySeconds) || fallbackDelaySeconds <= 0.0) { return false; } delaySeconds = fallbackDelaySeconds; return true; } private static bool IsFinite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public sealed class ResourceRecord { public string Key { get; set; } public long UserId { get; set; } public uint ObjectId { get; set; } public int Prefab { get; set; } public float X { get; set; } public float Y { get; set; } public float Z { get; set; } public float RotX { get; set; } public float RotY { get; set; } public float RotZ { get; set; } public float RotW { get; set; } = 1f; public float ScaleX { get; set; } = 1f; public float ScaleY { get; set; } = 1f; public float ScaleZ { get; set; } = 1f; public double MissingSince { get; set; } = -1.0; public double GrowSeconds { get; set; } public bool Pending { get; set; } } public static class ResourceRecordCodec { public const uint Magic = 1381451602u; public const int SchemaVersion = 1; public const int MaximumRecords = 100000; public const int MaximumKeyLength = 96; public const int MaximumEncodedLength = 33554432; private const int MinimumRecordLength = 75; public static bool IsValid(ResourceRecord record, out string error) { return Validate(record, out error); } public static byte[] Encode(IEnumerable records) { if (records == null) { throw new ArgumentNullException("records"); } List list = new List(); HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (ResourceRecord record in records) { if (list.Count >= 100000) { throw new ArgumentException("Resource ledger exceeds the record limit.", "records"); } if (!Validate(record, out var error)) { throw new ArgumentException(error, "records"); } if (!hashSet.Add(record.Key)) { throw new ArgumentException("Resource ledger contains duplicate keys.", "records"); } list.Add(Copy(record)); } list.Sort((ResourceRecord left, ResourceRecord right) => StringComparer.Ordinal.Compare(left.Key, right.Key)); using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1381451602u); binaryWriter.Write(1); binaryWriter.Write(list.Count); foreach (ResourceRecord item in list) { binaryWriter.Write((byte)item.Key.Length); binaryWriter.Write(Encoding.ASCII.GetBytes(item.Key)); binaryWriter.Write(item.UserId); binaryWriter.Write(item.ObjectId); binaryWriter.Write(item.Prefab); binaryWriter.Write(item.X); binaryWriter.Write(item.Y); binaryWriter.Write(item.Z); binaryWriter.Write(item.RotX); binaryWriter.Write(item.RotY); binaryWriter.Write(item.RotZ); binaryWriter.Write(item.RotW); binaryWriter.Write(item.ScaleX); binaryWriter.Write(item.ScaleY); binaryWriter.Write(item.ScaleZ); binaryWriter.Write(item.MissingSince); binaryWriter.Write(item.GrowSeconds); binaryWriter.Write(item.Pending); } binaryWriter.Flush(); if (memoryStream.Length > 33554432) { throw new ArgumentException("Resource ledger exceeds the payload limit.", "records"); } return memoryStream.ToArray(); } public static bool TryDecode(byte[] raw, out List records, out string error) { records = null; error = string.Empty; if (raw == null || raw.Length < 12 || raw.Length > 33554432) { return Fail("Resource ledger length is outside supported bounds.", out error); } try { using MemoryStream memoryStream = new MemoryStream(raw, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (binaryReader.ReadUInt32() != 1381451602) { return Fail("Resource ledger magic does not match.", out error); } if (binaryReader.ReadInt32() != 1) { return Fail("Unsupported resource ledger schema version.", out error); } int num = binaryReader.ReadInt32(); if (num < 0 || num > 100000 || num > (memoryStream.Length - memoryStream.Position) / 75) { return Fail("Resource ledger record count is invalid or truncated.", out error); } List list = new List(num); HashSet hashSet = new HashSet(StringComparer.Ordinal); for (int i = 0; i < num; i++) { int num2 = binaryReader.ReadByte(); if (num2 < 1 || num2 > 96) { return Fail("Resource ledger key length is invalid.", out error); } byte[] array = binaryReader.ReadBytes(num2); if (array.Length != num2) { return Fail("Truncated resource ledger key.", out error); } for (int j = 0; j < array.Length; j++) { if (array[j] > 127) { return Fail("Resource ledger key is not a supported stable token.", out error); } } ResourceRecord resourceRecord = new ResourceRecord { Key = Encoding.ASCII.GetString(array), UserId = binaryReader.ReadInt64(), ObjectId = binaryReader.ReadUInt32(), Prefab = binaryReader.ReadInt32(), X = binaryReader.ReadSingle(), Y = binaryReader.ReadSingle(), Z = binaryReader.ReadSingle(), RotX = binaryReader.ReadSingle(), RotY = binaryReader.ReadSingle(), RotZ = binaryReader.ReadSingle(), RotW = binaryReader.ReadSingle(), ScaleX = binaryReader.ReadSingle(), ScaleY = binaryReader.ReadSingle(), ScaleZ = binaryReader.ReadSingle(), MissingSince = binaryReader.ReadDouble(), GrowSeconds = binaryReader.ReadDouble() }; byte b = binaryReader.ReadByte(); if (b > 1) { return Fail("Resource pending state is not a canonical boolean.", out error); } resourceRecord.Pending = b == 1; if (!Validate(resourceRecord, out error)) { return false; } if (!hashSet.Add(resourceRecord.Key)) { return Fail("Resource ledger contains duplicate keys.", out error); } list.Add(resourceRecord); } if (memoryStream.Position != memoryStream.Length) { return Fail("Unexpected trailing resource ledger data.", out error); } records = list; return true; } catch (EndOfStreamException) { return Fail("Truncated resource ledger payload.", out error); } } private static bool Validate(ResourceRecord record, out string error) { error = string.Empty; if (record == null) { return Fail("Resource ledger contains a null record.", out error); } if (record.Prefab == 0) { return Fail("Resource ledger prefab identity is missing.", out error); } if (record.UserId == 0L && record.ObjectId == 0) { return Fail("Resource ledger contains an empty network object identity.", out error); } if (string.IsNullOrEmpty(record.Key) || record.Key.Length > 96) { return Fail("Resource ledger key length is invalid.", out error); } string key = record.Key; foreach (char c in key) { if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_' && c != '-' && c != '.' && c != ':') { return Fail("Resource ledger key is not a supported stable token.", out error); } } if (!InRange(record.X, -20000f, 20000f) || !InRange(record.Z, -20000f, 20000f) || !InRange(record.Y, -5000f, 20000f)) { return Fail("Resource position is outside supported world bounds.", out error); } if (!IsFinite(record.RotX) || !IsFinite(record.RotY) || !IsFinite(record.RotZ) || !IsFinite(record.RotW)) { return Fail("Resource rotation contains a nonfinite value.", out error); } double num = (double)record.RotX * (double)record.RotX + (double)record.RotY * (double)record.RotY + (double)record.RotZ * (double)record.RotZ + (double)record.RotW * (double)record.RotW; if (num < 0.98 || num > 1.02) { return Fail("Resource rotation is not a normalized quaternion.", out error); } if (!ValidScale(record.ScaleX) || !ValidScale(record.ScaleY) || !ValidScale(record.ScaleZ)) { return Fail("Resource scale is outside supported bounds.", out error); } if (!IsFinite(record.MissingSince) || (record.MissingSince != -1.0 && record.MissingSince < 0.0)) { return Fail("Resource missing timestamp is invalid.", out error); } if (!IsFinite(record.GrowSeconds) || record.GrowSeconds < 0.0) { return Fail("Resource growth time is invalid.", out error); } return true; } private static ResourceRecord Copy(ResourceRecord entry) { return new ResourceRecord { Key = entry.Key, UserId = entry.UserId, ObjectId = entry.ObjectId, Prefab = entry.Prefab, X = entry.X, Y = entry.Y, Z = entry.Z, RotX = entry.RotX, RotY = entry.RotY, RotZ = entry.RotZ, RotW = entry.RotW, ScaleX = entry.ScaleX, ScaleY = entry.ScaleY, ScaleZ = entry.ScaleZ, MissingSince = entry.MissingSince, GrowSeconds = entry.GrowSeconds, Pending = entry.Pending }; } private static bool ValidScale(float value) { if (IsFinite(value) && value > 0f) { return value <= 100f; } return false; } private static bool InRange(float value, float minimum, float maximum) { if (IsFinite(value) && value >= minimum) { return value <= maximum; } return false; } private static bool IsFinite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } private static bool Fail(string message, out string error) { error = message; return false; } } public enum ResourcePresence { Unknown, Missing, Intact, Depleted } public enum ResourceRecoveryAction { Wait, KeepIntactOriginal, AdoptReplacement, RetryCreation } public static class ResourceStateRules { public static bool ShouldTrackObservation(ResourcePresence presence, bool destroying) { if (!destroying) { return presence == ResourcePresence.Depleted; } return true; } public static bool CanRetireIntact(ResourceRecord record, ResourcePresence verifiedPresence) { if (IsUntouchedOriginal(record)) { return verifiedPresence == ResourcePresence.Intact; } return false; } public static bool IsUntouchedOriginal(ResourceRecord record) { if (record != null && !record.Pending && record.MissingSince == -1.0) { return record.Key == record.UserId.ToString(CultureInfo.InvariantCulture) + ":" + record.ObjectId.ToString(CultureInfo.InvariantCulture); } return false; } public static bool TryTakeIntactCandidate(IDictionary records, Queue candidates, Func verify, out ResourceRecord retired) { retired = null; while (candidates.Count > 0) { string key = candidates.Dequeue(); if (records.TryGetValue(key, out var value) && !value.Pending && CanRetireIntact(value, verify(value))) { retired = value; return true; } } return false; } public static ResourceRecoveryAction PlanPendingRecovery(bool fullWorldScanComplete, ResourcePresence original, int matchingReplacements, bool conflictingIdentity) { if (!fullWorldScanComplete || conflictingIdentity || matchingReplacements < 0 || matchingReplacements > 1 || original == ResourcePresence.Unknown || !Enum.IsDefined(typeof(ResourcePresence), original)) { return ResourceRecoveryAction.Wait; } if (matchingReplacements == 1) { return ResourceRecoveryAction.AdoptReplacement; } if (original != ResourcePresence.Intact) { return ResourceRecoveryAction.RetryCreation; } return ResourceRecoveryAction.KeepIntactOriginal; } public static bool ObservePresence(ResourceRecord record, ResourcePresence presence, double now) { if (record == null || record.Pending || !Finite(now) || now < 0.0 || presence == ResourcePresence.Unknown || !Enum.IsDefined(typeof(ResourcePresence), presence)) { return false; } double num = ((presence == ResourcePresence.Intact) ? (-1.0) : ((!Finite(record.MissingSince) || record.MissingSince < 0.0 || record.MissingSince > now) ? now : record.MissingSince)); if (num == record.MissingSince) { return false; } record.MissingSince = num; return true; } public static bool TryCompleteReplacement(ResourceRecord record, bool replacementIdentityVerified, bool allOriginalIdsRemoved, long replacementUserId, uint replacementObjectId) { if (record == null || !record.Pending || !replacementIdentityVerified || !allOriginalIdsRemoved || (replacementUserId == 0L && replacementObjectId == 0)) { return false; } record.UserId = replacementUserId; record.ObjectId = replacementObjectId; record.Pending = false; record.MissingSince = -1.0; return true; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public static class NativeRockHealth { public const int MaximumAreas = 10000; public const int MaximumPayloadLength = 40004; public static bool TryGetDepletion(float[] health, out bool depleted) { depleted = false; if (health == null || health.Length == 0 || health.Length > 10000) { return false; } bool flag = false; foreach (float num in health) { if (float.IsNaN(num) || float.IsInfinity(num)) { return false; } if (num <= 0f) { flag = true; } } depleted = flag; return true; } public static bool TryReadMineRock5(byte[] raw, int expectedAreas, out bool depleted) { depleted = false; if (raw == null || expectedAreas < 1 || expectedAreas > 10000 || raw.Length != 4 + expectedAreas * 4 || raw.Length > 40004) { return false; } using MemoryStream input = new MemoryStream(raw, writable: false); using BinaryReader binaryReader = new BinaryReader(input); if (binaryReader.ReadInt32() != expectedAreas) { return false; } float[] array = new float[expectedAreas]; for (int i = 0; i < array.Length; i++) { array[i] = binaryReader.ReadSingle(); } return TryGetDepletion(array, out depleted); } } public sealed class TerrainData { public const int SupportedVersion = 1; public const int MaximumCellCount = 66049; public const int MaximumEncodedLength = 1717306; private readonly TerrainHeight[] _heights; private readonly TerrainPaint[] _paint; public int Width { get; } public int HeightCount => _heights.Length; public int PaintCount => _paint.Length; public int PaintStride { get; } public int Operations { get; } public float LastOperationX { get; } public float LastOperationY { get; } public float LastOperationZ { get; } public float LastOperationRadius { get; } public bool HasModifications { get { for (int i = 0; i < _heights.Length; i++) { if (_heights[i].Modified) { return true; } } for (int j = 0; j < _paint.Length; j++) { if (_paint[j].Modified) { return true; } } return false; } } private TerrainData(int operations, float lastX, float lastY, float lastZ, float lastRadius, TerrainHeight[] heights, TerrainPaint[] paint, int heightStride, int paintStride) { Operations = operations; LastOperationX = lastX; LastOperationY = lastY; LastOperationZ = lastZ; LastOperationRadius = lastRadius; _heights = heights; _paint = paint; Width = heightStride - 1; PaintStride = paintStride; } public bool IsHeightModified(int index) { return _heights[index].Modified; } public bool IsPaintModified(int index) { return _paint[index].Modified; } public TerrainHeight GetHeight(int index) { return _heights[index]; } public TerrainPaint GetPaint(int index) { return _paint[index]; } public static bool TryDecode(byte[] raw, out TerrainData data, out string error) { data = null; error = string.Empty; if (raw == null || raw.Length < 32 || raw.Length > 1717306) { return Fail("Terrain payload length is outside supported bounds.", out error); } try { using MemoryStream memoryStream = new MemoryStream(raw, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (binaryReader.ReadInt32() != 1) { return Fail("Unsupported terrain schema version.", out error); } int operations = binaryReader.ReadInt32(); float lastX = ReadFinite(binaryReader); float lastY = ReadFinite(binaryReader); float lastZ = ReadFinite(binaryReader); float num = ReadFinite(binaryReader); if (num < 0f) { return Fail("Terrain operation radius cannot be negative.", out error); } int num2 = binaryReader.ReadInt32(); if (!TryGetSquareStride(num2, out var stride) || stride < 2) { return Fail("Unsupported terrain height grid dimensions.", out error); } if (memoryStream.Length - memoryStream.Position < (long)num2 + 4L) { return Fail("Truncated terrain height grid.", out error); } TerrainHeight[] array = new TerrainHeight[num2]; for (int i = 0; i < array.Length; i++) { if (ReadFlag(binaryReader)) { array[i] = new TerrainHeight(modified: true, ReadFinite(binaryReader), ReadFinite(binaryReader)); } } int num3 = binaryReader.ReadInt32(); int num4 = stride - 1; if ((num3 != num2 && num3 != num4 * num4) || !TryGetSquareStride(num3, out var stride2)) { return Fail("Unsupported terrain paint grid dimensions.", out error); } if (memoryStream.Length - memoryStream.Position < num3) { return Fail("Truncated terrain paint grid.", out error); } TerrainPaint[] array2 = new TerrainPaint[num3]; for (int j = 0; j < array2.Length; j++) { if (ReadFlag(binaryReader)) { array2[j] = new TerrainPaint(modified: true, ReadFinite(binaryReader), ReadFinite(binaryReader), ReadFinite(binaryReader), ReadFinite(binaryReader)); } } if (memoryStream.Position != memoryStream.Length) { return Fail("Unexpected trailing terrain payload data.", out error); } data = new TerrainData(operations, lastX, lastY, lastZ, num, array, array2, stride, stride2); return true; } catch (EndOfStreamException) { return Fail("Truncated terrain payload.", out error); } catch (InvalidDataException ex2) { return Fail(ex2.Message, out error); } } public byte[] Encode() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1); binaryWriter.Write(Operations); binaryWriter.Write(LastOperationX); binaryWriter.Write(LastOperationY); binaryWriter.Write(LastOperationZ); binaryWriter.Write(LastOperationRadius); binaryWriter.Write(_heights.Length); TerrainHeight[] heights = _heights; for (int i = 0; i < heights.Length; i++) { TerrainHeight terrainHeight = heights[i]; binaryWriter.Write(terrainHeight.Modified); if (terrainHeight.Modified) { binaryWriter.Write(terrainHeight.LevelDelta); binaryWriter.Write(terrainHeight.SmoothDelta); } } binaryWriter.Write(_paint.Length); TerrainPaint[] paint = _paint; for (int i = 0; i < paint.Length; i++) { TerrainPaint terrainPaint = paint[i]; binaryWriter.Write(terrainPaint.Modified); if (terrainPaint.Modified) { binaryWriter.Write(terrainPaint.Red); binaryWriter.Write(terrainPaint.Green); binaryWriter.Write(terrainPaint.Blue); binaryWriter.Write(terrainPaint.Alpha); } } binaryWriter.Flush(); return memoryStream.ToArray(); } public int ClearWhere(Func heightPredicate, Func paintPredicate) { if (heightPredicate == null) { throw new ArgumentNullException("heightPredicate"); } if (paintPredicate == null) { throw new ArgumentNullException("paintPredicate"); } List list = new List(); List list2 = new List(); for (int i = 0; i < _heights.Length; i++) { if (_heights[i].Modified && heightPredicate(i)) { list.Add(i); } } for (int j = 0; j < _paint.Length; j++) { if (_paint[j].Modified && paintPredicate(j)) { list2.Add(j); } } foreach (int item in list) { _heights[item] = default(TerrainHeight); } foreach (int item2 in list2) { _paint[item2] = default(TerrainPaint); } return list.Count + list2.Count; } private static bool TryGetSquareStride(int count, out int stride) { stride = 0; if (count < 1 || count > 66049) { return false; } stride = (int)Math.Sqrt(count); return stride * stride == count; } private static bool ReadFlag(BinaryReader reader) { byte num = reader.ReadByte(); if (num > 1) { throw new InvalidDataException("Noncanonical terrain modification flag."); } return num == 1; } private static float ReadFinite(BinaryReader reader) { float num = reader.ReadSingle(); if (float.IsNaN(num) || float.IsInfinity(num)) { throw new InvalidDataException("Terrain payload contains a nonfinite number."); } return num; } private static bool Fail(string message, out string error) { error = message; return false; } } public readonly struct TerrainHeight { public bool Modified { get; } public float LevelDelta { get; } public float SmoothDelta { get; } internal TerrainHeight(bool modified, float levelDelta, float smoothDelta) { Modified = modified; LevelDelta = levelDelta; SmoothDelta = smoothDelta; } } public readonly struct TerrainPaint { public bool Modified { get; } public float Red { get; } public float Green { get; } public float Blue { get; } public float Alpha { get; } internal TerrainPaint(bool modified, float red, float green, float blue, float alpha) { Modified = modified; Red = red; Green = green; Blue = blue; Alpha = alpha; } } public static class TerrainPayload { public const int MaximumCompressedLength = 1782842; private static readonly uint[] CrcTable = CreateCrcTable(); public static bool TryInflate(byte[] bytes, out byte[] raw) { raw = null; if (bytes == null || bytes.Length < 18 || bytes.Length > 1782842 || bytes[0] != 31 || bytes[1] != 139 || bytes[2] != 8 || bytes[3] != 0) { return false; } uint num = ReadUInt32(bytes, bytes.Length - 4); if (num < 32 || num > 1717306) { return false; } try { using MemoryStream stream = new MemoryStream(bytes, writable: false); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[8192]; int num2; while ((num2 = gZipStream.Read(array, 0, array.Length)) > 0) { if (memoryStream.Length + num2 > 1717306) { return false; } memoryStream.Write(array, 0, num2); } if (memoryStream.Length != num) { return false; } byte[] array2 = memoryStream.ToArray(); if (Crc32(array2) != ReadUInt32(bytes, bytes.Length - 8)) { return false; } raw = array2; return true; } catch (InvalidDataException) { return false; } catch (IOException) { return false; } } private static uint ReadUInt32(byte[] bytes, int offset) { return (uint)(bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)); } private static uint Crc32(byte[] bytes) { uint num = uint.MaxValue; foreach (byte b in bytes) { num = CrcTable[(num ^ b) & 0xFF] ^ (num >> 8); } return ~num; } private static uint[] CreateCrcTable() { uint[] array = new uint[256]; for (uint num = 0u; num < array.Length; num++) { uint num2 = num; for (int i = 0; i < 8; i++) { num2 = (((num2 & 1) != 0) ? (0xEDB88320u ^ (num2 >> 1)) : (num2 >> 1)); } array[num] = num2; } return array; } } }