Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Regrove v1.0.1
plugins/Regrove/Regrove.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("Regrove")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("(c) 2026 Cody Keats")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+b6fe0926147bdc6243868904975100e1f0b97970")] [assembly: AssemblyProduct("Regrove")] [assembly: AssemblyTitle("Regrove")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] namespace Regrove { internal static class Ground { private const int W = 65; private const int N = 4225; private const float PAINTED = 0.25f; private static readonly int CompilerHash = StringExtensionMethods.GetStableHashCode("_TerrainCompiler"); private static readonly Dictionary<ZDOID, (uint rev, bool[] painted)> cache = new Dictionary<ZDOID, (uint, bool[])>(); private static readonly List<ZDO> near = new List<ZDO>(); public static bool Worked(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_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) Vector2s zone = ZoneSystem.GetZone(pos); Vector3 zonePos = ZoneSystem.GetZonePos(zone); near.Clear(); ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(0, 0, true), near, (List<ZDO>)null); foreach (ZDO item in near) { if (item.GetPrefab() != CompilerHash || ZoneSystem.GetZone(item.GetPosition()) != zone) { continue; } bool[] array = Painted(item); if (array == null) { return false; } int num = Mathf.RoundToInt(pos.x - (zonePos.x - 32f)); int num2 = Mathf.RoundToInt(pos.z - (zonePos.z - 32f)); for (int i = num2 - 2; i <= num2 + 2; i++) { for (int j = num - 2; j <= num + 2; j++) { if (j >= 0 && i >= 0 && j < 65 && i < 65 && array[i * 65 + j]) { return true; } } } return false; } return false; } private static bool[] Painted(ZDO zdo) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) uint dataRevision = zdo.DataRevision; if (cache.TryGetValue(zdo.m_uid, out (uint, bool[]) value) && value.Item1 == dataRevision) { return value.Item2; } bool[] array = null; try { array = Decode(zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null)); } catch (Exception ex) { ZLog.LogWarning((object)("Regrove: terrain data not understood: " + ex.Message)); } if (cache.Count > 2000) { cache.Clear(); } cache[zdo.m_uid] = (dataRevision, array); return array; } private static bool[] Decode(byte[] blob) { if (blob == null || blob.Length == 0) { return null; } using GZipStream input = new GZipStream(new MemoryStream(blob), CompressionMode.Decompress); using BinaryReader binaryReader = new BinaryReader(input); binaryReader.ReadInt32(); binaryReader.ReadInt32(); binaryReader.ReadSingle(); binaryReader.ReadSingle(); binaryReader.ReadSingle(); binaryReader.ReadSingle(); int num = binaryReader.ReadInt32(); if (num != 4225) { throw new InvalidDataException("height grid of " + num); } for (int i = 0; i < num; i++) { if (binaryReader.ReadBoolean()) { binaryReader.ReadSingle(); binaryReader.ReadSingle(); } } int num2 = binaryReader.ReadInt32(); if (num2 != 4225) { throw new InvalidDataException("paint grid of " + num2); } bool[] array = new bool[4225]; bool flag = false; for (int j = 0; j < num2; j++) { if (binaryReader.ReadBoolean()) { float num3 = binaryReader.ReadSingle(); float num4 = binaryReader.ReadSingle(); float num5 = binaryReader.ReadSingle(); binaryReader.ReadSingle(); if (num3 > 0.25f || num4 > 0.25f || num5 > 0.25f) { flag = (array[j] = true); } } } return flag ? array : null; } } [BepInPlugin("com.cocopuff2u.regrove", "Regrove", "1.0.1")] public class Plugin : BaseUnityPlugin { public enum Regrowth { Sapling, Tree } public enum SignTargets { Both, Stumps, Saplings } public const string GUID = "com.cocopuff2u.regrove"; public const string NAME = "Regrove"; public const string VERSION = "1.0.1"; private const string TREESURRECTION = "ArgusMagnus.ServersideQoL.Treesurrection"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> SaplingChance; internal static ConfigEntry<float> SaplingDelay; internal static ConfigEntry<float> GrowTime; internal static ConfigEntry<bool> RemoveOnFell; internal static ConfigEntry<float> RegrowDays; internal static ConfigEntry<Regrowth> RegrowAs; internal static ConfigEntry<int> RegrowChance; internal static ConfigEntry<int> MaxPerRound; internal static ConfigEntry<float> RoundMinutes; internal static ConfigEntry<SignTargets> SignsOn; internal static ConfigEntry<bool> ProtectWards; internal static ConfigEntry<float> ProtectRadius; internal static ConfigEntry<bool> ProtectGround; internal static ConfigEntry<string> ExcludeTrees; internal static ConfigEntry<bool> SpecialWoodOnly; internal static ConfigEntry<bool> CountdownSigns; internal static ConfigEntry<float> SignRadius; internal static bool blocked; internal static int Reloads; private FileSystemWatcher watcher; private volatile bool changed; private float reloadAt; private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns the whole mod on or off"); SaplingChance = ((BaseUnityPlugin)this).Config.Bind<int>("Stumps", "SaplingChance", 100, new ConfigDescription("Chance in percent that a stump a player removes leaves a sapling of its tree", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); SaplingDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Stumps", "SaplingDelaySeconds", 5f, "Seconds between the stump going and the sapling appearing, so the last axe swing doesn't hit it"); GrowTime = ((BaseUnityPlugin)this).Config.Bind<float>("Stumps", "GrowTimeMultiplier", 1f, "How long a regrowing sapling takes compared with one a player plants (0.5 = twice as fast)"); RemoveOnFell = ((BaseUnityPlugin)this).Config.Bind<bool>("Stumps", "RemoveOnFell", false, "Stumps go as soon as their tree falls and the sapling is planted right away, so nobody has to dig them out. The stump's wood is lost"); RegrowDays = ((BaseUnityPlugin)this).Config.Bind<float>("Regrow", "StumpRegrowDays", 3f, "In-game days a stump can stand before it grows back by itself, without anyone removing it. The game's clock only runs while someone is online. 0 turns this off"); RegrowAs = ((BaseUnityPlugin)this).Config.Bind<Regrowth>("Regrow", "RegrowAs", Regrowth.Sapling, "What a left stump turns into. Sapling: a sapling of its tree, which then grows. Tree: the tree that stood there, the same kind and size, at once; swamp, Mistlands and Ashlands trees come back too"); RegrowChance = ((BaseUnityPlugin)this).Config.Bind<int>("Regrow", "RegrowChance", 100, new ConfigDescription("Chance in percent that a left stump grows back at all. Each stump's chance is fixed (the same stump always gets the same answer), so below 100 some stumps simply stay, and old clearings fill in patchily", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); MaxPerRound = ((BaseUnityPlugin)this).Config.Bind<int>("Regrow", "MaxPerRound", 50, new ConfigDescription("Left stumps that may grow back in one round", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>())); RoundMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Regrow", "RoundMinutes", 5f, new ConfigDescription("Minutes between rounds: how often the world is checked for left stumps that are due", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); ProtectWards = ((BaseUnityPlugin)this).Config.Bind<bool>("Protect", "InsideWards", true, "No saplings inside an active ward"); ProtectRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Protect", "BuildRadius", 20f, new ConfigDescription("No saplings within this many metres of anything a player built. 0 turns this off", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); ProtectGround = ((BaseUnityPlugin)this).Config.Bind<bool>("Protect", "PathsAndFields", false, "No saplings on paths, paved roads or cultivated ground, or within 2 m of them"); ExcludeTrees = ((BaseUnityPlugin)this).Config.Bind<string>("Trees", "ExcludeTrees", "", "Trees Regrove leaves alone, by name or the start of a name, comma separated (e.g. \"SwampTree, Oak\"). The server log lists every tree's name at start"); SpecialWoodOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Wood", "SpecialWoodOnly", false, "Logs and stumps drop their tree's special wood in place of plain wood, one for one: core wood from pines, fine wood from birches and oaks, ancient bark from swamp trees, Yggdrasil wood, blackwood, frost wood. Beech and fir have none and still give plain wood"); CountdownSigns = ((BaseUnityPlugin)this).Config.Bind<bool>("Signs", "CountdownSigns", false, "A small sign beside each stump and regrowing sapling near a player, saying how long it has left (time played). Plain game signs, so players need no mod; they are never saved"); SignsOn = ((BaseUnityPlugin)this).Config.Bind<SignTargets>("Signs", "SignsOn", SignTargets.Both, "Which get a countdown sign: Both, Stumps or Saplings"); SignRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Signs", "SignRadius", 15f, new ConfigDescription("How close, in metres, a stump or sapling must be to a player to get a sign", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 40f), Array.Empty<object>())); new Harmony("com.cocopuff2u.regrove").PatchAll(Assembly.GetExecutingAssembly()); WatchConfig(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Regrove 1.0.1 loaded"); } private void WatchConfig() { try { watcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath)); watcher.Changed += delegate { changed = true; }; watcher.Created += delegate { changed = true; }; watcher.Renamed += delegate { changed = true; }; watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; watcher.EnableRaisingEvents = true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Settings won't reload by themselves: " + ex.Message)); } } private void ReloadIfChanged() { if (changed) { changed = false; reloadAt = Time.time + 1f; } if (reloadAt == 0f || Time.time < reloadAt) { return; } reloadAt = 0f; try { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { ((BaseUnityPlugin)this).Config.Reload(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } Trees.SettingsChanged(); Reloads++; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Settings reloaded"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Settings not reloaded: " + ex.Message)); } } private void Start() { if (Chainloader.PluginInfos.ContainsKey("ArgusMagnus.ServersideQoL.Treesurrection")) { blocked = true; ((BaseUnityPlugin)this).Logger.LogError((object)"ServersideQoL.Treesurrection is installed and does the same thing. Regrove is not running: remove one of the two."); } } private void Update() { ReloadIfChanged(); Stumps.Update(); } } internal static class Signs { private struct Shown { public ZDOID sign; public string text; } private const int MAX = 64; private const float KEEP = 10f; private const int NEW_PER_UPDATE = 4; private static readonly int SignHash = StringExtensionMethods.GetStableHashCode("sign"); private static readonly Dictionary<ZDOID, Shown> shown = new Dictionary<ZDOID, Shown>(); private static readonly Dictionary<ZDOID, (ZDO target, Vector3 viewer)> wanted = new Dictionary<ZDOID, (ZDO, Vector3)>(); private static readonly Dictionary<ZDOID, (bool kept, float until)> keptCache = new Dictionary<ZDOID, (bool, float)>(); private static readonly List<ZDO> near = new List<ZDO>(); private static readonly List<ZDOID> gone = new List<ZDOID>(); private static readonly HashSet<ZDOID> live = new HashSet<ZDOID>(); private static float next; public static void Update() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: 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_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_036d: 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_019f: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) if (Time.time < next) { return; } next = Time.time + 2f; if (!Plugin.CountdownSigns.Value) { if (shown.Count > 0) { RemoveAll(); } return; } wanted.Clear(); float value = Plugin.SignRadius.Value; List<Vector3> list = new List<Vector3>(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { list.Add(peer.m_refPos); } foreach (Vector3 item in list) { near.Clear(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(item), new SimulationDistance(1, 0, true), near, (List<ZDO>)null); foreach (ZDO item2 in near) { if (wanted.Count >= 64) { break; } if (wanted.ContainsKey(item2.m_uid)) { continue; } float num = Utils.DistanceXZ(item2.GetPosition(), item); if (!(num > value + 10f) && (!(num > value) || shown.ContainsKey(item2.m_uid))) { int prefab = item2.GetPrefab(); Plugin.SignTargets value2 = Plugin.SignsOn.Value; if ((value2 != Plugin.SignTargets.Saplings && Trees.Stumps.ContainsKey(prefab)) || (value2 != Plugin.SignTargets.Stumps && Trees.Saplings.Contains(prefab) && Stumps.IsOurs(item2))) { wanted[item2.m_uid] = (item2, item); } } } } live.Clear(); int num2 = 0; foreach (KeyValuePair<ZDOID, (ZDO, Vector3)> item3 in wanted) { string text = Text(item3.Value.Item1); if (text == null) { continue; } live.Add(item3.Key); if (shown.TryGetValue(item3.Key, out var value3)) { ZDO zDO = ZDOMan.instance.GetZDO(value3.sign); if (zDO != null) { if (value3.text != text) { zDO.Set(ZDOVars.s_text, text); shown[item3.Key] = new Shown { sign = value3.sign, text = text }; } continue; } } if (num2 >= 4) { live.Remove(item3.Key); continue; } ZDO val = Place(item3.Value.Item1, item3.Value.Item2, text); if (val != null) { shown[item3.Key] = new Shown { sign = val.m_uid, text = text }; num2++; } } gone.Clear(); foreach (KeyValuePair<ZDOID, Shown> item4 in shown) { if (!live.Contains(item4.Key)) { gone.Add(item4.Key); } } foreach (ZDOID item5 in gone) { Remove(item5); } } private static string Text(ZDO target) { //IL_0123: Unknown result type (might be due to invalid IL or missing references) long ticks = ZNet.instance.GetTime().Ticks; int prefab = target.GetPrefab(); if (Trees.Stumps.ContainsKey(prefab)) { if (Plugin.RegrowDays.Value <= 0f || !Stumps.WillRegrow(target)) { return null; } if (Trees.Excluded(Stumps.TreeOf(target))) { return null; } if (Kept(target)) { return "Stays\n(near a base)"; } long num = target.GetLong(Stumps.SeenHash, 0L); long num2 = ((num != 0L) ? num : ticks) + Stumps.RegrowAge(); string text = ((Plugin.RegrowAs.Value == Plugin.Regrowth.Tree) ? "Tree" : "Sapling"); if (num2 > ticks) { return text + " in\n" + Span(num2 - ticks); } return text + "\nany moment now"; } long num3 = target.GetLong(ZDOVars.s_plantTime, 0L); if (num3 == 0L) { return null; } GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); Plant val = ((prefab2 != null) ? prefab2.GetComponentInChildren<Plant>(true) : null); if ((Object)(object)val == (Object)null) { return null; } float num4 = target.GetFloat("Plant.m_growTime", val.m_growTime); float num5 = target.GetFloat("Plant.m_growTimeMax", val.m_growTimeMax); State state = Random.state; Random.InitState(target.GetInt(ZDOVars.s_seed, 0)); float num6 = Mathf.Lerp(num4, num5, Random.value); Random.state = state; long num7 = num3 + (long)(num6 * 10000000f); if (num7 > ticks) { return "Tree in\n" + Span(num7 - ticks); } return "Tree\nany moment now"; } private static bool Kept(ZDO stump) { //IL_0006: 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_0055: Unknown result type (might be due to invalid IL or missing references) if (keptCache.TryGetValue(stump.m_uid, out (bool, float) value) && Time.time < value.Item2) { return value.Item1; } bool flag = Stumps.Protected(stump.GetPosition()); if (keptCache.Count > 4000) { keptCache.Clear(); } keptCache[stump.m_uid] = (flag, Time.time + 60f); return flag; } private static string Span(long ticks) { TimeSpan timeSpan = TimeSpan.FromTicks(ticks); if (timeSpan.TotalHours >= 1.0) { int num = (int)Math.Round(timeSpan.TotalMinutes / 5.0) * 5; return $"about {num / 60}h {num % 60:D2}m"; } if (timeSpan.TotalMinutes >= 1.0) { return $"{timeSpan.Minutes}m"; } return "under a minute"; } private static ZDO Place(ZDO target, Vector3 viewer, string text) { //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_0035: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0057: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(SignHash); ZNetView val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ZNetView>() : null); if ((Object)(object)val == (Object)null) { return null; } Vector3 position = target.GetPosition(); Vector3 val2 = viewer - position; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = Vector3.forward; } ((Vector3)(ref val2)).Normalize(); bool flag = Trees.Stumps.ContainsKey(target.GetPrefab()); Vector3 val3 = position + val2 * (flag ? 1.3f : 0.7f) + Vector3.up * 0.9f; ZDO obj = ZDOMan.instance.CreateNewZDO(val3, SignHash); obj.Persistent = false; obj.Type = val.m_type; obj.Distant = val.m_distant; obj.SetPrefab(SignHash); obj.SetRotation(Quaternion.LookRotation(val2)); obj.Set("HasFields", true); obj.Set("HasFieldsWearNTear", true); obj.Set("WearNTear.m_supports", false); obj.Set("HasFieldsPiece", true); obj.Set("Piece.m_canBeRemoved", false); obj.Set(ZDOVars.s_text, text); return obj; } private static void Remove(ZDOID target) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (shown.TryGetValue(target, out var value)) { ZDO zDO = ZDOMan.instance.GetZDO(value.sign); if (zDO != null) { Stumps.Remove(zDO); } } shown.Remove(target); } public static void RemoveAll() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) gone.Clear(); gone.AddRange(shown.Keys); foreach (ZDOID item in gone) { Remove(item); } } } internal static class Stumps { private struct Pending { public float at; public int stump; public int tree; public Vector3 pos; public Quaternion rot; } private struct Felled { public float until; public float next; public int tree; public int stump; public Vector3 pos; } private struct Removal { public float at; public ZDOID id; public int tree; } [HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")] private static class Destroyed { private static void Prefix(ZDOMan __instance, ZDOID uid) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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_0134: Unknown result type (might be due to invalid IL or missing references) if (!Active || !Trees.Ready || ours.Remove(uid) || __instance.m_deadZDOs.ContainsKey(uid)) { return; } ZDO zDO = __instance.GetZDO(uid); if (zDO == null) { return; } int prefab = zDO.GetPrefab(); Wood.Broken(zDO); if (Trees.StumpOf.TryGetValue(prefab, out var value)) { if (!Trees.Excluded(prefab)) { felled.Add(new Felled { until = Time.time + 15f, tree = prefab, stump = value, pos = zDO.GetPosition() }); } } else if (Trees.Stumps.ContainsKey(prefab)) { if (!treeOf.TryGetValue(uid, out var value2)) { value2 = zDO.GetInt(TreeHash, 0); } treeOf.Remove(uid); if (Random.Range(0, 100) < Plugin.SaplingChance.Value) { pending.Add(new Pending { at = Time.time + Plugin.SaplingDelay.Value, stump = prefab, tree = value2, pos = zDO.GetPosition(), rot = zDO.GetRotation() }); } } } } internal static readonly int SeenHash = StringExtensionMethods.GetStableHashCode("regrove_seen"); private static readonly int TreeHash = StringExtensionMethods.GetStableHashCode("regrove_tree"); private static readonly int PlantedHash = StringExtensionMethods.GetStableHashCode("regrove_planted"); private static readonly int OursHash = StringExtensionMethods.GetStableHashCode("HasFieldsPlant"); private const int SWEEP_BUDGET = 2000; private const float FALL_WATCH = 15f; private static readonly List<Pending> pending = new List<Pending>(); private static readonly List<Felled> felled = new List<Felled>(); private static readonly List<Removal> removals = new List<Removal>(); private static readonly HashSet<ZDOID> ours = new HashSet<ZDOID>(); private static readonly Dictionary<ZDOID, int> treeOf = new Dictionary<ZDOID, int>(); private static readonly List<ZDO> near = new List<ZDO>(); private static readonly List<ZDOID> due = new List<ZDOID>(); private static int sector = -1; private static int index; private static int seen; private static int stamped; private static int busy; private static int growing; private static int sweeps; private static readonly Stopwatch clock = new Stopwatch(); private static double roundMs; private static double slowestMs; private static int roundFrames; private static float nextSweep = 60f; private static bool Active { get { if (Plugin.Enabled.Value && !Plugin.blocked && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZDOMan.instance != null) { return (Object)(object)ZNetScene.instance != (Object)null; } return false; } } public static void Update() { if (Active) { clock.Restart(); Tick(); double totalMilliseconds = clock.Elapsed.TotalMilliseconds; roundMs += totalMilliseconds; roundFrames++; if (totalMilliseconds > slowestMs) { slowestMs = totalMilliseconds; } } } private static void Tick() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (!Trees.Ready) { Trees.Load(); if (!Trees.Ready) { return; } if ((Object)(object)EnvMan.instance != (Object)null) { ZLog.Log((object)$"Regrove: an in-game day is {EnvMan.instance.m_dayLengthSec / 60} minutes"); } } for (int num = Stumps.pending.Count - 1; num >= 0; num--) { Pending pending = Stumps.pending[num]; if (!(Time.time < pending.at)) { Stumps.pending.RemoveAt(num); int tree = TreeFor(pending.stump, pending.tree, pending.pos); if (!Trees.Excluded(tree) && !Protected(pending.pos)) { Sow(tree, pending.pos, pending.rot); } } } Wood.Update(); Signs.Update(); WatchFelled(); RemoveStumps(); Sweep(); } private static void WatchFelled() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) for (int num = felled.Count - 1; num >= 0; num--) { Felled value = felled[num]; if (Time.time > value.until) { felled.RemoveAt(num); } else if (!(Time.time < value.next)) { value.next = Time.time + 0.5f; felled[num] = value; FindNear(value.pos); foreach (ZDO item in near) { if (item.GetPrefab() == value.stump && !(Utils.DistanceXZ(item.GetPosition(), value.pos) > 0.5f) && !treeOf.ContainsKey(item.m_uid)) { treeOf[item.m_uid] = value.tree; if (Plugin.RemoveOnFell.Value) { removals.Add(new Removal { at = Time.time + Plugin.SaplingDelay.Value, id = item.m_uid, tree = value.tree }); } felled.RemoveAt(num); break; } } } } } private static void RemoveStumps() { //IL_003c: 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_0050: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) for (int num = removals.Count - 1; num >= 0; num--) { Removal removal = removals[num]; if (!(Time.time < removal.at)) { removals.RemoveAt(num); ZDO zDO = ZDOMan.instance.GetZDO(removal.id); if (zDO != null) { Vector3 position = zDO.GetPosition(); if (!Protected(position) && Random.Range(0, 100) < Plugin.SaplingChance.Value) { Sow(removal.tree, position, zDO.GetRotation()); } Wood.StumpDrops(zDO.GetPrefab(), position); Remove(zDO); } } } } private static void Sweep() { //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: 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_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) if (Plugin.RegrowDays.Value <= 0f) { return; } List<ZDO>[] objectsBySector = ZDOMan.instance.m_objectsBySector; if (objectsBySector == null) { return; } if (sector < 0) { if (Time.time < nextSweep) { return; } sector = 0; index = 0; seen = (stamped = (busy = (growing = 0))); due.Clear(); roundMs = (slowestMs = 0.0); roundFrames = 0; } long ticks = ZNet.instance.GetTime().Ticks; long num = RegrowAge(); int num2 = 2000; while (sector < objectsBySector.Length && num2 > 0) { List<ZDO> list = objectsBySector[sector]; if (list == null || index >= list.Count) { sector++; index = 0; continue; } int num3 = Mathf.Min(list.Count, index + num2); num2 -= num3 - index; while (index < num3) { ZDO val = list[index]; int prefab = val.GetPrefab(); if (Trees.Saplings.Contains(prefab) && IsOurs(val)) { growing++; } if (Trees.Stumps.ContainsKey(prefab)) { seen++; if (Busy(val)) { busy++; } else { if (treeOf.TryGetValue(val.m_uid, out var value)) { val.Set(TreeHash, value, false); treeOf.Remove(val.m_uid); } long num4 = val.GetLong(SeenHash, 0L); if (num4 == 0L) { val.Set(SeenHash, ticks); stamped++; } else if (ticks - num4 >= num && due.Count < Plugin.MaxPerRound.Value && WillRegrow(val)) { due.Add(val.m_uid); } } } index++; } } if (sector < objectsBySector.Length) { return; } sector = -1; nextSweep = Time.time + Plugin.RoundMinutes.Value * 60f; bool flag = Plugin.RegrowAs.Value == Plugin.Regrowth.Tree; int num5 = 0; int num6 = 0; foreach (ZDOID item in due) { ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO != null && !Busy(zDO)) { Vector3 position = zDO.GetPosition(); int tree = TreeFor(zDO.GetPrefab(), zDO.GetInt(TreeHash, 0), position); if (Trees.Excluded(tree) || Protected(position) || !(flag ? Grow(tree, zDO) : Sow(tree, position, zDO.GetRotation()))) { zDO.Set(SeenHash, ticks); num6++; } else { Remove(zDO); num5++; } } } if (due.Count > 0 || sweeps++ == 0) { ZLog.Log((object)string.Format("Regrove: {0} stumps standing ({1} new, {2} near players), {3} turned into {4}, {5} kept (near a base or path, left alone, or nothing grows there); {6} saplings regrowing; round took {7:0} ms over {8} frames, slowest frame {9:0.00} ms", seen, stamped, busy, num5, flag ? "trees" : "saplings", num6, growing, roundMs, roundFrames, slowestMs)); } due.Clear(); } private static bool Busy(ZDO zdo) { if (!zdo.HasOwner()) { return false; } long owner = zdo.GetOwner(); if (owner != ZDOMan.GetSessionID()) { return ZNet.instance.GetPeer(owner) != null; } return false; } internal static bool WillRegrow(ZDO stump) { int value = Plugin.RegrowChance.Value; if (value >= 100) { return true; } return (uint)(((int)((ZDOID)(ref stump.m_uid)).ID * -1640531535) ^ ((int)((ZDOID)(ref stump.m_uid)).UserID * 40503)) % 100u < value; } internal static long RegrowAge() { long num = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.m_dayLengthSec : 1800) * 10000000; return (long)(Plugin.RegrowDays.Value * (float)num); } internal static bool IsOurs(ZDO sapling) { if (!sapling.GetBool(PlantedHash, false)) { return sapling.GetBool(OursHash, false); } return true; } internal static int TreeOf(ZDO stump) { //IL_0006: 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) if (!treeOf.TryGetValue(stump.m_uid, out var value)) { value = stump.GetInt(TreeHash, 0); } return TreeFor(stump.GetPrefab(), value, stump.GetPosition()); } internal static void Remove(ZDO zdo) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) ours.Add(zdo.m_uid); treeOf.Remove(zdo.m_uid); zdo.SetOwner(ZDOMan.GetSessionID()); ZDOMan.instance.DestroyZDO(zdo); } private static void FindNear(Vector3 pos) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) near.Clear(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(pos), new SimulationDistance(1, 0, true), near, (List<ZDO>)null); } internal static bool Protected(Vector3 pos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (Plugin.ProtectGround.Value && Ground.Worked(pos)) { return true; } bool value = Plugin.ProtectWards.Value; float value2 = Plugin.ProtectRadius.Value; if (!value && value2 <= 0f) { return false; } FindNear(pos); foreach (ZDO item in near) { int prefab = item.GetPrefab(); float num = Utils.DistanceXZ(item.GetPosition(), pos); if (value && Trees.WardRadius.TryGetValue(prefab, out var value3) && num <= value3 && item.GetBool(ZDOVars.s_enabled, false)) { return true; } if (value2 > 0f && num <= value2 && Trees.Pieces.Contains(prefab) && item.GetLong(ZDOVars.s_creator, 0L) != 0L) { return true; } } return false; } private static int TreeFor(int stump, int known, Vector3 pos) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) List<int> list = Trees.Stumps[stump]; if (known != 0 && list.Contains(known)) { return known; } if (list.Count == 1) { return list[0]; } FindNear(pos); Dictionary<int, int> dictionary = new Dictionary<int, int>(); int result = list[0]; int num = 0; foreach (ZDO item in near) { int prefab = item.GetPrefab(); if (list.Contains(prefab)) { dictionary.TryGetValue(prefab, out var value); value = (dictionary[prefab] = value + 1); if (value > num) { result = prefab; num = value; } } } return result; } private static bool Sow(int tree, Vector3 pos, Quaternion rot) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Trees.SaplingOf.TryGetValue(tree, out var value)) { return false; } GameObject prefab = ZNetScene.instance.GetPrefab(value); Plant val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<Plant>(true) : null); if ((Object)(object)val == (Object)null) { return false; } if (WorldGenerator.instance != null && (WorldGenerator.instance.GetBiome(pos) & val.m_biome) == 0) { return false; } ZDO val2 = Create(value, pos, rot); if (val2 == null) { return false; } val2.Set(ZDOVars.s_plantTime, ZNet.instance.GetTime().Ticks); val2.Set(ZDOVars.s_seed, (int)(((ZDOID)(ref val2.m_uid)).ID + ((ZDOID)(ref val2.m_uid)).UserID), false); val2.Set(PlantedHash, true); float num = Mathf.Max(0f, Plugin.GrowTime.Value); bool flag = false; if (val.m_growRadius != 0f) { val2.Set("Plant.m_growRadius", 0f); flag = true; } if (val.m_needCultivatedGround) { val2.Set("Plant.m_needCultivatedGround", false); flag = true; } if (val.m_destroyIfCantGrow) { val2.Set("Plant.m_destroyIfCantGrow", false); flag = true; } if (!val.m_tolerateCold) { val2.Set("Plant.m_tolerateCold", true); flag = true; } if (num != 1f) { val2.Set("Plant.m_growTime", val.m_growTime * num); val2.Set("Plant.m_growTimeMax", val.m_growTimeMax * num); flag = true; } if (flag) { val2.Set("HasFields", true); val2.Set("HasFieldsPlant", true); } return true; } private static bool Grow(int tree, ZDO stump) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) ZDO val = Create(tree, stump.GetPosition(), stump.GetRotation()); if (val == null) { return false; } Vector3 vec = stump.GetVec3(ZDOVars.s_scaleHash, Vector3.zero); float num = default(float); if (vec != Vector3.zero) { val.Set(ZDOVars.s_scaleHash, vec); } else if (stump.GetFloat(ZDOVars.s_scaleScalarHash, ref num)) { val.Set(ZDOVars.s_scaleScalarHash, num); } return true; } internal static ZDO Create(int hash, Vector3 pos, Quaternion rot) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(hash); ZNetView val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ZNetView>() : null); if ((Object)(object)val == (Object)null) { return null; } ZDO obj = ZDOMan.instance.CreateNewZDO(pos, hash); obj.Persistent = val.m_persistent; obj.Type = val.m_type; obj.Distant = val.m_distant; obj.SetPrefab(hash); obj.SetRotation(rot); return obj; } } internal static class Trees { public static readonly Dictionary<int, List<int>> Stumps = new Dictionary<int, List<int>>(); public static readonly Dictionary<int, int> StumpOf = new Dictionary<int, int>(); public static readonly Dictionary<int, int> SaplingOf = new Dictionary<int, int>(); public static readonly HashSet<int> Saplings = new HashSet<int>(); public static readonly Dictionary<int, float> WardRadius = new Dictionary<int, float>(); public static readonly HashSet<int> Pieces = new HashSet<int>(); public static readonly Dictionary<int, int> SpecialWood = new Dictionary<int, int>(); public static readonly Dictionary<int, DropTable> StumpDrops = new Dictionary<int, DropTable>(); public static readonly int Wood = StringExtensionMethods.GetStableHashCode("Wood"); private static readonly Dictionary<int, bool> excluded = new Dictionary<int, bool>(); private static readonly (string kind, string tree)[] families = new(string, string)[3] { ("birch", "Birch1"), ("fir", "FirTree"), ("pine", "Pinetree_01") }; public static bool Ready { get; private set; } public static void Load() { ZNetScene instance = ZNetScene.instance; if (Ready || (Object)(object)instance == (Object)null || instance.m_prefabs == null || instance.m_prefabs.Count == 0) { return; } Dictionary<int, int> dictionary = new Dictionary<int, int>(); Dictionary<int, GameObject> dictionary2 = new Dictionary<int, GameObject>(); foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); PrivateArea component = prefab.GetComponent<PrivateArea>(); if ((Object)(object)component != (Object)null) { WardRadius[stableHashCode] = component.m_radius; } if ((Object)(object)prefab.GetComponent<Piece>() != (Object)null) { Pieces.Add(stableHashCode); } TreeBase componentInChildren = prefab.GetComponentInChildren<TreeBase>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.m_stubPrefab != (Object)null) { int stableHashCode2 = StringExtensionMethods.GetStableHashCode(((Object)componentInChildren.m_stubPrefab).name); StumpOf[stableHashCode] = stableHashCode2; if ((Object)(object)componentInChildren.m_logPrefab != (Object)null) { dictionary2[stableHashCode] = componentInChildren.m_logPrefab; } DropOnDestroyed component2 = componentInChildren.m_stubPrefab.GetComponent<DropOnDestroyed>(); if ((Object)(object)component2 != (Object)null) { StumpDrops[stableHashCode2] = component2.m_dropWhenDestroyed; } if (!Stumps.TryGetValue(stableHashCode2, out var value)) { value = (Stumps[stableHashCode2] = new List<int>()); } value.Add(stableHashCode); continue; } TreeLog component3 = prefab.GetComponent<TreeLog>(); if ((Object)(object)component3 != (Object)null) { int num = SpecialIn(component3.m_dropWhenDestroyed); if (num != 0) { SpecialWood[stableHashCode] = num; } continue; } Plant componentInChildren2 = prefab.GetComponentInChildren<Plant>(true); if (componentInChildren2?.m_grownPrefabs == null) { continue; } GameObject[] grownPrefabs = componentInChildren2.m_grownPrefabs; foreach (GameObject val in grownPrefabs) { if (!((Object)(object)val == (Object)null)) { int stableHashCode3 = StringExtensionMethods.GetStableHashCode(((Object)val).name); if (!dictionary.ContainsKey(stableHashCode3)) { dictionary[stableHashCode3] = stableHashCode; } } } } foreach (int key2 in StumpOf.Keys) { if (dictionary.TryGetValue(key2, out var value2) || Family(Name(key2), dictionary, out value2)) { SaplingOf[key2] = value2; Saplings.Add(value2); } } foreach (KeyValuePair<int, GameObject> item in dictionary2) { int key = StumpOf[item.Key]; if (SpecialWood.ContainsKey(key)) { continue; } GameObject val2 = item.Value; while ((Object)(object)val2 != (Object)null) { if (SpecialWood.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)val2).name), out var value3)) { SpecialWood[key] = value3; break; } val2 = val2.GetComponent<TreeLog>()?.m_subLogPrefab; } } List<string> list2 = new List<string>(); foreach (KeyValuePair<int, int> item2 in SpecialWood) { list2.Add(Name(item2.Key) + " -> " + Name(item2.Value)); } ZLog.Log((object)("Regrove: special wood: " + string.Join(", ", list2))); foreach (KeyValuePair<int, List<int>> stump in Stumps) { List<string> list3 = new List<string>(); foreach (int item3 in stump.Value) { list3.Add(SaplingOf.TryGetValue(item3, out var value4) ? (Name(item3) + " -> " + Name(value4) + " (" + Describe(instance.GetPrefab(value4).GetComponentInChildren<Plant>(true)) + ")") : (Name(item3) + " (no sapling)")); } ZLog.Log((object)("Regrove: " + Name(stump.Key) + ": " + string.Join(", ", list3))); } Ready = true; } private static int SpecialIn(DropTable table) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (table?.m_drops == null) { return 0; } foreach (DropData drop in table.m_drops) { if (!((Object)(object)drop.m_item == (Object)null)) { string text = ((Object)drop.m_item).name.ToLowerInvariant(); if (text != "wood" && (text.Contains("wood") || text.Contains("log") || text.Contains("bark"))) { return StringExtensionMethods.GetStableHashCode(((Object)drop.m_item).name); } } } return 0; } public static bool Excluded(int tree) { if (excluded.TryGetValue(tree, out var value)) { return value; } value = false; string text = Name(tree); string[] array = Plugin.ExcludeTrees.Value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0 && text.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { value = true; break; } } excluded[tree] = value; return value; } public static void SettingsChanged() { excluded.Clear(); } private static bool Family(string tree, Dictionary<int, int> grownFrom, out int sapling) { sapling = 0; string text = tree.ToLowerInvariant(); (string, string)[] array = families; for (int i = 0; i < array.Length; i++) { var (value, text2) = array[i]; if (text.Contains(value)) { return grownFrom.TryGetValue(StringExtensionMethods.GetStableHashCode(text2), out sapling); } } return false; } private static string Describe(Plant p) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return $"{p.m_biome}; grows in {p.m_growTime / 60f:F0}-{p.m_growTimeMax / 60f:F0} min, needs {p.m_growRadius:0.#} m of room"; } public static string Name(int prefab) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(prefab) : null); if (!((Object)(object)val != (Object)null)) { return prefab.ToString(); } return ((Object)val).name; } } internal static class Wood { private struct Watch { public Vector3 pos; public float radius; public float until; public int special; public HashSet<ZDOID> before; } private const float WATCH = 3f; private static readonly List<Watch> watches = new List<Watch>(); private static readonly List<ZDO> near = new List<ZDO>(); private static float next; public static void Broken(ZDO zdo) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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) if (!Plugin.SpecialWoodOnly.Value || !Trees.SpecialWood.TryGetValue(zdo.GetPrefab(), out var value)) { return; } Vector3 position = zdo.GetPosition(); float radius = (Trees.Stumps.ContainsKey(zdo.GetPrefab()) ? 2.5f : 4f); HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); Find(position); foreach (ZDO item in near) { if (item.GetPrefab() == Trees.Wood) { hashSet.Add(item.m_uid); } } watches.Add(new Watch { pos = position, radius = radius, until = Time.time + 3f, special = value, before = hashSet }); } public static void Update() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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) if (watches.Count == 0 || Time.time < next) { return; } next = Time.time + 0.1f; for (int num = watches.Count - 1; num >= 0; num--) { Watch watch = watches[num]; Find(watch.pos); foreach (ZDO item in near) { if (item.GetPrefab() == Trees.Wood && !watch.before.Contains(item.m_uid) && !(Utils.DistanceXZ(item.GetPosition(), watch.pos) > watch.radius)) { int stack = Stack(item); Vector3 position = item.GetPosition(); Stumps.Remove(item); Drop(watch.special, stack, position); } } if (Time.time > watch.until) { watches.RemoveAt(num); } } } public static void StumpDrops(int stump, Vector3 pos) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if (!Trees.StumpDrops.TryGetValue(stump, out var value)) { return; } Trees.SpecialWood.TryGetValue(stump, out var value2); Dictionary<int, int> dictionary = new Dictionary<int, int>(); foreach (GameObject drop in value.GetDropList()) { int num = StringExtensionMethods.GetStableHashCode(((Object)drop).name); if (num == Trees.Wood && value2 != 0 && Plugin.SpecialWoodOnly.Value) { num = value2; } dictionary.TryGetValue(num, out var value3); dictionary[num] = value3 + 1; } foreach (KeyValuePair<int, int> item in dictionary) { Drop(item.Key, item.Value, pos + Vector3.up * 0.5f); } } private static void Find(Vector3 pos) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) near.Clear(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(pos), new SimulationDistance(1, 0, true), near, (List<ZDO>)null); } private static int Stack(ZDO zdo) { GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); ItemDrop val = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { return 1; } ItemData val2 = val.m_itemData.Clone(); val2.m_stack = 1; ItemDrop.LoadFromZDO(val2, zdo, -1); return Mathf.Max(1, val2.m_stack); } internal static void Drop(int item, int stack, Vector3 pos) { //IL_0094: 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_00e7: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(item); ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); ZNetView val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ZNetView>() : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { int num = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize); while (stack > 0) { ItemData val3 = val.m_itemData.Clone(); val3.m_stack = Mathf.Min(stack, num); val3.m_dropPrefab = prefab; stack -= val3.m_stack; ZDO val4 = ZDOMan.instance.CreateNewZDO(pos, item); val4.Persistent = val2.m_persistent; val4.Type = val2.m_type; val4.Distant = val2.m_distant; val4.SetPrefab(item); val4.SetRotation(Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); ItemDrop.SaveToZDO(val3, val4, -1); } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }