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 Sproti v0.5.2
Sproti.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Sproti")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Sproti")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7b1c5e2a-9d34-4f86-a0e7-3c58d1f4b926")] [assembly: AssemblyFileVersion("0.5.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.2.0")] namespace Sproti; internal static class CheatCommands { private class FindTree : ConsoleCommand { public override string Name => "sproti_findtree"; public override string Help => "Ping your nearest Sproti tree on the map and list positions (with devcommands: all Sproti trees)"; public override bool IsCheat => false; public override void Run(string[] args) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { TreeLimit.Find(Player.m_localPlayer, ((Terminal)Console.instance).IsCheatsEnabled(), "Sproti_Tree"); } } } private class FindNursery : ConsoleCommand { public override string Name => "sproti_findnursery"; public override string Help => "Ping your Sproti's tree nursery on the map and list positions (with devcommands: all nurseries)"; public override bool IsCheat => false; public override void Run(string[] args) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { TreeLimit.Find(Player.m_localPlayer, ((Terminal)Console.instance).IsCheatsEnabled(), "Sproti_NurseryMarker"); } } } private class ReloadConfig : ConsoleCommand { public override string Name => "sproti_reload_config"; public override string Help => "Reload Sproti's config file after editing it"; public override bool IsCheat => false; public override void Run(string[] args) { ((BaseUnityPlugin)Sproti.Instance).Config.Reload(); Console.instance.Print("Sproti config reloaded"); } } private class RecipeAdd : ConsoleCommand { public override string Name => "sproti_recipe_add"; public override string Help => "Learn the Sproti tree (the nursery comes from the move-in scene)"; public override bool IsCheat => true; public override void Run(string[] args) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { RecipeUnlock.Learn(Player.m_localPlayer); } } } private class RecipeRemove : ConsoleCommand { public override string Name => "sproti_recipe_remove"; public override string Help => "Forget the Sproti tree and nursery, replay the move-in scene"; public override bool IsCheat => true; public override void Run(string[] args) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { RecipeUnlock.Forget(Player.m_localPlayer); } } } private class Free : ConsoleCommand { public override string Name => "sproti_free"; public override string Help => "Freed Sproti appears in front of you"; public override bool IsCheat => true; public override void Run(string[] args) { //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_0056: 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_005b: 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) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)GameCamera.instance)) { Vector3 val = ((Component)GameCamera.instance).transform.forward; val.y = 0f; val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : ((Component)localPlayer).transform.forward); FreedSproti.Spawn(((Component)localPlayer).transform.position + val * 3f, ((Component)localPlayer).transform.position, ((Component)localPlayer).transform.position, terrainOnly: false); } } } private class MoveIn : ConsoleCommand { public override string Name => "sproti_movein"; public override string Help => "Move-in scene in front of you"; public override bool IsCheat => true; public override void Run(string[] args) { //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_0056: 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_005b: 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) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)GameCamera.instance)) { Vector3 val = ((Component)GameCamera.instance).transform.forward; val.y = 0f; val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : ((Component)localPlayer).transform.forward); Vector3 val2 = ((Component)localPlayer).transform.position + val * 3f; FreedSproti.Spawn(val2, ((Component)localPlayer).transform.position, val2 + val * 3f, terrainOnly: false, moveIn: true); } } } public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RecipeAdd()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RecipeRemove()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new Free()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new MoveIn()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new FindTree()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new FindNursery()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ReloadConfig()); } } internal static class Cultivating { [HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")] private static class RegisterOp { private static void Prefix(ObjectDB __instance) { TerrainOp[] array = (TerrainOp[])(object)new TerrainOp[2] { s_op, s_smallOp }; foreach (TerrainOp val in array) { if (Object.op_Implicit((Object)(object)val) && !__instance.m_terrainOps.Contains(val)) { __instance.m_terrainOps.Add(val); } } } } public const string CultivatorItem = "Cultivator"; private const string VanillaOp = "cultivate_v2"; private const string OpPrefab = "Sproti_Cultivate"; private const float PaintRadius = 1.5f; private const string SmallOpPrefab = "Sproti_CultivateSmall"; private const float SmallPaintRadius = 0.5f; private const int SpotStep = 3; private const float BuildingDistance = 1.5f; private const float HouseRadius = 2.5f; private const float StandHeight = 0.5f; private const float StandRadius = 0.4f; private static TerrainOp s_op; private static TerrainOp s_smallOp; private static Piece s_vanillaPiece; private static int SpaceMask => LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); private static int StandMask => LayerMask.GetMask(new string[4] { "Default", "static_solid", "Default_small", "piece" }); public static void CreatePrefab() { s_op = CreateOp("Sproti_Cultivate", 1.5f); s_smallOp = (Object.op_Implicit((Object)(object)s_op) ? CreateOp("Sproti_CultivateSmall", 0.5f) : null); if (Object.op_Implicit((Object)(object)s_op)) { s_vanillaPiece = Cache.GetPrefab<GameObject>("cultivate_v2").GetComponent<Piece>(); } } private static TerrainOp CreateOp(string name, float paintRadius) { GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, "cultivate_v2"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<TerrainOp>())) { Sproti.Log.LogWarning((object)"terrain op cultivate_v2 not found, Sproti cannot cultivate"); return null; } foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList()) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } Object.DestroyImmediate((Object)(object)val.GetComponent<Piece>()); TerrainOp component = val.GetComponent<TerrainOp>(); Settings settings = component.m_settings; settings.m_smooth = false; settings.m_level = false; settings.m_raise = false; settings.m_paintRadius = paintRadius; settings.m_halfOffset = false; return component; } public static ItemData FindCultivator(Inventory inventory) { return ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => Object.op_Implicit((Object)(object)item.m_dropPrefab) && ((Object)item.m_dropPrefab).name == "Cultivator")); } public static IEnumerator FindSpots(SprotiTree tree, Func<Vector3, bool> blocked, List<Vector3> spots) { if (!Object.op_Implicit((Object)(object)s_op) || !Object.op_Implicit((Object)(object)s_smallOp)) { yield break; } Vector3 center = ((Component)tree).transform.position; int cx = Mathf.RoundToInt(center.x); int cz = Mathf.RoundToInt(center.z); float radius = tree.Radius; float reach = radius + 1.5f; int steps = Mathf.CeilToInt(reach / 3f); Vector3 val = default(Vector3); float y = default(float); for (int x = -steps; x <= steps; x++) { for (int z = -steps; z <= steps; z++) { if (SearchBudget.Exhausted) { yield return null; if (!Object.op_Implicit((Object)(object)tree)) { yield break; } } ((Vector3)(ref val))..ctor((float)(cx + x * 3), 0f, (float)(cz + z * 3)); if (Utils.DistanceXZ(val, center) <= reach && ZoneSystem.instance.GetGroundHeight(val, ref y)) { val.y = y; if (Paintable(val, tree, out var _).Count > 0 && FindStand(val, out var stand) && !blocked(stand)) { spots.Add(stand); } } } } } public static bool CultivateAt(SprotiTree tree, Vector3 stand) { //IL_001a: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00c2: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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 (!Object.op_Implicit((Object)(object)s_op) || !Object.op_Implicit((Object)(object)s_smallOp)) { return false; } Vector3 val = SpotOf(stand, ((Component)tree).transform.position); bool whole; List<Vector3> list = Paintable(val, tree, out whole); if (list.Count == 0) { return false; } if (whole) { Object.Instantiate<GameObject>(((Component)s_op).gameObject, val, Quaternion.identity); } else { foreach (Vector3 item in list) { Object.Instantiate<GameObject>(((Component)s_smallOp).gameObject, item, Quaternion.identity); } } if (Object.op_Implicit((Object)(object)s_vanillaPiece)) { s_vanillaPiece.m_placeEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } return true; } public static void CultivateUnderHouse(SprotiTree tree) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0075: 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_0091: 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_00a7: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_smallOp)) { return; } long creator = ((Component)tree).GetComponent<Piece>().GetCreator(); Vector3 position = ((Component)tree).transform.position; Vector3 val = default(Vector3); for (int i = Mathf.FloorToInt(position.x - 2.5f); i <= Mathf.CeilToInt(position.x + 2.5f); i++) { for (int j = Mathf.FloorToInt(position.z - 2.5f); j <= Mathf.CeilToInt(position.z + 2.5f); j++) { ((Vector3)(ref val))..ctor((float)i, 0f, (float)j); if (!(Utils.DistanceXZ(val, position) > 2.5f) && !DoorPath.Covers(((Component)tree).transform, val)) { val.y = ZoneSystem.instance.GetGroundHeight(val); if (!Protected(val, creator)) { Object.Instantiate<GameObject>(((Component)s_smallOp).gameObject, val, Quaternion.identity); } } } } } private static Vector3 SpotOf(Vector3 stand, Vector3 center) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0068: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(center.x); int num2 = Mathf.RoundToInt(center.z); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)(num + Mathf.RoundToInt((stand.x - (float)num) / 3f) * 3), 0f, (float)(num2 + Mathf.RoundToInt((stand.z - (float)num2) / 3f) * 3)); val.y = ZoneSystem.instance.GetGroundHeight(val); return val; } private static bool FindStand(Vector3 spot, out Vector3 stand) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) foreach (Vector3 item in from v in Vertices(spot) orderby Utils.DistanceXZ(v, spot) select v) { Vector3 val = (stand = item); stand.y = ZoneSystem.instance.GetGroundHeight(val); if (!Physics.CheckSphere(stand + Vector3.up * 0.5f, 0.4f, StandMask, (QueryTriggerInteraction)1) && !Planting.InsideSolid(stand)) { return true; } } stand = spot; return false; } private static IEnumerable<Vector3> Vertices(Vector3 spot) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) for (int x = -1; x <= 1; x++) { for (int z = -1; z <= 1; z++) { yield return spot + new Vector3((float)x, 0f, (float)z); } } } private static bool NeedsWork(Vector3 spot, Vector3 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_002f: Unknown result type (might be due to invalid IL or missing references) foreach (Vector3 item in Vertices(spot)) { Heightmap val = Heightmap.FindHeightmap(item); if (Object.op_Implicit((Object)(object)val) && Utils.DistanceXZ(item, center) <= radius && !val.IsCultivated(item)) { return true; } } return false; } private static List<Vector3> Paintable(Vector3 spot, SprotiTree tree, out bool whole) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0042: 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_005b: 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_005f: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_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) List<Vector3> list = new List<Vector3>(); whole = false; Vector3 position = ((Component)tree).transform.position; if (!NeedsWork(spot, position, tree.Radius)) { return list; } whole = true; long creator = ((Component)tree).GetComponent<Piece>().GetCreator(); bool flag = NearBuilding(spot, 3f, tree); foreach (Vector3 item in Vertices(spot)) { Vector3 val = item; val.y = ZoneSystem.instance.GetGroundHeight(item); if (Protected(val, creator) || SprotiHouse.OnPath(((Component)tree).transform.InverseTransformPoint(val), 0f) || DoorPath.Covers(((Component)tree).transform, val) || (flag && NearBuilding(val, 1.5f, tree)) || Planting.InsideSolid(val)) { whole = false; continue; } Heightmap val2 = Heightmap.FindHeightmap(item); if (!Object.op_Implicit((Object)(object)val2) || Utils.DistanceXZ(item, position) > tree.Radius) { whole = false; } else if (!val2.IsCultivated(item)) { list.Add(val); } } return list; } private static bool Protected(Vector3 ground, long creator) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!(ground.y < ZoneSystem.instance.m_waterLevel) && !Location.IsInsideNoBuildLocation(ground)) { return !Planting.CreatorHasWardAccess(creator, ground); } return true; } private static bool NearBuilding(Vector3 point, float distance, SprotiTree tree) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(point, distance, SpaceMask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { if (IsPlayerBuilding(array[i], tree)) { return true; } } return false; } private static bool IsPlayerBuilding(Collider collider, SprotiTree tree) { Piece componentInParent = ((Component)collider).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)componentInParent) || (Object)(object)((Component)componentInParent).gameObject == (Object)(object)((Component)tree).gameObject || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<Plant>()) || Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<TreeChest>())) { return false; } bool flag; switch (componentInParent.m_name) { case "$piece_woodfence": case "$piece_stonefence": case "$piece_woodfencegate": case "$piece_stakewall": case "$piece_dvergr_stake_wall": case "$piece_BlackwoodStakewall": flag = true; break; default: flag = false; break; } if (flag) { return false; } return componentInParent.IsPlacedByPlayer(); } } internal static class DoorPath { [HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")] private static class RegisterOp { private static void Prefix(ObjectDB __instance) { TerrainOp[] array = (TerrainOp[])(((object)s_ops) ?? ((object)new TerrainOp[0])); foreach (TerrainOp item in array) { if (!__instance.m_terrainOps.Contains(item)) { __instance.m_terrainOps.Add(item); } } } } private const string VanillaOp = "paved_road_v2"; private const float PaintRadius = 0.5f; private const float CentreAhead = 0.8f; private const float HalfWidth = 1f; private const float HalfLength = 1f; private static readonly (float limit, float strength)[] Rings = new(float, float)[3] { (0.7f, 1f), (1f, 0.6f), (1.3f, 0.55f) }; private static TerrainOp[] s_ops; private static Vector3 Centre => SprotiHouse.DoorOffset + Vector3.forward * 0.8f; public static void CreatePrefab() { s_ops = (TerrainOp[])(object)new TerrainOp[Rings.Length]; for (int i = 0; i < Rings.Length; i++) { GameObject val = PrefabManager.Instance.CreateClonedPrefab("Sproti_Pave" + i, "paved_road_v2"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<TerrainOp>())) { Sproti.Log.LogWarning((object)"terrain op paved_road_v2 not found, no path in front of Sproti's door"); s_ops = null; break; } foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList()) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } Object.DestroyImmediate((Object)(object)val.GetComponent<Piece>()); TerrainOp component = val.GetComponent<TerrainOp>(); Settings settings = component.m_settings; settings.m_smooth = false; settings.m_level = false; settings.m_raise = false; settings.m_halfOffset = false; settings.m_paintRadius = 0.5f; settings.m_paintStrength = Rings[i].strength; s_ops[i] = component; } } private static float EllipseDistance(Transform tree, Vector3 world) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0025: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_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) Vector3 val = tree.TransformPoint(Centre); Vector3 val2 = tree.InverseTransformDirection(new Vector3(world.x - val.x, 0f, world.z - val.z)); Vector2 val3 = new Vector2(val2.x / 1f, val2.z / 1f); return ((Vector2)(ref val3)).magnitude; } public static bool Covers(Transform tree, Vector3 vertex) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return EllipseDistance(tree, vertex) <= Rings[Rings.Length - 1].limit; } public static void Pave(Transform tree) { //IL_0009: 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_0013: 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_00ed: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00c6: Unknown result type (might be due to invalid IL or missing references) if (s_ops == null) { return; } Vector3 val = tree.TransformPoint(Centre); float num = Mathf.Max(1f, 1f) * Rings[Rings.Length - 1].limit; Vector3 val2 = default(Vector3); for (int i = Mathf.FloorToInt(val.x - num); i <= Mathf.CeilToInt(val.x + num); i++) { for (int j = Mathf.FloorToInt(val.z - num); j <= Mathf.CeilToInt(val.z + num); j++) { ((Vector3)(ref val2))..ctor((float)i, 0f, (float)j); float distance = EllipseDistance(tree, val2); int num2 = Array.FindIndex(Rings, ((float limit, float strength) r) => distance <= r.limit); if (num2 >= 0) { val2.y = ZoneSystem.instance.GetGroundHeight(val2); Object.Instantiate<GameObject>(((Component)s_ops[num2]).gameObject, val2, Quaternion.identity); } } } } } internal class FreedSproti : MonoBehaviour, Hoverable, Interactable { private enum Scene { Freed, MoveIn } private class SceneData { public string[] Lines; public SprotiFace.Expression[] Faces; public int TeachLine; public int OriginFrom = -1; public int OriginTo = -1; public bool PopOut; } [HarmonyPatch(typeof(Destructible), "Destroy")] private static class NestDestroyed { private static void Prefix(Destructible __instance, HitData hit) { //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_0036: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (hit == null) { return; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null && !(Utils.GetPrefabName(((Component)__instance).gameObject) != "Spawner_GreydwarfNest")) { Vector3 position = ((Component)__instance).transform.position; if (RecipeUnlock.AnyoneUnaware(position, 50f) && Random.value < 0.25f) { Sproti.Log.LogInfo((object)$"sproti freed from nest at {position}"); Spawn(TryFreeSpot(position, ((Component)val).transform.position, out var spot) ? spot : position, ((Component)val).transform.position, position, terrainOnly: true); } } } } public const string PrefabName = "Sproti_Freed"; private const string NestPrefab = "Spawner_GreydwarfNest"; private const string StartKey = "sproti_freed_start"; private const string LineKey = "sproti_freed_line"; private const string LineStartKey = "sproti_freed_line_start"; private const string OriginKey = "sproti_freed_origin"; private const string SceneKey = "sproti_scene"; private const string BuilderKey = "sproti_scene_builder"; private const string AbortedKey = "sproti_scene_aborted"; private const string AtTreeKey = "sproti_scene_at_tree"; private const float OrphanCheckDelay = 2f; private const string NextRpc = "Sproti_FreedNext"; private const float Chance = 0.25f; public const float Range = 50f; private const float AppearDelay = 2f; private const float NestDistance = 6f; private const float NestMaxAngle = 30f; private const int SpotTries = 12; private const float SpotRadius = 0.35f; private const float SpotClearance = 0.15f; private const int SpotSearchHeight = 30; private const string AppearSound = "sfx_lootspawn"; private const float RemoveDelay = 1f; private const float LineTimeout = 10f; private const float SilentTime = 1.5f; private const float TeachWindow = 5f; private const float TextCullDistance = 30f; private const float TurnSpeed = 90f; private const float OriginTurnSpeed = 360f; private const int GroundSearch = 3; private static readonly SceneData Freed = new SceneData { Lines = new string[4] { "$sproti_freed_1", "$sproti_freed_2", "$sproti_freed_3", "$sproti_freed_4" }, Faces = new SprotiFace.Expression[4] { SprotiFace.Expression.Idling, SprotiFace.Expression.Working, SprotiFace.Expression.Judging, SprotiFace.Expression.Working }, TeachLine = 4 }; private static readonly SceneData MoveIn = new SceneData { Lines = new string[7] { "$sproti_movein_1", null, "$sproti_movein_2", "$sproti_movein_3", "$sproti_movein_4", "$sproti_movein_5", "$sproti_movein_6" }, Faces = new SprotiFace.Expression[7] { SprotiFace.Expression.Idling, SprotiFace.Expression.Idling, SprotiFace.Expression.Judging, SprotiFace.Expression.Working, SprotiFace.Expression.Working, SprotiFace.Expression.Idling, SprotiFace.Expression.Judging }, TeachLine = 5, OriginFrom = 1, OriginTo = 2, PopOut = true }; private static readonly List<FreedSproti> s_moveIns = new List<FreedSproti>(); private ZNetView m_nview; private SceneData m_scene; private Vector3 m_origin; private Transform m_visual; private Collider m_collider; private SprotiFade m_fade; private SprotiFace m_face; private SprotiPuppet m_puppet; private bool m_appeared; private int m_shownLine = -1; private static int SpotMask => LayerMask.GetMask(new string[4] { "Default", "static_solid", "Default_small", "piece" }); private string[] Lines => m_scene.Lines; private static long Now => ZNet.instance.GetTime().Ticks; public static void CreatePrefab(GameObject creature) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateEmptyPrefab("Sproti_Freed", true); Object.DestroyImmediate((Object)(object)val.GetComponent<Collider>()); Object.DestroyImmediate((Object)(object)val.GetComponent<MeshRenderer>()); Object.DestroyImmediate((Object)(object)val.GetComponent<MeshFilter>()); ((Object)Object.Instantiate<Transform>(creature.transform.Find("Visual"), val.transform, false)).name = "Visual"; val.layer = LayerMask.NameToLayer("piece_nonsolid"); CapsuleCollider obj = val.AddComponent<CapsuleCollider>(); obj.radius = 0.35f; obj.height = 1.11216f; obj.center = new Vector3(0f, 0.55608f, 0f); val.AddComponent<FreedSproti>(); PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false)); } public static void Spawn(Vector3 position, Vector3 lookAt, Vector3 origin, bool terrainOnly, bool moveIn = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) float y = default(float); if (terrainOnly) { position.y = ZoneSystem.instance.GetGroundHeight(position); } else if (ZoneSystem.instance.GetSolidHeight(position, ref y, 3)) { position.y = y; } ZDO val = Create(position, lookAt, origin); if (moveIn && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { val.Set("sproti_scene", 1); val.Set("sproti_scene_builder", Player.m_localPlayer.GetPlayerID()); } } public static void SpawnMoveIn(SprotiTree tree) { //IL_0074: 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_008a: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || RecipeUnlock.HasSeenMoveIn(localPlayer)) { return; } foreach (FreedSproti s_moveIn in s_moveIns) { if (s_moveIn.m_nview.IsValid() && s_moveIn.m_nview.GetZDO().GetLong("sproti_scene_builder", 0L) == localPlayer.GetPlayerID()) { return; } } ZDO obj = Create(tree.HomePosition, ((Component)localPlayer).transform.position, ((Component)tree).transform.position); obj.Set("sproti_scene", 1); obj.Set("sproti_scene_builder", localPlayer.GetPlayerID()); obj.Set("sproti_scene_at_tree", true); } private static ZDO Create(Vector3 position, Vector3 lookAt, Vector3 origin) { //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_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_0022: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) Vector3 val = lookAt - position; val.y = 0f; Quaternion val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? Quaternion.LookRotation(val) : Quaternion.identity); ZDO zDO = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Sproti_Freed"), position, val2).GetComponent<ZNetView>().GetZDO(); zDO.Set("sproti_freed_origin", origin); return zDO; } public static bool MoveInAt(SprotiTree tree) { //IL_001e: 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) foreach (FreedSproti s_moveIn in s_moveIns) { if (Object.op_Implicit((Object)(object)tree) && Utils.DistanceXZ(s_moveIn.m_origin, ((Component)tree).transform.position) < 0.1f) { return true; } } return false; } private static float Seconds(long ticks) { return (float)ticks / 10000000f; } private static long Ticks(float seconds) { return (long)(seconds * 10000000f); } private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid()) { ZDO zDO = m_nview.GetZDO(); if (m_nview.IsOwner() && zDO.GetLong("sproti_freed_start", 0L) == 0L) { long num = Now + Ticks(2f); zDO.Set("sproti_freed_start", num); zDO.Set("sproti_freed_line", 0); zDO.Set("sproti_freed_line_start", num); } m_nview.Register<int>("Sproti_FreedNext", (Action<long, int>)RPC_Next); OwnerRemoval.Register(m_nview, Abort); m_visual = ((Component)this).transform.Find("Visual"); m_collider = ((Component)this).GetComponent<Collider>(); m_fade = new SprotiFade(((Component)this).transform.Find("Visual/Rig")); m_fade.Snap(visible: false); m_face = new SprotiFace(((Component)this).transform.Find("Visual/Rig")); m_puppet = ((Component)((Component)this).transform.Find("Visual/Rig")).GetComponent<SprotiPuppet>(); } } private void Start() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid()) { return; } ZDO zDO = m_nview.GetZDO(); bool flag = zDO.GetInt("sproti_scene", 0) == 1; m_scene = (flag ? MoveIn : Freed); m_origin = zDO.GetVec3("sproti_freed_origin", ((Component)this).transform.position); m_face.Set(m_scene.Faces[0]); if (flag) { s_moveIns.Add(this); if (zDO.GetBool("sproti_scene_at_tree", false)) { ((MonoBehaviour)this).Invoke("CheckOrphaned", 2f); } } } private void OnDestroy() { s_moveIns.Remove(this); m_fade?.Destroy(); if (Object.op_Implicit((Object)(object)Chat.instance)) { Chat.instance.ClearNpcText(((Component)this).gameObject); } } private void Update() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid() || m_scene == null) { return; } ZDO zDO = m_nview.GetZDO(); long num = zDO.GetLong("sproti_freed_start", 0L); if (num == 0L) { return; } float num2 = Seconds(Now - num); int num3 = zDO.GetInt("sproti_freed_line", 0); float num4 = Seconds(Now - zDO.GetLong("sproti_freed_line_start", 0L)); bool flag = num3 < Lines.Length; if (num2 >= 0f && !m_appeared) { m_appeared = true; if (m_nview.IsOwner() && num2 < 1f) { NetSound.Play("sfx_lootspawn", ((Component)this).transform.position); } } bool flag2 = num2 >= 0f && flag; if (flag2 != m_fade.Alpha > 0f) { m_fade.Snap(flag2); } m_collider.enabled = flag2; bool toOrigin = num3 >= m_scene.OriginFrom && num3 <= m_scene.OriginTo; Turn(toOrigin, m_scene.OriginFrom >= 0 && num3 >= m_scene.OriginFrom && num3 <= m_scene.OriginTo + 1); if (num4 >= 0f && num3 != m_shownLine) { if (flag) { if (Lines[num3] != null) { Say(Lines[num3]); } else if (Object.op_Implicit((Object)(object)Chat.instance)) { Chat.instance.ClearNpcText(((Component)this).gameObject); } m_face.Set(m_scene.Faces[num3]); } else { if (Object.op_Implicit((Object)(object)Chat.instance)) { Chat.instance.ClearNpcText(((Component)this).gameObject); } if (num4 < 1f && num2 >= 0f && m_scene.PopOut) { NetSound.Play("sfx_pickable_pick", ((Component)this).transform.position, local: true, 1f, 2f); } else if (num4 < 1f && num2 >= 0f && m_nview.IsOwner()) { NetSound.Play("sfx_lootspawn", ((Component)this).transform.position); } } bool flag3 = zDO.GetBool("sproti_scene_aborted", false); if (num3 >= m_scene.TeachLine && num4 < 5f && !flag3) { Teach(); } Player localPlayer = Player.m_localPlayer; if (!flag && m_scene == MoveIn && num4 < 5f && !flag3 && Object.op_Implicit((Object)(object)localPlayer) && localPlayer.GetPlayerID() == zDO.GetLong("sproti_scene_builder", 0L) && RecipeUnlock.IsNurseryKnown(localPlayer)) { RecipeUnlock.MarkMoveInSeen(localPlayer); } m_shownLine = num3; } if (m_nview.IsOwner()) { if (flag && num4 >= ((Lines[num3] != null) ? 10f : 1.5f)) { Advance(num3); } else if (!flag && num4 >= 1f) { m_nview.Destroy(); } } } private void Turn(bool toOrigin, bool fast) { //IL_003f: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)m_visual)) { m_puppet.LookTarget = (Character)(object)(toOrigin ? null : localPlayer); Vector3 val = (toOrigin ? m_origin : ((Component)localPlayer).transform.position) - m_visual.position; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f)) { m_visual.rotation = Quaternion.RotateTowards(m_visual.rotation, Quaternion.LookRotation(val), (fast ? 360f : 90f) * Time.deltaTime); } } } public static void TreeRemoved(SprotiTree tree) { //IL_0016: 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) foreach (FreedSproti s_moveIn in s_moveIns) { if (Utils.DistanceXZ(s_moveIn.m_origin, ((Component)tree).transform.position) < 0.1f) { OwnerRemoval.Request(s_moveIn.m_nview); } } } private void CheckOrphaned() { //IL_0028: 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) if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid() && m_nview.IsOwner() && SprotiTree.IsLoaded(m_origin) && !Object.op_Implicit((Object)(object)SprotiTree.FindAt(m_origin))) { Abort(); } } private void Abort() { ZDO zDO = m_nview.GetZDO(); if (zDO.GetInt("sproti_freed_line", 0) < Lines.Length) { zDO.Set("sproti_scene_aborted", true); zDO.Set("sproti_freed_line", Lines.Length); zDO.Set("sproti_freed_line_start", Now); } } private void Advance(int line) { ZDO zDO = m_nview.GetZDO(); if (zDO.GetInt("sproti_freed_line", 0) == line && line < Lines.Length && !(Seconds(Now - zDO.GetLong("sproti_freed_line_start", 0L)) < 0f)) { zDO.Set("sproti_freed_line", line + 1); zDO.Set("sproti_freed_line_start", Now); } } private void RPC_Next(long sender, int line) { if (m_nview.IsOwner()) { Advance(line); } } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || !m_nview.IsValid() || m_shownLine < 0 || m_shownLine >= Lines.Length) { return false; } m_nview.InvokeRPC("Sproti_FreedNext", new object[1] { m_shownLine }); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { if (m_shownLine < 0 || m_shownLine >= Lines.Length) { return ""; } return Localization.instance.Localize("$sproti_creature\n[<color=yellow><b>$KEY_Use</b></color>] $sproti_freed_next"); } public string GetHoverName() { return Localization.instance.Localize("$sproti_creature"); } public float GetHoverOffset() { return 0f; } private void Say(string text) { //IL_0017: 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) if (Object.op_Implicit((Object)(object)Chat.instance)) { Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 1.51216f, 30f, 10f, "$sproti_creature", text, false); } } private void Teach() { //IL_0014: 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) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && !(Vector3.Distance(((Component)localPlayer).transform.position, m_origin) > 50f)) { if (m_scene == Freed && !RecipeUnlock.IsKnown(localPlayer)) { RecipeUnlock.Learn(localPlayer); } else if (m_scene == MoveIn && !RecipeUnlock.IsNurseryKnown(localPlayer)) { RecipeUnlock.LearnNursery(localPlayer); } } } private static bool TryFreeSpot(Vector3 nest, Vector3 attacker, out Vector3 spot) { //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_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_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_0060: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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) //IL_009f: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) Vector3 val = nest - attacker; val.y = 0f; val = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward); spot = nest; float num2 = default(float); for (int i = 0; i < 12; i++) { spot = nest + Quaternion.Euler(0f, Random.Range(-30f, 30f), 0f) * val * 6f; spot.y = ZoneSystem.instance.GetGroundHeight(spot); Vector3 val2 = spot + Vector3.up * 0.5f; Vector3 val3 = spot + Vector3.up * 0.76215994f; bool num = ZoneSystem.instance.GetSolidHeight(spot, ref num2, 30) && num2 > spot.y + 0.15f; bool flag = spot.y < ZoneSystem.instance.m_waterLevel; if (!num && !flag && !Physics.CheckCapsule(val2, val3, 0.35f, SpotMask)) { return true; } } return false; } } internal static class Harvesting { [HarmonyPatch(typeof(Pickable), "RPC_Pick")] private static class ServerPickEffects { private static ZDOID EffectSource() { //IL_0015: 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) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return ZDOID.None; } return ((Character)localPlayer).GetZDOID(); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: 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_0034: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown return new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Player), "m_localPlayer"), (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Character), "GetZDOID", (Type[])null, (Type[])null), (string)null) }).ThrowIfInvalid("Pickable.RPC_Pick local player effect source not found").Set(OpCodes.Call, (object)AccessTools.Method(typeof(ServerPickEffects), "EffectSource", (Type[])null, (Type[])null)) .Advance(1) .Set(OpCodes.Nop, (object)null) .InstructionEnumeration(); } } [HarmonyPatch(typeof(Pickable), "Awake")] private static class RegisterPickable { private static void Postfix(Pickable __instance) { s_pickables.Add(__instance); } } private static readonly HashSet<Pickable> s_pickables = new HashSet<Pickable>(); internal static List<GameObject> CultivatorPieces() { return ObjectDB.instance.GetItemPrefab("Cultivator").GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces.m_pieces; } private static HashSet<string> CropPickableNames() { HashSet<string> hashSet = new HashSet<string>(); foreach (GameObject item in CultivatorPieces()) { Plant component = item.GetComponent<Plant>(); if (!Object.op_Implicit((Object)(object)component) || !component.m_needCultivatedGround) { continue; } GameObject[] grownPrefabs = component.m_grownPrefabs; foreach (GameObject val in grownPrefabs) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<Pickable>())) { hashSet.Add(((Object)val).name); } } } return hashSet; } public static IEnumerator Candidates(SprotiTree tree, Inventory output, Func<Vector3, bool> blocked, List<Pickable> result) { HashSet<string> crops = CropPickableNames(); s_pickables.RemoveWhere((Pickable val) => !Object.op_Implicit((Object)(object)val)); List<Pickable> list = s_pickables.ToList(); foreach (Pickable p in list) { if (SearchBudget.Exhausted) { yield return null; if (!Object.op_Implicit((Object)(object)tree)) { yield break; } } if (Object.op_Implicit((Object)(object)p) && ((Component)p).gameObject.activeInHierarchy && Utils.DistanceXZ(((Component)p).transform.position, ((Component)tree).transform.position) <= tree.Radius && Object.op_Implicit((Object)(object)p.m_nview) && p.m_nview.IsValid() && Object.op_Implicit((Object)(object)p.m_itemPrefab) && IsPlant(p, crops) && p.CanBePicked() && !blocked(((Component)p).transform.position) && Fits(output, MaxYield(p))) { result.Add(p); } } } private static bool IsPlant(Pickable pickable, HashSet<string> crops) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)pickable.m_pickRaiseSkill != 106) { return crops.Contains(Utils.GetPrefabName(((Component)pickable).gameObject)); } return true; } public static GameObject ChooseSort(List<Pickable> candidates, Inventory output, Vector3 from) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Pickable val = (from p in candidates orderby (output.FindFreeStackSpace(ItemName(p.m_itemPrefab), (float)Game.m_worldLevel) <= 0) ? 1 : 0, Vector3.Distance(((Component)p).transform.position, @from) select p).FirstOrDefault(); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.m_itemPrefab; } public static Pickable TakeNearest(List<Pickable> candidates, SprotiTree tree, Inventory output, Vector3 from, Func<Vector3, bool> blocked) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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) candidates.RemoveAll((Pickable p) => !Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)p.m_nview) || !p.m_nview.IsValid() || !p.CanBePicked() || Utils.DistanceXZ(((Component)p).transform.position, ((Component)tree).transform.position) > tree.Radius || blocked(((Component)p).transform.position)); int num = -1; float num2 = float.MaxValue; for (int num3 = 0; num3 < candidates.Count; num3++) { Vector3 val = ((Component)candidates[num3]).transform.position - from; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num2 && YieldFits(candidates[num3], output)) { num = num3; num2 = sqrMagnitude; } } if (num < 0) { return null; } Pickable result = candidates[num]; candidates.RemoveAt(num); return result; } public static string SortName(GameObject sort) { return Localization.instance.Localize(ItemName(sort)); } private static string ItemName(GameObject item) { return item.GetComponent<ItemDrop>().m_itemData.m_shared.m_name; } private static Dictionary<GameObject, int> MaxYield(Pickable pickable) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_0097: 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_00c2: Unknown result type (might be due to invalid IL or missing references) Dictionary<GameObject, int> dictionary = new Dictionary<GameObject, int>(); int value = (pickable.m_dontScale ? pickable.m_amount : Mathf.Max(pickable.m_minAmountScaled, Game.instance.ScaleDrops(pickable.m_itemPrefab, pickable.m_amount))); dictionary[pickable.m_itemPrefab] = value; DropTable extraDrops = pickable.m_extraDrops; if (!extraDrops.IsEmpty()) { float num = Mathf.Max(1f, Game.m_resourceRate); int num2 = extraDrops.m_dropMax * Mathf.CeilToInt(num); foreach (DropData drop in extraDrops.m_drops) { int num3 = (drop.m_dontScale ? drop.m_stackMax : Mathf.CeilToInt((float)drop.m_stackMax * num)); dictionary.TryGetValue(drop.m_item, out var value2); dictionary[drop.m_item] = value2 + num3 * num2; } } return dictionary; } public static bool YieldFits(Pickable pickable, Inventory output) { return Fits(output, MaxYield(pickable)); } private static bool Fits(Inventory inventory, Dictionary<GameObject, int> maxYield) { int num = 0; foreach (KeyValuePair<GameObject, int> item in maxYield) { ItemData itemData = item.Key.GetComponent<ItemDrop>().m_itemData; int num2 = Mathf.Max(0, item.Value - inventory.FindFreeStackSpace(itemData.m_shared.m_name, (float)Game.m_worldLevel)); int num3 = Mathf.Max(1, itemData.m_shared.m_maxStackSize); num += (num2 + num3 - 1) / num3; } return num <= inventory.GetEmptySlots(); } public static bool Harvest(Pickable pickable, Container output) { Inventory inventory = output.GetInventory(); if (pickable.m_picked || !pickable.CanBePicked() || !Fits(inventory, MaxYield(pickable))) { return false; } HashSet<ItemDrop> before = new HashSet<ItemDrop>(ItemDrop.s_instances); pickable.m_nview.InvokeRPC("RPC_Pick", new object[1] { 0 }); foreach (ItemDrop item in ItemDrop.s_instances.Where((ItemDrop d) => Object.op_Implicit((Object)(object)d) && !before.Contains(d)).ToList()) { if (item.m_nview.IsOwner() && inventory.CanAddItem(item.m_itemData, item.m_itemData.m_stack) && inventory.AddItem(item.m_itemData)) { ZNetScene.instance.Destroy(((Component)item).gameObject); } else { Sproti.Log.LogDebug((object)$"harvest overflow {item.m_itemData.m_shared.m_name} x{item.m_itemData.m_stack} stays on the ground"); } } return true; } } internal static class NetSound { public const string Pop = "sfx_pickable_pick"; public const float PopPitch = 2f; private static readonly HashSet<string> s_missing = new HashSet<string>(); public static void Play(string prefab, Vector3 position, bool local = false, float volume = 1f, float pitch = 1f) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefab) : null); if (!Object.op_Implicit((Object)(object)val) && local) { val = Cache.GetPrefab<GameObject>(prefab); } if (!Object.op_Implicit((Object)(object)val)) { if (s_missing.Add(prefab)) { Sproti.Log.LogWarning((object)("sound " + prefab + " not found")); } return; } ZNetView.m_forceDisableInit = local; try { GameObject val2 = Object.Instantiate<GameObject>(val, position, Quaternion.identity); CamShaker[] componentsInChildren = val2.GetComponentsInChildren<CamShaker>(); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } ZSFX component = val2.GetComponent<ZSFX>(); if (component != null) { component.SetVolumeModifier(volume); component.SetPitchModifier(pitch); } } finally { ZNetView.m_forceDisableInit = false; } } } internal static class NurseryLimit { internal struct Info { public bool HasTree; public bool HasNursery; public bool Active; } [HarmonyPatch(typeof(Game), "Start")] private static class Register { private static void Postfix() { ZRoutedRpc.instance.Register<long>("Sproti_NurseryInfo", (Action<long, long>)RPC_Info); ZRoutedRpc.instance.Register<long, int>("Sproti_NurseryInfoAnswer", (Action<long, long, int>)RPC_InfoAnswer); s_info.Clear(); s_asked.Clear(); s_pending.Clear(); s_placedTime = float.MinValue; s_selected = false; } } [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] private static class NurserySelected { private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Piece selectedPiece = __instance.GetSelectedPiece(); int num; if (((Character)__instance).InPlaceMode() && Object.op_Implicit((Object)(object)selectedPiece)) { num = (Object.op_Implicit((Object)(object)((Component)selectedPiece).GetComponent<NurseryMarker>()) ? 1 : 0); if (num != 0 && !s_selected) { Ask(__instance.GetPlayerID()); } } else { num = 0; } s_selected = (byte)num != 0; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class Placed { private static void Postfix(Player __instance, Piece piece, bool __result) { if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)((Component)piece).GetComponent<NurseryMarker>())) { s_placedTime = Time.time; s_info[__instance.GetPlayerID()] = new Info { HasTree = true, HasNursery = true, Active = true }; } } } [HarmonyPatch(typeof(WearNTear), "Remove")] private static class Removed { private static void Prefix(WearNTear __instance) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid()) { NurseryMarker component = ((Component)__instance).GetComponent<NurseryMarker>(); if (Object.op_Implicit((Object)(object)component) && component.Creator == localPlayer.GetPlayerID()) { s_placedTime = float.MinValue; ((MonoBehaviour)localPlayer).StartCoroutine(AskLater(component.Creator)); } SprotiTree component2 = ((Component)__instance).GetComponent<SprotiTree>(); if (Object.op_Implicit((Object)(object)component2) && ((Component)component2).GetComponent<TreeNursery>().HasArea) { ((Character)localPlayer).Message((MessageType)2, "$msg_sproti_nursery_now_inactive", 0, (Sprite)null, false); } } } } private const string RequestName = "Sproti_NurseryInfo"; private const string AnswerName = "Sproti_NurseryInfoAnswer"; private const float PlacedGrace = 5f; private const float RemovedDelay = 2f; private const float RefreshTime = 10f; private const float RefusedInterval = 2f; private const float AnswerTimeout = 5f; private const int TreeFlag = 1; private const int NurseryFlag = 2; private const int ActiveFlag = 4; private static readonly Dictionary<long, Info> s_info = new Dictionary<long, Info>(); private static readonly Dictionary<long, float> s_asked = new Dictionary<long, float>(); private static readonly HashSet<long> s_pending = new HashSet<long>(); private static float s_placedTime = float.MinValue; private static bool s_selected; internal static bool Get(long creator, out Info info) { if (!s_asked.TryGetValue(creator, out var value) || Time.time - value > 10f) { Ask(creator); } return s_info.TryGetValue(creator, out info); } private static void Ask(long creator, bool force = false) { if (ZRoutedRpc.instance != null && (force || !s_pending.Contains(creator) || !(Time.time - s_asked[creator] < 5f))) { s_asked[creator] = Time.time; s_pending.Add(creator); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "Sproti_NurseryInfo", new object[1] { creator }); } } private static IEnumerator AskLater(long creator) { yield return (object)new WaitForSeconds(2f); Ask(creator, force: true); } internal static string Problem(Player player) { long playerID = player.GetPlayerID(); bool flag = false; bool flag2 = false; foreach (NurseryMarker item in NurseryMarker.Of(playerID)) { flag = true; flag2 |= item.IsActive; } if (!flag) { if (!s_info.TryGetValue(playerID, out var value)) { Ask(playerID); return "$msg_sproti_nursery_checking"; } flag = value.HasNursery; flag2 = value.Active; } if (flag) { if (!flag2) { return "$msg_sproti_nursery_inactive_exists"; } return "$msg_sproti_nursery_exists"; } return null; } internal static void Refused(Player player) { long playerID = player.GetPlayerID(); if (!s_asked.TryGetValue(playerID, out var value) || Time.time - value >= 2f) { Ask(playerID); } } private static void RPC_Info(long sender, long creator) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) int stableHashCode = StringExtensionMethods.GetStableHashCode("Sproti_Tree"); int stableHashCode2 = StringExtensionMethods.GetStableHashCode("Sproti_NurseryMarker"); List<Vector3> trees = new List<Vector3>(); List<Vector3> list = new List<Vector3>(); foreach (ZDO value in ZDOMan.instance.m_objectsByID.Values) { int prefab = value.GetPrefab(); if ((prefab == stableHashCode || prefab == stableHashCode2) && value.GetLong(ZDOVars.s_creator, 0L) == creator) { ((prefab == stableHashCode) ? trees : list).Add(value.GetPosition()); } } bool flag = list.Exists((Vector3 marker) => trees.Exists((Vector3 tree) => Utils.DistanceXZ(marker, tree) <= 32f)); int num = (int)(((trees.Count > 0) ? 1u : 0u) | (uint)((list.Count > 0) ? 2 : 0)) | (flag ? 4 : 0); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Sproti_NurseryInfoAnswer", new object[2] { creator, num }); } private static void RPC_InfoAnswer(long sender, long creator, int flags) { s_pending.Remove(creator); Info value = new Info { HasTree = ((flags & 1) != 0), HasNursery = ((flags & 2) != 0), Active = ((flags & 4) != 0) }; Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && creator == localPlayer.GetPlayerID() && !value.HasNursery && Time.time - s_placedTime <= 5f && s_info.TryGetValue(creator, out var value2)) { value.HasNursery = value2.HasNursery; value.Active = value2.Active; } s_info[creator] = value; } } internal class NurseryMarker : MonoBehaviour, Interactable, Hoverable { private static readonly List<NurseryMarker> Instances = new List<NurseryMarker>(); private ZNetView m_nview; private Piece m_piece; private CircleProjector[] m_circles; private readonly SprotiMap m_map = new SprotiMap("Sproti.map_icon_nursery.png", moves: false); private SprotiTree m_home; private int m_homeVersion = -1; internal bool Alive { get { if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid()) { return m_nview.GetZDO().GetFloat(ZDOVars.s_health, 1000f) > 0f; } return false; } } internal long Creator => m_piece.GetCreator(); internal bool IsActive => Object.op_Implicit((Object)(object)Home); private SprotiTree Home { get { if (!Alive) { return null; } return CachedHome(); } } internal static IEnumerable<NurseryMarker> All => Instances.Where((NurseryMarker marker) => marker.Alive); private SprotiTree CachedHome() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (m_homeVersion != SprotiTree.HomesVersion || (Object.op_Implicit((Object)(object)m_home) && !m_home.IsValid)) { m_homeVersion = SprotiTree.HomesVersion; m_home = NearestInRange<SprotiTree>(SprotiTree.Instances.Where((SprotiTree tree) => tree.IsValid && Builder(tree) == Creator), ((Component)this).transform.position); } return m_home; } private static long Builder(SprotiTree tree) { return ((Component)tree).GetComponent<Piece>().GetCreator(); } private static T NearestInRange<T>(IEnumerable<T> candidates, Vector3 position) where T : Component { //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) return (from c in candidates select (c: c, distance: Utils.DistanceXZ(((Component)c).transform.position, position)) into c where c.distance <= 32f orderby c.distance select c.c).FirstOrDefault(); } internal static NurseryMarker FindFor(SprotiTree home) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)home) && home.IsValid) { return NearestInRange<NurseryMarker>(Instances.Where((NurseryMarker marker) => marker.Alive && marker.Creator == Builder(home)), ((Component)home).transform.position); } return null; } internal static IEnumerable<NurseryMarker> Of(long creator) { return Instances.Where((NurseryMarker marker) => marker.Alive && marker.Creator == creator); } private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); m_piece = ((Component)this).GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid()) { m_circles = ((Component)this).GetComponentsInChildren<CircleProjector>(true); Instances.Add(this); SprotiTree.HomesVersion++; } } private void OnDestroy() { if (Instances.Remove(this)) { SprotiTree.HomesVersion++; } m_map.Remove(); } private void Update() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (m_circles == null) { return; } m_map.Update((Alive && Sproti.MapHomes.Value) ? m_piece : null, ((Component)this).transform.position); SprotiTree home = Home; bool flag = Object.op_Implicit((Object)(object)home) && home.MarkersVisible; CircleProjector[] circles = m_circles; foreach (CircleProjector val in circles) { if (((Component)val).gameObject.activeSelf != flag) { ((Component)val).gameObject.SetActive(flag); } } } public bool Interact(Humanoid user, bool hold, bool alt) { SprotiTree home = Home; if (hold || !alt || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)home)) { return false; } home.ShowAreas(); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { string text = SprotiTree.WithBuilder(m_piece.m_name, m_nview); SprotiTree home = Home; if (Object.op_Implicit((Object)(object)home)) { text += TreePerks.HoverLines(home.Perks & 2); text += "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $sproti_show_radius"; } else { NurseryLimit.Info info; bool flag = SprotiTree.Instances.Any((SprotiTree tree) => tree.IsValid && Builder(tree) == Creator) || (NurseryLimit.Get(Creator, out info) && info.HasTree); text = text + "\n<color=red>$sproti_inactive (" + (flag ? "$sproti_too_far" : "$sproti_no_tree") + ")</color>"; } return Localization.instance.Localize(text); } public string GetHoverName() { return Localization.instance.Localize(m_piece.m_name); } public float GetHoverOffset() { return 0f; } } internal static class OwnerRemoval { private const string Rpc = "Sproti_Remove"; private const int MaxHops = 3; public static void Register(ZNetView nview, Action remove) { nview.Register<int>("Sproti_Remove", (Action<long, int>)delegate(long sender, int hops) { Handle(nview, remove, hops); }); } public static void Request(ZNetView nview) { if (Object.op_Implicit((Object)(object)nview) && nview.IsValid()) { nview.InvokeRPC("Sproti_Remove", new object[1] { 0 }); } } private static void Handle(ZNetView nview, Action remove, int hops) { if (nview.IsValid()) { if (nview.IsOwner()) { remove(); } else if (nview.GetZDO().GetOwner() != 0L && hops < 3) { nview.InvokeRPC("Sproti_Remove", new object[1] { hops + 1 }); } } } } internal static class OwnershipRpc { [HarmonyPatch(typeof(Game), "Start")] private static class Register { private static void Postfix() { ZRoutedRpc.instance.Register<ZDOID>("Sproti_RequestOwn", (Action<long, ZDOID>)RPC_RequestOwn); } } private const string Name = "Sproti_RequestOwn"; public static void Request(ZNetView nview) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (nview.IsValid() && !nview.IsOwner()) { ZDO zDO = nview.GetZDO(); if (!zDO.HasOwner()) { nview.ClaimOwnership(); return; } ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "Sproti_RequestOwn", new object[1] { zDO.m_uid }); } } private static void RPC_RequestOwn(long sender, ZDOID id) { //IL_0005: 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_004d: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(id); if (zDO != null && zDO.IsOwner()) { GameObject val = ZNetScene.instance.FindInstance(id); Container val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Container>() : null); if (!Object.op_Implicit((Object)(object)val2) || !val2.IsInUse()) { ZDOMan.instance.ForceSendZDO(sender, id); zDO.SetOwner(sender); } } } } internal static class Planting { public enum Result { Planted, SpotTaken, NoMaterial } private struct Candidate { public Vector3 Position; public Heightmap Heightmap; public bool? GroundUsable; } public sealed class Plan { public Piece Piece; public List<Vector3> Spots; } private const float GridStep = 0.5f; private const float ColliderReach = 0.5f; private const float EdgePadding = 0.5f; private const int EdgeSamples = 8; private const int BudgetCheckEvery = 16; private static int s_roofMask; private static int s_spaceMask; private static Collider[] s_hits = (Collider[])(object)new Collider[64]; private const float RoofHeight = 100f; private const float SolidClearance = 0.2f; private static int s_rockMask; private static int RoofMask { get { if (s_roofMask == 0) { return s_roofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); } return s_roofMask; } } private static int SpaceMask { get { if (s_spaceMask == 0) { return s_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); } return s_spaceMask; } } private static int RockMask { get { if (s_rockMask == 0) { return s_rockMask = LayerMask.GetMask(new string[2] { "Default", "static_solid" }); } return s_rockMask; } } private static int Overlap(Vector3 pos, float radius) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) int result; while ((result = Physics.OverlapSphereNonAlloc(pos, radius, s_hits, SpaceMask)) == s_hits.Length) { s_hits = (Collider[])(object)new Collider[s_hits.Length * 2]; } return result; } private static List<Piece> PlantablePieces() { List<Piece> list = new List<Piece>(); foreach (GameObject item in Harvesting.CultivatorPieces()) { Piece component = item.GetComponent<Piece>(); Plant component2 = item.GetComponent<Plant>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && component2.m_needCultivatedGround && component2.m_attachDistance <= 0f && component2.m_growRadiusVines <= 0f && component.m_resources.Length == 1 && Object.op_Implicit((Object)(object)component.m_resources[0].m_resItem)) { list.Add(component); } } list.AddRange(TreeRegrowth.Saplings); return list; } private static Requirement Material(Piece piece) { return piece.m_resources[0]; } private static string MaterialName(Piece piece) { return Material(piece).m_resItem.m_itemData.m_shared.m_name; } internal static bool IsTreeSeed(string itemName) { return TreeRegrowth.Saplings.Exists((Piece piece) => MaterialName(piece) == itemName); } public static string MaterialPrefab(Piece piece) { return ((Object)Material(piece).m_resItem).name; } internal static bool IsTreeThought(string thought) { return TreeRegrowth.Saplings.Exists((Piece piece) => thought == SprotiThought.Plant(MaterialPrefab(piece))); } private static ItemData MaterialSlot(Inventory inventory, Piece piece) { ItemData val = ((IEnumerable<ItemData>)SlotOrder(inventory)).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => item.m_shared.m_name == MaterialName(piece))); if (val == null || val.m_stack < Material(piece).m_amount) { return null; } return val; } public static bool HasMaterial(Container input, Piece piece) { return MaterialSlot(input.GetInventory(), piece) != null; } public static string ThoughtItem(Piece piece) { if (TreeRegrowth.Saplings.Contains(piece)) { return MaterialPrefab(piece); } Pickable val = (from prefab in ((Component)piece).GetComponent<Plant>().m_grownPrefabs where Object.op_Implicit((Object)(object)prefab) select prefab.GetComponent<Pickable>()).FirstOrDefault((Func<Pickable, bool>)((Pickable pickable) => Object.op_Implicit((Object)(object)pickable) && Object.op_Implicit((Object)(object)pickable.m_itemPrefab))); if (!Object.op_Implicit((Object)(object)val)) { return MaterialPrefab(piece); } return ((Object)val.m_itemPrefab).name; } public static bool WontGrowAt(SprotiTree tree, string itemName) { //IL_0039: 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) Piece val = ((IEnumerable<Piece>)PlantablePieces()).FirstOrDefault((Func<Piece, bool>)((Piece p) => MaterialName(p) == itemName)); if (TreeRegrowth.Saplings.Contains(val)) { return false; } Heightmap val2 = Heightmap.FindHeightmap(((Component)tree).transform.position); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2)) { return !ClimateFits(((Component)val).GetComponent<Plant>(), val2, ((Component)tree).transform.position); } return false; } public static IEnumerator PlanRound(SprotiTree tree, Inventory input, Func<Vector3, bool> blocked, Plan plan) { List<Piece> pieces = PlantablePieces(); float maxGrowRadius = ((pieces.Count > 0) ? pieces.Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius) : 0f); Heightmap treeHeightmap = Heightmap.FindHeightmap(((Component)tree).transform.position); List<ItemData> items = SlotOrder(input); List<Candidate> cropCandidates = null; List<Candidate> treeCandidates = null; TreeNursery nursery = ((Component)tree).GetComponent<TreeNursery>(); long creator = ((Component)tree).GetComponent<Piece>().GetCreator(); HashSet<Piece> tried = new HashSet<Piece>(); Dictionary<Vector2s, bool> zonesReady = new Dictionary<Vector2s, bool>(); foreach (ItemData item in items) { Piece piece = ((IEnumerable<Piece>)pieces).FirstOrDefault((Func<Piece, bool>)((Piece p) => MaterialName(p) == item.m_shared.m_name)); if (!Object.op_Implicit((Object)(object)piece) || !tried.Add(piece)) { continue; } Plant component = ((Component)piece).GetComponent<Plant>(); bool flag = TreeRegrowth.Saplings.Contains(piece); if (flag ? (!nursery.HasArea) : (!Object.op_Implicit((Object)(object)treeHeightmap) || !ClimateFits(component, treeHeightmap, ((Component)tree).transform.position))) { continue; } int num = RunAmount(items, item) / Mathf.Max(1, Material(piece).m_amount); if (num <= 0) { continue; } List<Candidate> list; if (!flag) { list = cropCandidates; if (list == null) { List<Candidate> list2; cropCandidates = (list2 = Grid(tree)); list = list2; } } else { list = treeCandidates; if (list == null) { List<Candidate> list2; treeCandidates = (list2 = NurseryGrid(tree, nursery)); list = list2; } } List<Candidate> candidates = list; Vector3 areaCenter = (flag ? nursery.Center : ((Component)tree).transform.position); float areaRadius = (flag ? 15f : tree.Radius); List<Vector3> spots = new List<Vector3>(); IEnumerator find = FindSpots(tree, piece, maxGrowRadius, num, blocked, creator, candidates, areaCenter, areaRadius, zonesReady, spots); while (find.MoveNext()) { yield return null; } if (!Object.op_Implicit((Object)(object)tree)) { yield break; } if (spots.Count > 0) { plan.Piece = piece; plan.Spots = spots; yield break; } } } private static List<ItemData> SlotOrder(Inventory inventory) { return (from item in inventory.GetAllItems() where item.m_worldLevel == Game.m_worldLevel orderby item.m_gridPos.y, item.m_gridPos.x select item).ToList(); } public static bool IsFront(Container input, Piece piece) { ItemData val = MaterialSlot(input.GetInventory(), piece); if (val != null) { return SlotOrder(input.GetInventory()).FirstOrDefault() == val; } return false; } private static int RunAmount(List<ItemData> items, ItemData first) { int num = 0; for (int i = items.IndexOf(first); i < items.Count && items[i].m_shared.m_name == first.m_shared.m_name; i++) { num += items[i].m_stack; } return num; } private static List<Candidate> Grid(SprotiTree tree) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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) Vector3 center = ((Component)tree).transform.position; float radius = tree.Radius; int num = Mathf.FloorToInt(radius / 0.5f); List<Candidate> list = new List<Candidate>(); Vector3 val = default(Vector3); for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { ((Vector3)(ref val))..ctor((float)i * 0.5f, 0f, (float)j * 0.5f); if (((Vector3)(ref val)).sqrMagnitude <= radius * radius) { list.Add(new Candidate { Position = center + val }); } } } return list.OrderBy(delegate(Candidate c) { //IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = c.Position - center; return ((Vector3)(ref val2)).sqrMagnitude; }).ToList(); } private static List<Candidate> NurseryGrid(SprotiTree tree, TreeNursery nursery) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) List<Candidate> list = new List<Candidate>(); int num = Mathf.FloorToInt(30f); Vector3 center = nursery.Center; for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { Vector3 val = center + new Vector3((float)i * 0.5f, 0f, (float)j * 0.5f); if (TreeNursery.Inside(val, center)) { list.Add(new Candidate { Position = val }); } } } return list.OrderBy(delegate(Candidate c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = c.Position - ((Component)tree).transform.position; return ((Vector3)(ref val2)).sqrMagnitude; }).ToList(); } private static IEnumerator FindSpots(SprotiTree tree, Piece piece, float maxGrowRadius, int amount, Func<Vector3, bool> blocked, long creator, List<Candidate> candidates, Vector3 areaCenter, float areaRadius, Dictionary<Vector2s, bool> zonesReady, List<Vector3> spots) { //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) Plant plant = ((Component)piece).GetComponent<Plant>(); bool sapling = TreeRegrowth.Saplings.Contains(piece); float spacing = (sapling ? TreeSpacing.Distance(plant, plant) : (plant.m_growRadius + 0.5f)); List<(Vector3 Position, float Spacing)> neighbours = Neighbours(plant, areaCenter, areaRadius + TreeSpacing.SearchRadius(plant, maxGrowRadius)); int checks = 0; float y = default(float); for (int i = 0; i < candidates.Count; i++) { int num = checks + 1; checks = num; if (num % 16 == 0 && SearchBudget.Exhausted) { yield return null; if (!Object.op_Implicit((Object)(object)tree)) { break; } } Candidate value = candidates[i]; Vector3 pos = value.Position; Vector3 local = ((Component)tree).transform.InverseTransformPoint(pos); if (SprotiHouse.OnPath(local, plant.m_growRadius) || SprotiHouse.NearChest(local, plant.m_growRadius) || spots.Any((Vector3 s) => Utils.DistanceXZ(s, pos) < spacing) || neighbours.Exists(((Vector3 Position, float Spacing) n) => Utils.DistanceXZ(n.Position, pos) < n.Spacing)) { continue; } if (!value.GroundUsable.HasValue) { Heightmap val = Heightmap.FindHeightmap(pos); value.GroundUsable = false; if (Object.op_Implicit((Object)(object)val) && (!plant.m_needCultivatedGround || val.IsCultivated(pos)) && !blocked(pos) && IsLoaded(pos, zonesReady) && ZoneSystem.instance.GetGroundHeight(pos, ref y)) { pos.y = y; value.Position = pos; value.Heightmap = val; value.GroundUsable = CanPlantOnGround(val, pos, creator, plant.m_needCultivatedGround); } candidates[i] = value; } if (value.GroundUsable != true || !Object.op_Implicit((Object)(object)value.Heightmap) || !CanGrowAt(piece, plant, value.Heightmap, pos, maxGrowRadius)) { continue; } spots.Add(pos); if (spots.Count >= amount) { break; } if (sapling) { Candidate[] array = candidates.GetRange(i + 1, candidates.Count - i - 1).ToArray(); float[] array2 = new float[array.Length]; for (int num2 = 0; num2 < array.Length; num2++) { array2[num2] = Utils.DistanceXZ(array[num2].Position, pos); } Array.Sort(array2, array); candidates = new List<Candidate>(array); i = -1; } } } private static bool IsLoaded(Vector3 pos, Dictionary<Vector2s, bool> zonesReady) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0028: Unknown result type (might be due to invalid IL or missing references) if (ZNetScene.instance.OutsideActiveArea(pos)) { return false; } Vector2s zone = ZoneSystem.GetZone(pos); if (!zonesReady.TryGetValue(zone, out var value)) { value = (zonesReady[zone] = ZNetScene.instance.IsAreaReady(pos)); } return value; } private static List<(Vector3 Position, float Spacing)> Neighbours(Plant plant, Vector3 center, float radius) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) HashSet<Plant> hashSet = new HashSet<Plant>(); int num = Overlap(center, radius); for (int i = 0; i < num; i++) { Plant component = ((Component)s_hits[i]).GetComponent<Plant>(); if (Object.op_Implicit((Object)(object)component)) { hashSet.Add(component); } } return hashSet.Select((Plant other) => (position: ((Component)other).transform.position, TreeSpacing.Distance(plant, other))).ToList(); } public static Result PlantAt(SprotiTree tree, Container input, Piece piece, Vector3 spot) { //IL_0082: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = input.GetInventory(); Requirement val = Material(piece); ItemData val2 = MaterialSlot(inventory, piece); if (val2 == null) { return Result.NoMaterial; } float maxGrowRadius = PlantablePieces().Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius); Piece component = ((Component)tree).GetComponent<Piece>(); TreeNursery component2 = ((Component)tree).GetComponent<TreeNursery>(); if (!(TreeRegrowth.Saplings.Contains(piece) ? component2.Contains(spot) : (Utils.DistanceXZ(spot, ((Component)tree).transform.position) <= tree.Radius)) || !CanPlantAt(piece, ((Component)piece).GetComponent<Plant>(), spot, maxGrowRadius, component.GetCreator())) { return Result.SpotTaken; } inventory.RemoveItem(val2, val.m_amount); Quaternion val3 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); GameObject val4 = Object.Instantiate<GameObject>(((Component)piece).gameObject, spot, val3); CopyCreator(component, val4.GetComponent<Piece>()); WearNTear component3 = val4.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component3)) { component3.OnPlaced(); } IPlaced[] components = val4.GetComponents<IPlaced>(); for (int num = 0; num < components.Length; num++) { components[num].OnPlaced(); } piece.m_placeEffect.Create(spot, val3, val4.transform, 1f, -1, default(ZDOID)); return Result.Planted; } private static void CopyCreator(Piece tree, Piece plant) { if (Object.op_Implicit((Object)(object)tree) && Object.op_Implicit((Object)(object)plant) && tree.GetCreator() != 0L) { plant.m_creator = tree.GetCreator(); plant.m_creatorPlatformUserIDIndex = tree.GetCreatorPlatformUserIdIndex(); ZDO zDO = plant.m_nview.GetZDO(); zDO.Set(ZDOVars.s_creator, plant.m_creator); zDO.Set(ZDOVars.s_creatorIndex, plant.m_creatorPlatformUserIDIndex, false); } } private static bool ClimateFits(Plant plant, Heightmap heightmap, Vector3 pos) { //IL_0001: 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_000e: 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_0015: 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_0025: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 //IL_0027: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 Biome biome = heightmap.GetBiome(pos, 0.02f, false); if ((biome & plant.m_biome) == 0) { return false; } if (!plant.m_tolerateHeat && (int)biome == 32 && !ShieldGenerator.IsInsideShield(pos)) { return false; } if (!plant.m_tolerateCold && ((int)biome == 64 || (int)biome == 4)) { return ShieldGenerator.IsInsideShield(pos); } return true; } public static bool CreatorHasWardAccess(long creator, Vector3 pos) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) bool flag = false; foreach (PrivateArea allArea in PrivateArea.m_allAreas) { if (allArea.IsEnabled() && allArea.IsInside(pos, 0f)) { if (creator != 0L && (allArea.m_piece.GetCreator() == creator || allArea.IsPermitted(creator))) { return true; } flag = true; } } return !flag; } private static bool CultivatedAround(Vector3 pos) { //IL_0019: 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_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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 8; i++) { float num = (float)i * 2f * (float)Math.PI / 8f; Vector3 val = pos + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * 0.5f; Heightmap val2 = Heightmap.FindHeightmap(val); if (!Object.op_Implicit((Object)(object)val2) || !val2.IsCultivated(val)) { return false; } } return true; } private static bool CanPlantAt(Piece piece, Plant plant, Vector3 pos, float maxGrowRadius, long creator) { //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_0010: 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) Heightmap heightmap = Heightmap.FindHeightmap(pos); if (SprotiTree.IsLoaded(pos) && CanPlantOnGround(heightmap, pos, creator, plant.m_needCultivatedGround)) { return CanGrowAt(piece, plant, heightmap, pos, maxGrowRadius); } return false; } private static bool CanPlantOnGround(Heightmap heightmap, Vector3 pos, long creator, bool needsCultivated) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)heightmap) && (!needsCultivated || (heightmap.IsCultivated(pos) && CultivatedAround(pos))) && !Location.IsInsideNoBuildLocation(pos) && CreatorHasWardAccess(creator, pos) && !Physics.Raycast(pos, Vector3.up, 100f, RoofMask)) { return !InsideSolid(pos); } return false; } internal static bool InsideSolid(Vector3 ground) { //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_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_0015: Unknown result type (might be due to invalid IL or missing references) return Physics.Raycast(ground + Vector3.up * 100f, Vector3.down, 99.8f, RockMask); } internal static bool CanRegrowAt(Piece sapling, Vector3 pos, Transform stump) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) Heightmap val = Heightmap.FindHeightmap(pos); if (!Object.op_Implicit((Object)(object)val) || Physics.RaycastAll(pos, Vector3.up, 100f, RoofMask).Any((RaycastHit hit) => !((Component)((RaycastHit)(ref hit)).collider).transform.IsChildOf(stump))) { return false; } float maxGrowRadius = TreeRegrowth.Saplings.Max((Piece p) => ((Component)p).GetComponent<Plant>().m_growRadius); return CanGrowAt(sa