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 SansaraTools v0.1.0
plugins/SansaraTools.dll
Decompiled 7 hours 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.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using SansaraTools.Core; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("SansaraTools")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+e2fac571d4f7c138f666b28f378dd6a67cf86f2b")] [assembly: AssemblyProduct("SansaraTools")] [assembly: AssemblyTitle("SansaraTools")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SansaraTools { internal static class AxeFlagsSync { internal static readonly int Key = StringExtensionMethods.GetStableHashCode("sansara_tools_axe"); private static Player _player; private static ZNetView _nview; private static bool _known; private static int _written; internal static void Tick() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { _player = null; return; } if (localPlayer != _player) { _player = localPlayer; _nview = ((Component)localPlayer).GetComponent<ZNetView>(); _known = false; } ZDO val = (((Object)(object)_nview != (Object)null) ? _nview.GetZDO() : null); if (val != null && _nview.IsOwner()) { if (!_known) { _known = true; _written = val.GetInt(Key, 0); } int num = AxeFlagBits.Pack(ToolConfig.Enabled.Value && ToolInput.HeldKind() == ToolKind.Axe, ToolState.UprootNow); if (num != _written) { val.Set(Key, num, false); _written = num; } } } internal static int Read(ZDOID attacker) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (((ZDOID)(ref attacker)).IsNone() || ZDOMan.instance == null) { return 0; } ZDO zDO = ZDOMan.instance.GetZDO(attacker); if (zDO == null) { return 0; } return zDO.GetInt(Key, 0); } } internal sealed class FellContext { internal ZDOID Attacker; internal bool Uproot; internal bool Felled; internal bool Uprooted; internal string TreePrefab; internal Vector3 Position; internal Quaternion Rotation; internal Vector3 Scale; } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] internal static class TreeFellOwnerPatch { internal const string RpcName = "SansaraTools_TreeFelled"; private static readonly FieldRef<TreeBase, ZNetView> NViewRef = AccessTools.FieldRefAccess<TreeBase, ZNetView>("m_nview"); internal static FellContext Current; private static void Prefix(TreeBase __instance, HitData hit, ref FellContext __state) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) __state = null; Current = null; if (hit == null || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value) { return; } ZNetView val = NViewRef.Invoke(__instance); if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner()) { int bits = AxeFlagsSync.Read(hit.m_attacker); if (AxeFlagBits.HoldsAxe(bits)) { Transform transform = ((Component)__instance).transform; __state = new FellContext { Attacker = hit.m_attacker, Uproot = (ToolConfig.Uproot.Value && AxeFlagBits.Uproot(bits)), TreePrefab = Utils.GetPrefabName(((Object)((Component)__instance).gameObject).name), Position = transform.position, Rotation = transform.rotation, Scale = transform.localScale }; Current = __state; } } } private static void Postfix(FellContext __state) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0051: 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_007a: Unknown result type (might be due to invalid IL or missing references) if (__state == null || !__state.Felled || !ToolConfig.Forester.Value) { return; } ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(__state.Attacker) : null); if (val != null && ZRoutedRpc.instance != null) { long owner = val.GetOwner(); if (owner != 0L) { ZPackage val2 = new ZPackage(); val2.Write(__state.Attacker); val2.Write(__state.TreePrefab); val2.Write(__state.Position); val2.Write(((Quaternion)(ref __state.Rotation)).eulerAngles.y); val2.Write(__state.Uprooted); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "SansaraTools_TreeFelled", new object[1] { val2 }); } } } private static void Finalizer() { Current = null; } } [HarmonyPatch(typeof(TreeBase), "SpawnLog")] internal static class TreeStubPatch { private static bool _failLogged; private static void Prefix(TreeBase __instance, ref GameObject __state) { __state = null; FellContext current = TreeFellOwnerPatch.Current; if (current != null) { current.Felled = true; GameObject stubPrefab = __instance.m_stubPrefab; if (current.Uproot && !((Object)(object)stubPrefab == (Object)null) && !((Object)(object)stubPrefab.GetComponent<Destructible>() == (Object)null)) { __state = stubPrefab; __instance.m_stubPrefab = null; } } } private static void Postfix(GameObject __state) { //IL_0016: 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_0038: Unknown result type (might be due to invalid IL or missing references) FellContext current = TreeFellOwnerPatch.Current; if ((Object)(object)__state == (Object)null || current == null) { return; } try { GameObject obj = Object.Instantiate<GameObject>(__state, current.Position, current.Rotation); ZNetView component = obj.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null) { component.SetLocalScale(current.Scale); } obj.GetComponent<Destructible>().Destroy((HitData)null); current.Uprooted = true; } catch (Exception ex) { if (!_failLogged) { _failLogged = true; Plugin.Log.LogError((object)("Sansara Tools: корчевание пня не выполнено: " + ex)); } } } private static void Finalizer(TreeBase __instance, GameObject __state) { if ((Object)(object)__state != (Object)null && (Object)(object)__instance != (Object)null) { __instance.m_stubPrefab = __state; } } } [HarmonyPatch(typeof(Game), "Start")] internal static class ForesterRpcPatch { private static void Postfix() { if (ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<ZPackage>("SansaraTools_TreeFelled", (Action<long, ZPackage>)Forester.OnFelled); } catch (ArgumentException) { } } } internal static class Forester { private const float FirstDelay = 2f; private const float RetryDelay = 2f; private const int Attempts = 4; private const float DuplicateWindow = 30f; private const float MaxTreeDistance = 30f; private static readonly Collider[] Buffer = (Collider[])(object)new Collider[30]; private static readonly List<Vector3> RecentSpots = new List<Vector3>(); private static readonly List<float> RecentTimes = new List<float>(); private static bool _uprootHintShown; private static int _spaceMask; private static int _roofMask; private const string NoSpace = "мешает соседний предмет (бревно, камень, постройка)"; internal static void OnFelled(long sender, ZPackage pkg) { //IL_001d: 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_002b: 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_0052: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) if (Application.isBatchMode || pkg == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ZDOID val; string treePrefab; Vector3 val2; float rotY; bool uprooted; try { val = pkg.ReadZDOID(); treePrefab = pkg.ReadString(); val2 = pkg.ReadVector3(); rotY = pkg.ReadSingle(); uprooted = pkg.ReadBool(); } catch (Exception) { return; } if (((ZDOID)(ref val)).IsNone() || val != ((Character)localPlayer).GetZDOID() || float.IsNaN(val2.x) || float.IsNaN(val2.y) || float.IsNaN(val2.z)) { return; } Vector3 val3 = val2 - ((Component)localPlayer).transform.position; if (((Vector3)(ref val3)).sqrMagnitude > 900f || !ToolConfig.Forestry().TryGet(treePrefab, out var entry)) { return; } bool flag = true; GameObject val4 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(entry.Sapling) : null); GameObject val5 = ((flag && (Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(entry.Seed) : null); ItemDrop val6 = (((Object)(object)val5 != (Object)null) ? val5.GetComponent<ItemDrop>() : null); flag = flag && (Object)(object)val4 != (Object)null && (Object)(object)val4.GetComponent<Piece>() != (Object)null && (Object)(object)val4.GetComponent<Plant>() != (Object)null && (Object)(object)val6 != (Object)null; int seeds = (flag ? ((Humanoid)localPlayer).GetInventory().CountItems(val6.m_itemData.m_shared.m_name, -1, false) : 0); switch (ForesterRule.Decide(ToolConfig.Enabled.Value && ToolConfig.Forester.Value, flag, uprooted, seeds)) { case ForesterAction.NeedUproot: if (!_uprootHintShown) { _uprootHintShown = true; Say("Лесник: саженец сажается только при корчевании (" + ((object)ToolConfig.ModeKey.Value/*cast due to .constrained prefix*/).ToString() + " — режим топора)"); } break; case ForesterAction.Plant: if (!IsDuplicate(val2)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(PlantLater(val4, val6, val2, rotY)); } break; } } private static bool IsDuplicate(Vector3 pos) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; for (int num = RecentTimes.Count - 1; num >= 0; num--) { if (time - RecentTimes[num] > 30f) { RecentTimes.RemoveAt(num); RecentSpots.RemoveAt(num); } else { Vector3 val = RecentSpots[num] - pos; if (((Vector3)(ref val)).sqrMagnitude < 0.25f) { return true; } } } RecentSpots.Add(pos); RecentTimes.Add(time); return false; } private static IEnumerator PlantLater(GameObject sapling, ItemDrop seed, Vector3 treePos, float rotY) { //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) string text = null; for (int attempt = 0; attempt < 4; attempt++) { yield return (object)new WaitForSeconds((attempt == 0) ? 2f : 2f); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !ToolConfig.Enabled.Value || !ToolConfig.Forester.Value) { yield break; } string name = seed.m_itemData.m_shared.m_name; if (((Humanoid)localPlayer).GetInventory().CountItems(name, -1, false) <= 0) { yield break; } Vector3 val = treePos; if ((Object)(object)ZoneSystem.instance != (Object)null) { val.y = ZoneSystem.instance.GetGroundHeight(val); } text = CheckSpot(sapling, val); if (text == null) { Piece component = sapling.GetComponent<Piece>(); localPlayer.PlacePiece(component, val, Quaternion.Euler(0f, rotY, 0f), false, false); ((Humanoid)localPlayer).GetInventory().RemoveItem(name, 1, -1, false); Say("Лесник: посажен " + Localization.instance.Localize(component.m_name) + " (−1 " + Localization.instance.Localize(name) + ")"); yield break; } if (text != "мешает соседний предмет (бревно, камень, постройка)") { break; } } if (text != null) { Say("Лесник: саженец не посажен — " + text); } } private static string CheckSpot(GameObject saplingPrefab, Vector3 pos) { //IL_000e: 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_0033: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0082: Invalid comparison between Unknown and I4 //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Invalid comparison between Unknown and I4 //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Invalid comparison between Unknown and I4 //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Invalid comparison between Unknown and I4 //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) Piece component = saplingPrefab.GetComponent<Piece>(); Plant component2 = saplingPrefab.GetComponent<Plant>(); Heightmap val = Heightmap.FindHeightmap(pos); if ((Object)(object)val == (Object)null) { return "нет земли"; } Biome biome = val.GetBiome(pos, 0.02f, false); if ((int)component.m_onlyInBiome != 0 && (Heightmap.FindBiome(pos) & component.m_onlyInBiome) == 0) { return "не тот биом"; } if ((component.m_cultivatedGroundOnly || component2.m_needCultivatedGround) && !val.IsCultivated(pos)) { return "нужна возделанная земля"; } if (component.m_vegetationGroundOnly) { float vegetationMask = val.GetVegetationMask(pos); if (((int)biome == 32) ? (vegetationMask > 0.1f) : (vegetationMask < 0.25f)) { return "здесь ничего не растёт"; } } if (!PrivateArea.CheckAccess(pos, 0f, false, false)) { return "чужой охранный камень"; } if (Location.IsInsideNoBuildLocation(pos)) { return "здесь нельзя строить"; } if ((biome & component2.m_biome) == 0) { return "не тот биом"; } if (!component2.m_tolerateHeat && (int)biome == 32 && !ShieldGenerator.IsInsideShield(pos)) { return "слишком жарко"; } if (!component2.m_tolerateCold && ((int)biome == 64 || (int)biome == 4) && !ShieldGenerator.IsInsideShield(pos)) { return "слишком холодно"; } if (_roofMask == 0) { _roofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); _spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); } if (Physics.Raycast(pos, Vector3.up, 100f, _roofMask)) { return "над местом крыша"; } int num = Physics.OverlapSphereNonAlloc(pos, component2.m_growRadius, Buffer, _spaceMask); for (int i = 0; i < num; i++) { Plant component3 = ((Component)Buffer[i]).GetComponent<Plant>(); if ((Object)(object)component3 == (Object)null || (int)component3.GetStatus() == 0) { return "мешает соседний предмет (бревно, камень, постройка)"; } } return null; } private static void Say(string text) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } } internal static class AxeItem { internal const string DisplayName = "Топор Вёлунда"; internal const string Description = "Топор, который валит лес без остатка: разделывает брёвна разом, роняет деревья от дровосека и умеет корчевать пни. Древесины даёт столько же, сколько обычный."; internal static void Apply(ItemDrop drop) { if (!((Object)(object)drop == (Object)null)) { SharedData shared = drop.m_itemData.m_shared; shared.m_maxDurability = ToolConfig.Durability.Value; shared.m_damages.m_chop = ToolConfig.ChopDamage.Value; } } } [HarmonyPatch(typeof(TreeBase), "Damage")] internal static class AxeTreePatch { private static void Prefix(TreeBase __instance, HitData hit) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!ToolSwing.Fresh(ToolKind.Axe, hit)) { return; } ToolSwing.MarkTreeHit(hit); if (ToolConfig.DirectedFall.Value && !((Object)(object)ToolSwing.Player == (Object)null)) { Vector3 position = ((Component)ToolSwing.Player).transform.position; Vector3 position2 = ((Component)__instance).transform.position; if (FallDirection.TryAway(position.x, position.z, position2.x, position2.z, out var dirX, out var dirZ)) { hit.m_dir = new Vector3(dirX, 0f, dirZ); } } } } [HarmonyPatch(typeof(TreeLog), "Damage")] internal static class AxeLogPatch { private static readonly Collider[] Buffer = (Collider[])(object)new Collider[64]; private static readonly List<TreeLog> Logs = new List<TreeLog>(); private static readonly List<Collider> LogColliders = new List<Collider>(); private static readonly List<P3> Points = new List<P3>(); private static readonly List<int> Picked = new List<int>(); private static int _mask; private static bool Prefix(TreeLog __instance, HitData hit, ref bool __state) { __state = false; if (!ToolSwing.Fresh(ToolKind.Axe, hit)) { return true; } ToolSwing.MarkTreeHit(hit); if (!ToolSwing.Logs.Add(__instance)) { return false; } __state = true; return true; } private static void Postfix(TreeLog __instance, HitData hit, bool __state) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) if (!__state || ToolSwing.InArea) { return; } float value = ToolConfig.LogAreaRadius.Value; if (value <= 0f) { return; } if (_mask == 0) { _mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); } Vector3 point = hit.m_point; int num = Physics.OverlapSphereNonAlloc(point, value, Buffer, _mask, (QueryTriggerInteraction)1); Logs.Clear(); LogColliders.Clear(); Points.Clear(); for (int i = 0; i < num; i++) { Collider val = Buffer[i]; if ((Object)(object)val == (Object)null) { continue; } TreeLog componentInParent = ((Component)val).GetComponentInParent<TreeLog>(); if ((Object)(object)componentInParent == (Object)null || componentInParent == __instance || ToolSwing.Logs.Contains(componentInParent)) { continue; } Vector3 val2 = ToolSwing.ClosestPoint(val, point); int num2 = Logs.IndexOf(componentInParent); if (num2 >= 0) { if (P3.DistSq(new P3(point.x, point.y, point.z), new P3(val2.x, val2.y, val2.z)) < P3.DistSq(new P3(point.x, point.y, point.z), Points[num2])) { Points[num2] = new P3(val2.x, val2.y, val2.z); LogColliders[num2] = val; } } else { Logs.Add(componentInParent); LogColliders.Add(val); Points.Add(new P3(val2.x, val2.y, val2.z)); } } AreaSelect.Pick(Points, new P3(point.x, point.y, point.z), value, Picked); if (Picked.Count == 0) { return; } ToolSwing.InArea = true; try { foreach (int item in Picked) { TreeLog val3 = Logs[item]; if (!((Object)(object)val3 == (Object)null) && !ToolSwing.Logs.Contains(val3)) { HitData val4 = hit.Clone(); P3 p = Points[item]; val4.m_point = new Vector3(p.X, p.Y, p.Z); val4.m_hitCollider = LogColliders[item]; val3.Damage(val4); } } } finally { ToolSwing.InArea = false; } } } internal static class AxeCareful { internal static bool Blocks(Component target, HitData hit) { if (!ToolSwing.Fresh(ToolKind.Axe, hit) || !ToolState.CarefulNow || (Object)(object)target == (Object)null) { return false; } Piece component = target.GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.IsPlacedByPlayer()) { return true; } return (Object)(object)target.GetComponent<Plant>() != (Object)null; } } [HarmonyPatch(typeof(WearNTear), "Damage")] internal static class AxeCarefulBuildingPatch { private static bool Prefix(WearNTear __instance, HitData hit) { return !AxeCareful.Blocks((Component)(object)__instance, hit); } } [HarmonyPatch(typeof(Destructible), "Damage")] internal static class AxeCarefulDestructiblePatch { private static bool Prefix(Destructible __instance, HitData hit) { return !AxeCareful.Blocks((Component)(object)__instance, hit); } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class AxeNoSelfLogPatch { private static bool Prefix(Character __instance, HitData hit) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (hit == null || (int)hit.m_hitType != 13) { return true; } if ((object)__instance != Player.m_localPlayer || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value || !ToolConfig.NoSelfLogDamage.Value) { return true; } float distance = Vector3.Distance(((Component)__instance).transform.position, ToolSwing.LastTreeHitPoint); return !LogGuard.IsProtected(Time.time, ToolSwing.LastTreeHitTime, ToolConfig.NoSelfLogSeconds.Value, distance, ToolConfig.NoSelfLogRadius.Value); } } internal static class HoeControl { internal static void Tick() { HoeState hoe = ToolState.Hoe; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { if (hoe.HeightLocked) { hoe.ResetHeight(); } HoeFillCost.Clear(); return; } if (ToolInput.HeldKind() != ToolKind.Hoe) { HoeFillCost.Clear(); if (hoe.HeightLocked) { hoe.ResetHeight(); Say("Мотыга: фиксация высоты сброшена"); } return; } HoeVariant hoeVariant = HoePieces.SelectedVariant(localPlayer); if (hoeVariant != null && !HoeOps.SlotBelongsTo(hoe.ActiveSlot, hoeVariant.Spec.Op)) { hoe.ActiveSlot = HoeOps.SizeSlotOf(hoeVariant.Spec.Op); } if (hoeVariant == null || !hoeVariant.Levels) { HoeFillCost.Clear(); } } internal static void CycleMode() { HoeState hoe = ToolState.Hoe; HoeOp hoeOp = HoePieces.SelectedVariant(Player.m_localPlayer)?.Spec.Op ?? HoeOp.Level; if (HoeOps.HasEdge(hoeOp)) { bool flag = hoe.CycleMode(allowed: true); HoePieces.OnSelectionChanged(); Say("Мотыга: чёткий край " + ToolTexts.OnOff(flag)); } else if (hoeOp == HoeOp.Raise) { hoe.ActiveSlot = ((hoe.ActiveSlot != SizeSlot.RaiseRadius) ? SizeSlot.RaiseRadius : SizeSlot.RaiseStep); Say("Мотыга: колесо листает " + ToolTexts.SlotName(hoe.ActiveSlot)); } else { Say("Мотыга: у операции «" + HoeOps.MenuName(hoeOp) + "» нет режимов"); } } internal static string AfterSizeStep() { HoePieces.OnSelectionChanged(); HoeVariant hoeVariant = HoePieces.SelectedVariant(Player.m_localPlayer); if (hoeVariant == null) { return ""; } int num = HoeOps.Stones(hoeVariant.Spec, ToolConfig.RaiseStoneBase.Value, ToolConfig.PaveStoneBase.Value); bool flag = hoeVariant.Levels && ToolConfig.RaiseStoneBase.Value > 0; if (!HoeOps.CostsStone(hoeVariant.Spec.Op)) { if (!flag) { return ""; } return ", насыпь — камень по объёму"; } string text = ((num > 0) ? (", камней: " + num) : ", бесплатно"); if (!flag) { return text; } return text + " + насыпь по объёму"; } internal static void Say(string text) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } } internal static class HoeFillCost { internal const float Interval = 0.2f; private static readonly FieldRef<Heightmap, HMBuildData> BuildData = AccessTools.FieldRefAccess<Heightmap, HMBuildData>("m_buildData"); private static readonly List<Heightmap> Maps = new List<Heightmap>(); private static readonly HoeVolume.HeightSample Sampler = Sample; private static HoeVariant _variant; private static float _time = -1000f; private static int _fill; private static float _cx; private static float _cz; private static float _scale = 1f; internal static int Fill { get { if (_variant == null) { return 0; } return _fill; } } internal static void Update(Player player, HoeVariant v, Vector3 ghostPos, bool force) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (v == null || !v.Levels) { Clear(); return; } float time = Time.time; if (v != _variant) { Clear(); _variant = v; force = true; } if (force || !(time - _time < 0.2f)) { _time = time; int baseStones = v.BaseStones; int value = ToolConfig.RaiseStoneBase.Value; _fill = ((value > 0) ? HoeVolume.Stones(value, Volume(v, ghostPos)) : 0); HoePieces.SetStones(v, baseStones + _fill); } } internal static void Clear() { if (_variant != null) { HoePieces.SetStones(_variant, _variant.BaseStones); _variant = null; } _fill = 0; _time = -1000f; } private static float Volume(HoeVariant v, Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0020: 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_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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) Vector3 val = pos + Vector3.up * v.Op.m_settings.m_levelOffset; Maps.Clear(); Heightmap.FindHeightmap(val, v.LevelOuter + 1f, Maps); if (Maps.Count == 0) { return 0f; } Heightmap val2 = Maps[0]; _scale = ((val2.m_scale > 0f) ? val2.m_scale : 1f); int num = default(int); int num2 = default(int); val2.WorldToVertex(val, ref num, ref num2); Vector3 position = ((Component)val2).transform.position; int num3 = val2.m_width / 2; _cx = position.x + (float)(num - num3) * _scale; _cz = position.z + (float)(num2 - num3) * _scale; return HoeVolume.Raise(val.y, v.LevelInner / _scale, v.LevelOuter / _scale, 1f * _scale, _scale * _scale, Sampler); } private static bool Sample(int dx, int dz, out float height, out float maxHeight) { //IL_0056: 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) height = 0f; maxHeight = float.MaxValue; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(_cx + (float)dx * _scale, 0f, _cz + (float)dz * _scale); int num = default(int); int num2 = default(int); for (int i = 0; i < Maps.Count; i++) { Heightmap val2 = Maps[i]; if ((Object)(object)val2 == (Object)null) { continue; } val2.WorldToVertex(val, ref num, ref num2); int num3 = val2.m_width + 1; if (num >= 0 && num2 >= 0 && num < num3 && num2 < num3) { float y = ((Component)val2).transform.position.y; height = val2.GetHeight(num, num2) + y; List<float> list = BuildData.Invoke(val2)?.m_baseHeights; int index = num2 * num3 + num; if (list != null && list.Count == num3 * num3) { maxHeight = list[index] + y + 8f; } return true; } } return false; } } internal static class HoeItem { internal const string DisplayName = "Мотыга Ивальди"; internal const string Description = "Мотыга, выкованная для больших строек: ровняет землю широким кругом и запоминает высоту. Не добывает больше, но экономит часы работы."; internal static void Apply(ItemDrop drop) { if (!((Object)(object)drop == (Object)null)) { drop.m_itemData.m_shared.m_maxDurability = ToolConfig.Durability.Value; HoePieces.Apply(drop); } } } [HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")] internal static class SoftLevelPatch { private static readonly FieldRef<TerrainComp, Heightmap> Hmap = AccessTools.FieldRefAccess<TerrainComp, Heightmap>("m_hmap"); private static readonly FieldRef<TerrainComp, int> Width = AccessTools.FieldRefAccess<TerrainComp, int>("m_width"); private static readonly FieldRef<TerrainComp, float[]> LevelDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_levelDelta"); private static readonly FieldRef<TerrainComp, float[]> SmoothDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_smoothDelta"); private static readonly FieldRef<TerrainComp, bool[]> Modified = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedHeight"); private static readonly FieldRef<TerrainComp, float> LastOpRadius = AccessTools.FieldRefAccess<TerrainComp, float>("m_lastOpRadius"); private static bool _errorLogged; private static void Prefix(TerrainComp __instance, Vector3 pos, Settings modifier, ref bool __state) { //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0060: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!modifier.m_level || !HoePieces.TryGetSoft(modifier, out var inner)) { return; } try { Heightmap val = Hmap.Invoke(__instance); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = pos + Vector3.up * modifier.m_levelOffset; int cx = default(int); int cy = default(int); val.WorldToVertex(val2, ref cx, ref cy); float y = (val2 - ((Component)__instance).transform.position).y; float num = ((val.m_scale > 0f) ? val.m_scale : 1f); SoftLevel.Apply(Width.Invoke(__instance) + 1, cx, cy, y, inner / num, modifier.m_levelRadius / num, 1f * num, (Func<int, int, float>)val.GetHeight, LevelDelta.Invoke(__instance), SmoothDelta.Invoke(__instance), Modified.Invoke(__instance)); modifier.m_level = false; __state = true; } } catch (Exception ex) { if (!_errorLogged) { _errorLogged = true; Plugin.Log.LogError((object)("Sansara Tools: мягкий край выравнивания не выполнен, выравнивание пойдёт ванильным (чёткий край): " + ex)); } } } private static void Finalizer(TerrainComp __instance, Settings modifier, bool __state) { if (__state) { modifier.m_level = true; LastOpRadius.Invoke(__instance) = modifier.GetRadius(); } } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] internal static class LockedHeightGhostPatch { private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); private static void Postfix(Player __instance, bool flashGuardStone) { //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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } HoeVariant hoeVariant = HoePieces.SelectedVariant(__instance); if (hoeVariant == null || !HoeOps.LevelsGround(hoeVariant.Spec.Op)) { return; } GameObject val = Ghost.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.activeSelf) { return; } if (ToolState.Hoe.HeightLocked) { Transform transform = val.transform; Vector3 position = transform.position; if (position.y != ToolState.Hoe.LockedHeight) { position.y = ToolState.Hoe.LockedHeight; transform.position = position; } } if (!flashGuardStone) { HoeFillCost.Update(__instance, hoeVariant, val.transform.position, force: false); } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class HoeFillPlacePatch { private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); private static bool Prefix(Player __instance, Piece piece, ref bool __result) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if (!HoePieces.TryGetVariant(((Component)piece).gameObject, out var variant) || !HoeOps.LevelsGround(variant.Spec.Op)) { return true; } GameObject val = Ghost.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.activeSelf) { return true; } HoeFillCost.Update(__instance, variant, val.transform.position, force: true); if (__instance.PlacementCostDisabled || (Object)(object)ZoneSystem.instance == (Object)null || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()) || __instance.HaveRequirements(piece, (RequirementMode)0)) { return true; } ((Character)__instance).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); __result = false; return false; } } [HarmonyPatch(typeof(Player), "PlacePiece")] internal static class LockHeightOnPlacePatch { private static void Postfix(Player __instance, Piece piece, Vector3 pos) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !ToolState.Hoe.HeightLocked && HoePieces.TryGetVariant(((Component)piece).gameObject, out var variant) && HoeOps.LevelsGround(variant.Spec.Op)) { ToolState.Hoe.LockHeight(pos.y); HoeControl.Say("Мотыга: высота зафиксирована (" + ToolTexts.Meters(Mathf.Round(pos.y * 10f) / 10f) + "), " + ((object)ToolConfig.ResetKey.Value/*cast due to .constrained prefix*/).ToString() + " — сброс"); } } } [HarmonyPatch(typeof(Player), "GetBuildStamina")] internal static class HoeStaminaPatch { private static void Postfix(Player __instance, ref float __result) { HoeVariant hoeVariant = HoePieces.SelectedVariant(__instance); if (hoeVariant != null) { __result *= HoeCost.StaminaFactor(HoePieces.StaminaFactors, HoeOps.StaminaIndex(hoeVariant.Spec, HoePieces.Lists)); } } } internal sealed class HoeVariant { internal HoeOpSpec Spec; internal GameObject Prefab; internal TerrainOp Op; internal Piece Piece; internal float SoftInner; internal bool Levels; internal float LevelInner; internal float LevelOuter; internal int BaseStones; } internal static class HoePieces { private const string TableName = "_SansaraHoePieceTable"; private static readonly Dictionary<string, HoeVariant> ByName = new Dictionary<string, HoeVariant>(); private static readonly Dictionary<GameObject, HoeVariant> ByPrefab = new Dictionary<GameObject, HoeVariant>(); private static readonly Dictionary<Settings, HoeVariant> BySettings = new Dictionary<Settings, HoeVariant>(); private static readonly Dictionary<HoeOp, GameObject> Bases = new Dictionary<HoeOp, GameObject>(); private static readonly HashSet<string> VisualLogged = new HashSet<string>(); private static GameObject _holder; private static PieceTable _table; private static PieceTable _vanillaTable; private static ItemDrop _stone; private static bool _initDone; private static bool _initFailed; private static HoeLists _lists = HoeLists.Default; private static float[] _stamina = (float[])HoeSizes.Stamina.Fallback.Clone(); private static readonly MethodInfo UpdateAvailable = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null); private static readonly MethodInfo SetPlaceMode = AccessTools.Method(typeof(Player), "SetPlaceMode", new Type[1] { typeof(PieceTable) }, (Type[])null); internal static PieceTable Table => _table; internal static HoeLists Lists => _lists; internal static float[] StaminaFactors => _stamina; internal static bool TryGetVariant(GameObject prefab, out HoeVariant variant) { variant = null; if ((Object)(object)prefab != (Object)null) { return ByPrefab.TryGetValue(prefab, out variant); } return false; } internal static bool TryGetSoft(Settings settings, out float inner) { if (settings != null && BySettings.TryGetValue(settings, out var value) && value.SoftInner > 0f) { inner = value.SoftInner; return true; } inner = 0f; return false; } internal static HoeVariant SelectedVariant(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)_table == (Object)null || (Object)(object)player.GetBuildTool() != (Object)(object)_table) { return null; } Piece selectedPiece = player.GetSelectedPiece(); if (!((Object)(object)selectedPiece != (Object)null) || !ByPrefab.TryGetValue(((Component)selectedPiece).gameObject, out var value)) { return null; } return value; } private static bool Init() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown if (_initDone || _initFailed) { return _initDone; } ItemDrop prefab = Cache.GetPrefab<ItemDrop>("Hoe"); _vanillaTable = (((Object)(object)prefab != (Object)null) ? prefab.m_itemData.m_shared.m_buildPieces : null); _stone = Cache.GetPrefab<ItemDrop>("Stone"); if ((Object)(object)_vanillaTable == (Object)null || (Object)(object)_stone == (Object)null) { _initFailed = true; Plugin.Log.LogError((object)"Sansara Tools: мотыга — не найдены ванильная таблица Hoe или предмет Stone, операции не созданы."); return false; } FindBase(HoeOp.Level, "mud_road_v2"); FindBase(HoeOp.Raise, "raise_v2"); FindBase(HoeOp.Path, "path_v2"); FindBase(HoeOp.Pave, "paved_road_v2"); FindBase(HoeOp.PaveCover, "paved_road_v2"); if (Bases.Count != HoeOps.MenuOrder.Length) { _initFailed = true; Plugin.Log.LogError((object)"Sansara Tools: мотыга — нет ванильных деталей mud_road_v2 / raise_v2 / path_v2 / paved_road_v2, операции не созданы."); return false; } _holder = new GameObject("SansaraToolsHoePrefabs"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); GameObject obj = Object.Instantiate<GameObject>(((Component)_vanillaTable).gameObject, _holder.transform, false); ((Object)obj).name = "_SansaraHoePieceTable"; _table = obj.GetComponent<PieceTable>(); _table.m_pieces = new List<GameObject>(); ItemManager.OnItemsRegistered += RegisterInObjectDB; ItemManager.OnItemsRegisteredFejd += RegisterInObjectDB; _initDone = true; return true; } private static void FindBase(HoeOp op, string name) { foreach (GameObject piece in _vanillaTable.m_pieces) { if ((Object)(object)piece != (Object)null && ((Object)piece).name == name && (Object)(object)piece.GetComponent<TerrainOp>() != (Object)null && (Object)(object)piece.GetComponent<Piece>() != (Object)null) { Bases[op] = piece; return; } } GameObject prefab = Cache.GetPrefab<GameObject>(name); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<TerrainOp>() != (Object)null && (Object)(object)prefab.GetComponent<Piece>() != (Object)null) { Bases[op] = prefab; } } internal static void Apply(ItemDrop hoe) { if ((Object)(object)hoe == (Object)null || !Init()) { return; } _lists = new HoeLists(ToolConfig.Sizes(SizeSlot.LevelRadius), ToolConfig.Sizes(SizeSlot.RaiseRadius), ToolConfig.Sizes(SizeSlot.RaiseStep), ToolConfig.Sizes(SizeSlot.PathWidth), ToolConfig.Sizes(SizeSlot.PaveWidth)); _stamina = ToolConfig.Stamina(); int num = 0; List<HoeOpSpec> list = HoeOps.Combinations(_lists); foreach (HoeOpSpec item in list) { if (!ByName.TryGetValue(item.Name, out var value)) { value = Create(item); if (value == null) { continue; } num++; } UpdatePiece(value); } if ((Object)(object)ObjectDB.instance != (Object)null) { RegisterIn(ObjectDB.instance); } bool flag = RefreshTable(); PieceTable val = (ToolConfig.Enabled.Value ? _table : _vanillaTable); bool flag2 = (Object)(object)hoe.m_itemData.m_shared.m_buildPieces != (Object)(object)val; hoe.m_itemData.m_shared.m_buildPieces = val; if (num > 0 || flag2) { Plugin.Log.LogInfo((object)($"Sansara Tools: мотыга — сочетаний {list.Count}, новых префабов {num}, всего {ByName.Count}; " + (((Object)(object)val == (Object)(object)_table) ? "таблица мотыги Ивальди." : "Enabled=false — у мотыги ванильная таблица."))); } RefreshPlayer(flag2 || flag); } private static HoeVariant Create(HoeOpSpec spec) { if (!Bases.TryGetValue(spec.Op, out var value)) { return null; } GameObject val = Object.Instantiate<GameObject>(value, _holder.transform, false); ((Object)val).name = spec.Name; HoeVariant hoeVariant = new HoeVariant { Spec = spec, Prefab = val, Op = val.GetComponent<TerrainOp>(), Piece = val.GetComponent<Piece>() }; HoeTerrainSettings hoeTerrainSettings = HoeOps.Settings(spec); WriteSettings(hoeVariant.Op.m_settings, hoeTerrainSettings); hoeVariant.SoftInner = hoeTerrainSettings.SoftInner; hoeVariant.Levels = HoeOps.LevelShape(spec, out hoeVariant.LevelInner, out hoeVariant.LevelOuter); hoeVariant.Op.m_spawnOnPlaced = null; hoeVariant.Piece.m_enabled = true; hoeVariant.Piece.m_canRotate = false; hoeVariant.Piece.m_craftingStation = null; float radius = value.GetComponent<TerrainOp>().GetRadius(); ScaleVisual(val, ((Object)value).name, (radius > 0f) ? (hoeTerrainSettings.Radius / radius) : 1f); ByName[spec.Name] = hoeVariant; ByPrefab[val] = hoeVariant; BySettings[hoeVariant.Op.m_settings] = hoeVariant; return hoeVariant; } private static void WriteSettings(Settings t, HoeTerrainSettings s) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) t.m_levelOffset = s.LevelOffset; t.m_level = s.Level; t.m_levelRadius = s.LevelRadius; t.m_square = s.Square; t.m_raise = s.Raise; t.m_raiseRadius = s.RaiseRadius; t.m_raisePower = s.RaisePower; t.m_raiseDelta = s.RaiseDelta; t.m_smooth = s.Smooth; t.m_smoothRadius = s.SmoothRadius; t.m_smoothPower = s.SmoothPower; t.m_paintCleared = s.PaintCleared; t.m_paintHeightCheck = false; t.m_paintType = (PaintType)((s.PaintType == HoePaint.Paved) ? 2 : 0); t.m_paintRadius = s.PaintRadius; t.m_paintStrength = s.PaintStrength; t.m_paintExp = s.PaintExp; t.m_halfOffset = s.HalfOffset; t.m_rotation = false; } private static void UpdatePiece(HoeVariant v) { //IL_0027: 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_0045: Unknown result type (might be due to invalid IL or missing references) Piece piece = v.Piece; piece.m_name = HoeOps.MenuName(v.Spec.Op); piece.m_description = HoeOps.Description(v.Spec, KeyName(ToolConfig.SizeModifier.Value), KeyName(ToolConfig.ModeKey.Value), KeyName(ToolConfig.ResetKey.Value)); v.BaseStones = HoeOps.Stones(v.Spec, ToolConfig.RaiseStoneBase.Value, ToolConfig.PaveStoneBase.Value); SetStones(v, v.BaseStones); } internal static void SetStones(HoeVariant v, int stones) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown Piece piece = v.Piece; Requirement[] resources = piece.m_resources; bool num; if (stones != 0) { if (resources == null || resources.Length != 1 || !((Object)(object)resources[0].m_resItem == (Object)(object)_stone)) { goto IL_004b; } num = resources[0].m_amount == stones; } else { if (resources == null) { return; } num = resources.Length == 0; } if (num) { return; } goto IL_004b; IL_004b: piece.m_resources = (Requirement[])(object)((stones == 0) ? new Requirement[0] : new Requirement[1] { new Requirement { m_resItem = _stone, m_amount = stones, m_recover = false } }); } private unsafe static string KeyName(KeyCode key) { return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); } internal static bool RefreshTable() { if ((Object)(object)_table == (Object)null) { return false; } bool sharpEdge = ToolState.SharpEdge; List<GameObject> pieces = _table.m_pieces; bool flag = pieces.Count != HoeOps.MenuOrder.Length; if (flag) { pieces.Clear(); for (int i = 0; i < HoeOps.MenuOrder.Length; i++) { pieces.Add(null); } } for (int j = 0; j < HoeOps.MenuOrder.Length; j++) { HoeOpSpec hoeOpSpec = HoeOps.Select(HoeOps.MenuOrder[j], _lists, ToolState.Hoe.Sizes, sharpEdge); if (ByName.TryGetValue(hoeOpSpec.Name, out var value) && (Object)(object)pieces[j] != (Object)(object)value.Prefab) { pieces[j] = value.Prefab; flag = true; } } if (pieces.Contains(null)) { pieces.RemoveAll((GameObject p) => (Object)(object)p == (Object)null); } return flag; } internal static void OnSelectionChanged() { if (RefreshTable()) { RefreshPlayer(changed: true); } } private static void RefreshPlayer(bool changed) { Player localPlayer = Player.m_localPlayer; if (!changed || (Object)(object)localPlayer == (Object)null || (Object)(object)_table == (Object)null) { return; } ItemData rightItem = ((Humanoid)localPlayer).RightItem; if (ToolItems.KindOf(rightItem) == ToolKind.Hoe) { PieceTable buildPieces = rightItem.m_shared.m_buildPieces; if ((Object)(object)localPlayer.GetBuildTool() != (Object)(object)buildPieces) { SetPlaceMode?.Invoke(localPlayer, new object[1] { buildPieces }); } else if ((Object)(object)buildPieces == (Object)(object)_table) { UpdateAvailable?.Invoke(localPlayer, null); } } } private static void RegisterInObjectDB() { if ((Object)(object)ObjectDB.instance != (Object)null) { RegisterIn(ObjectDB.instance); } } private static void RegisterIn(ObjectDB db) { foreach (HoeVariant value in ByName.Values) { if (!db.m_terrainOps.Contains(value.Op)) { db.m_terrainOps.Add(value.Op); } db.m_terrainOpsByHash[StringExtensionMethods.GetStableHashCode(value.Spec.Name)] = value.Op; } } private static void ScaleVisual(GameObject prefab, string baseName, float factor) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; int num3 = 0; if (Mathf.Abs(factor - 1f) > 0.001f) { CircleProjector[] componentsInChildren = prefab.GetComponentsInChildren<CircleProjector>(true); foreach (CircleProjector val in componentsInChildren) { val.m_radius *= factor; val.m_nrOfSegments = Mathf.Max(val.m_nrOfSegments, Mathf.CeilToInt((float)val.m_nrOfSegments * factor)); num++; } Projector[] componentsInChildren2 = prefab.GetComponentsInChildren<Projector>(true); foreach (Projector obj in componentsInChildren2) { obj.orthographicSize *= factor; num2++; } HashSet<Transform> hashSet = new HashSet<Transform>(); MeshRenderer[] componentsInChildren3 = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Transform transform = ((Component)componentsInChildren3[i]).transform; if (!((Object)(object)transform == (Object)(object)prefab.transform) && !((Object)(object)((Component)transform).GetComponentInParent<CircleProjector>() != (Object)null) && hashSet.Add(transform)) { Vector3 localScale = transform.localScale; transform.localScale = new Vector3(localScale.x * factor, localScale.y, localScale.z * factor); num3++; } } } if (VisualLogged.Add(baseName)) { Plugin.Log.LogInfo((object)$"Sansara Tools: призрак на основе {baseName} — CircleProjector {num}, Projector {num2}, сеток {num3} (масштаб {factor:0.##})."); } } } [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] internal static class WheelPatch { private static void Postfix(ref float __result) { if (__result == 0f) { return; } try { if (ToolInput.ShouldSwallowWheel()) { __result = 0f; } } catch (Exception ex) { Plugin.Log.LogError((object)("Sansara Tools: патч колеса: " + ex.Message)); } } } internal static class PickaxeItem { internal const string DisplayName = "Кирка Синдри"; internal const string Description = "Кирка, которая берёт жилу целиком: один удар скалывает всё вокруг точки попадания, тяжёлый удар — ещё шире. Добычи с жилы столько же, сколько у обычной кирки."; internal static void Apply(ItemDrop drop) { if (!((Object)(object)drop == (Object)null)) { SharedData shared = drop.m_itemData.m_shared; shared.m_maxDurability = ToolConfig.Durability.Value; shared.m_damages.m_pickaxe = ToolConfig.PickaxeDamage.Value; ApplyHeavy(shared); PickaxeDig.Apply(drop); } } private static void ApplyHeavy(SharedData shared) { Attack attack = shared.m_attack; if (attack != null) { Attack val = attack.Clone(); string text = ((ToolConfig.HeavyAnimation.Value != null) ? ToolConfig.HeavyAnimation.Value.Trim() : ""); val.m_attackAnimation = (ToolConfig.Enabled.Value ? text : ""); val.m_attackStamina = HeavyStrike.Stamina(attack.m_attackStamina, ToolConfig.HeavyCostFactor.Value); shared.m_secondaryAttack = val; } } } internal static class PickaxeArea { internal static bool Applies(HitData hit) { if (ToolSwing.Fresh(ToolKind.Pickaxe, hit)) { return hit.m_radius <= 0f; } return false; } internal static float Radius() { return HeavyStrike.Radius(ToolSwing.Heavy, ToolConfig.AreaRadius.Value, ToolConfig.HeavyRadius.Value); } internal static void ScaleHeavy(HitData hit) { float num = HeavyStrike.RockDamageFactor(ToolSwing.Heavy, ToolConfig.HeavyDamageFactor.Value); if (num != 1f) { ((DamageTypes)(ref hit.m_damage)).Modify(num); } } } [HarmonyPatch(typeof(MineRock5), "Damage")] internal static class PickaxeMineRock5Patch { private static void Prefix(HitData hit) { if (PickaxeArea.Applies(hit)) { PickaxeArea.ScaleHeavy(hit); hit.m_radius = PickaxeArea.Radius(); } } } [HarmonyPatch(typeof(Destructible), "Damage")] internal static class PickaxeDestructiblePatch { private static void Prefix(HitData hit) { if (PickaxeArea.Applies(hit)) { PickaxeArea.ScaleHeavy(hit); hit.m_radius = PickaxeArea.Radius(); } } } [HarmonyPatch(typeof(MineRock), "Damage")] internal static class PickaxeMineRockPatch { private static readonly FieldRef<MineRock, Collider[]> AreasRef = AccessTools.FieldRefAccess<MineRock, Collider[]>("m_hitAreas"); private static readonly FieldRef<MineRock, ZNetView> NViewRef = AccessTools.FieldRefAccess<MineRock, ZNetView>("m_nview"); private static readonly List<P3> Points = new List<P3>(); private static readonly List<int> Index = new List<int>(); private static readonly List<int> Picked = new List<int>(); private static bool Prefix(MineRock __instance, HitData hit) { //IL_0041: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00a4: Unknown result type (might be due to invalid IL or missing references) if (!PickaxeArea.Applies(hit)) { return true; } Collider[] array = AreasRef.Invoke(__instance); ZNetView val = NViewRef.Invoke(__instance); if (array == null || (Object)(object)val == (Object)null || !val.IsValid()) { return true; } float radius = PickaxeArea.Radius(); Vector3 point = hit.m_point; Points.Clear(); Index.Clear(); for (int i = 0; i < array.Length; i++) { Collider val2 = array[i]; if (!((Object)(object)val2 == (Object)null) && val2.enabled && ((Component)val2).gameObject.activeInHierarchy) { Vector3 val3 = ToolSwing.ClosestPoint(val2, point); Points.Add(new P3(val3.x, val3.y, val3.z)); Index.Add(i); } } AreaSelect.Pick(Points, new P3(point.x, point.y, point.z), radius, Picked); if (Picked.Count == 0) { return true; } PickaxeArea.ScaleHeavy(hit); hit.m_radius = radius; foreach (int item in Picked) { val.InvokeRPC("Hit", new object[2] { hit, Index[item] }); } return false; } } [HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")] internal static class PickaxeTerrainPatch { private static bool Prefix(ref GameObject prefab, ref GameObject __result) { if (!ToolSwing.Active || ToolSwing.Kind != ToolKind.Pickaxe) { return true; } switch (PickaxeTerrain.For(ToolState.PickaxeModeNow, ToolConfig.WideDigRadius.Value)) { case TerrainAction.None: __result = null; return false; case TerrainAction.Wide: { GameObject val = PickaxeDig.Current(); if ((Object)(object)val != (Object)null) { prefab = val; } return true; } default: return true; } } } internal static class PickaxeDig { private static readonly Dictionary<string, TerrainOp> ByName = new Dictionary<string, TerrainOp>(); private static GameObject _holder; private static GameObject _base; private static bool _hooked; private static bool _failLogged; private static TerrainOp _current; internal static GameObject Current() { if (!((Object)(object)_current != (Object)null)) { return null; } return ((Component)_current).gameObject; } internal static void Apply(ItemDrop pickaxe) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown _current = null; if ((Object)(object)pickaxe == (Object)null || ToolConfig.WideDigRadius.Value < 0.5f) { return; } if ((Object)(object)_base == (Object)null) { GameObject spawnOnHitTerrain = pickaxe.m_itemData.m_shared.m_spawnOnHitTerrain; if ((Object)(object)spawnOnHitTerrain == (Object)null || (Object)(object)spawnOnHitTerrain.GetComponent<TerrainOp>() == (Object)null) { if (!_failLogged) { _failLogged = true; Plugin.Log.LogError((object)"Sansara Tools: у кирки нет операции копки с TerrainOp в корне — «широкая копка» недоступна."); } return; } _base = spawnOnHitTerrain; _holder = new GameObject("SansaraToolsPickaxeDig"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } string text = PickaxeTerrain.DigName(ToolConfig.WideDigRadius.Value); if (!ByName.TryGetValue(text, out var value)) { PickaxeTerrain.TryParseDig(text, out var radius); GameObject obj = Object.Instantiate<GameObject>(_base, _holder.transform, false); ((Object)obj).name = text; value = obj.GetComponent<TerrainOp>(); Settings settings = value.m_settings; settings.m_raise = true; settings.m_raiseRadius = radius; settings.m_paintRadius = PickaxeTerrain.PaintRadius(radius); ByName[text] = value; Plugin.Log.LogInfo((object)("Sansara Tools: «широкая копка» — операция " + text + " (основа " + ((Object)_base).name + ").")); } _current = value; if (!_hooked) { _hooked = true; ItemManager.OnItemsRegistered += RegisterInObjectDB; ItemManager.OnItemsRegisteredFejd += RegisterInObjectDB; } RegisterInObjectDB(); } private static void RegisterInObjectDB() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } foreach (KeyValuePair<string, TerrainOp> item in ByName) { if (!instance.m_terrainOps.Contains(item.Value)) { instance.m_terrainOps.Add(item.Value); } instance.m_terrainOpsByHash[StringExtensionMethods.GetStableHashCode(item.Key)] = item.Value; } } } [HarmonyPatch(typeof(VisEquipment), "SetRightHandEquipped")] internal static class PickaxeLightPatch { private static readonly FieldRef<VisEquipment, GameObject> RightRef = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance"); private static readonly int PickaxeHash = StringExtensionMethods.GetStableHashCode("SansaraPickaxe"); private const string LightName = "SansaraPickaxeLight"; private static void Postfix(VisEquipment __instance, int hash, bool __result) { //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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (__result && hash == PickaxeHash && !Application.isBatchMode && ToolConfig.Light != null && ToolConfig.Light.Value && ToolConfig.Enabled.Value) { GameObject val = RightRef.Invoke(__instance); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.transform.Find("SansaraPickaxeLight") != (Object)null)) { GameObject val2 = new GameObject("SansaraPickaxeLight"); val2.transform.SetParent(val.transform, false); val2.transform.localPosition = new Vector3(0f, 0.3f, 0f); Light obj = val2.AddComponent<Light>(); obj.type = (LightType)2; obj.color = new Color(1f, 0.78f, 0.52f); obj.range = 5f; obj.intensity = 0.9f; obj.shadows = (LightShadows)0; } } } } [BepInPlugin("sansara.Tools", "Sansara Tools", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "sansara.Tools"; public const string Name = "Sansara Tools"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static Plugin Instance; private void Awake() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; ToolConfig.Bind(((BaseUnityPlugin)this).Config); ToolItems.Register(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { ToolItems.MarkDirty(); }; SynchronizationManager.OnConfigurationSynchronized += delegate { ToolItems.MarkDirty(); }; int num = PatchEach(new Harmony("sansara.Tools")); Log.LogInfo((object)string.Format("{0} {1} загружен ({2}, патчей {3}).", "Sansara Tools", "0.1.0", Application.isBatchMode ? "сервер: клавиши не подключаются" : "клиент", num)); } private static int PatchEach(Harmony harmony) { int num = 0; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly); foreach (Type type in typesFromAssembly) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0) { try { harmony.CreateClassProcessor(type).Patch(); num++; } catch (Exception arg) { Log.LogError((object)$"Sansara Tools: патч {type.Name} не применён: {arg}"); } } } return num; } private void Update() { try { ToolItems.ApplyIfDirty(); } catch (Exception ex) { Log.LogError((object)("Sansara Tools: применение настроек: " + ex)); } if (Application.isBatchMode) { return; } try { HoeControl.Tick(); ToolInput.Tick(); ToolPickup.Tick(); AxeFlagsSync.Tick(); } catch (Exception ex2) { Log.LogError((object)("Sansara Tools: ввод: " + ex2)); } } } internal static class ToolConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> Durability; internal static ConfigEntry<string> LevelRadii; internal static ConfigEntry<string> RaiseRadii; internal static ConfigEntry<string> RaiseSteps; internal static ConfigEntry<string> PathWidths; internal static ConfigEntry<string> PaveWidths; internal static ConfigEntry<int> RaiseStoneBase; internal static ConfigEntry<int> PaveStoneBase; internal static ConfigEntry<string> StaminaFactors; internal static ConfigEntry<float> PickaxeDamage; internal static ConfigEntry<float> AreaRadius; internal static ConfigEntry<float> HeavyRadius; internal static ConfigEntry<float> HeavyDamageFactor; internal static ConfigEntry<float> HeavyCostFactor; internal static ConfigEntry<string> HeavyAnimation; internal static ConfigEntry<float> WideDigRadius; internal static ConfigEntry<bool> Light; internal static ConfigEntry<float> PickaxePickupRange; internal static ConfigEntry<float> ChopDamage; internal static ConfigEntry<float> LogAreaRadius; internal static ConfigEntry<bool> DirectedFall; internal static ConfigEntry<bool> NoSelfLogDamage; internal static ConfigEntry<float> NoSelfLogSeconds; internal static ConfigEntry<float> NoSelfLogRadius; internal static ConfigEntry<bool> Uproot; internal static ConfigEntry<bool> Careful; internal static ConfigEntry<bool> Forester; internal static ConfigEntry<string> ForesterTrees; internal static ConfigEntry<float> AxePickupRange; internal static ConfigEntry<KeyCode> SizeModifier; internal static ConfigEntry<KeyCode> ModeKey; internal static ConfigEntry<KeyCode> ResetKey; private static readonly Dictionary<string, string> Warned = new Dictionary<string, string>(); private static string _forestryText; private static ForestryTable _forestry = ForestryTable.Empty; private static ConfigEntry<T> Server<T>(ConfigFile cfg, string section, string key, T value, string description, AcceptableValueBase range = null) { //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_001d: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return cfg.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } private static AcceptableValueRange<T> Range<T>(T min, T max) where T : IComparable { return new AcceptableValueRange<T>(min, max); } internal static void Bind(ConfigFile cfg) { Enabled = Server(cfg, "General", "Enabled", value: true, "false — режимы и операции инструментов отключены (горячие клавиши молчат). Предметы регистрируются всегда: иначе игра удалила бы уже выданные. Баланс: выключатель на случай перекоса экономики, предметы остаются в инвентарях обычными инструментами-основами."); Durability = Server(cfg, "General", "Durability", 800, "Прочность всех трёх инструментов (максимум, m_maxDurability). Больше — реже ремонт. У уже выданных предметов текущая прочность не меняется, меняется предел; ремонт — в чёрной кузне (рецепт-заглушка без изготовления).", (AcceptableValueBase)(object)Range(50, 10000)); LevelRadii = Server(cfg, "Hoe", "LevelRadii", HoeSizes.Level.Text, "Радиусы выравнивания, м, через запятую (1–8, до 6 значений; мусор отбрасывается). Колесо мыши с модификатором листает размеры. Срезать землю — бесплатно; подсыпать — камень по объёму насыпи по ставке RaiseStoneBase (насыпь меньше четверти эталона — бесплатно). Баланс: чем больше радиус, тем быстрее стройка; цена — выносливость (StaminaFactors) и камень за насыпь."); RaiseRadii = Server(cfg, "Hoe", "RaiseRadii", HoeSizes.RaiseRadius.Text, "Радиусы поднятия земли, м, через запятую (1–4). Баланс: цена в камне растёт с квадратом радиуса."); RaiseSteps = Server(cfg, "Hoe", "RaiseSteps", HoeSizes.RaiseStep.Text, "Высота шага поднятия, м, через запятую (0,25–2; десятичная точка). Баланс: цена в камне растёт пропорционально шагу."); PathWidths = Server(cfg, "Hoe", "PathWidths", HoeSizes.PathWidth.Text, "Ширина тропинки, м, через запятую (0,5–6). Высота не меняется. Бесплатно."); PaveWidths = Server(cfg, "Hoe", "PaveWidths", HoeSizes.PaveWidth.Text, "Ширина мощения, м, через запятую (1–8). Баланс: цена в камне растёт втрое при удвоении ширины."); RaiseStoneBase = Server(cfg, "Hoe", "RaiseStoneBase", 2, "Камней за шаг 0,5 м на радиусе 2 м; прочие размеры — пропорционально объёму: base × (r/2)² × (шаг/0,5), вверх. По той же ставке платится насыпь «Выровнять» и «Мощения»: ceil(base × V / 6,28 м³), V — поднимаемый объём. 0 — поднятие и насыпь бесплатны. Баланс: главный тормоз земляных валов (камень — ограниченный ресурс).", (AcceptableValueBase)(object)Range(0, 20)); PaveStoneBase = Server(cfg, "Hoe", "PaveStoneBase", 1, "Камней за мощение шириной 2 м; на 4 м втрое больше (степень log2(3)); насыпь — сверх этого по RaiseStoneBase. 0 — мостовая без базовой цены.", (AcceptableValueBase)(object)Range(0, 20)); StaminaFactors = Server(cfg, "Hoe", "StaminaFactors", HoeSizes.Stamina.Text, "Множители выносливости по номеру размера (малый, средний, большой) на каждый удар: 1 — как у ванильной мотыги. Короче списка размеров — последнее значение; 0,1–10."); PickaxeDamage = Server(cfg, "Pickaxe", "PickaxeDamage", 65f, "Урон киркой (m_pickaxe) по жилам и камню; у основы из чёрного металла — 65. Уровень инструмента и урон оружием не меняются. Баланс: добыча с жилы зависит от числа кусков, а не от урона; больше урон — быстрее добыча.", (AcceptableValueBase)(object)Range(1f, 500f)); AreaRadius = Server(cfg, "Pickaxe", "AreaRadius", 1.5f, "Радиус скола по площади, м: удар ломает все куски жилы в этом радиусе от точки попадания. Количество добычи не растёт, растёт скорость.", (AcceptableValueBase)(object)Range(0.5f, 5f)); HeavyRadius = Server(cfg, "Pickaxe", "HeavyRadius", 3f, "Радиус тяжёлого удара (вторичная атака), м.", (AcceptableValueBase)(object)Range(1f, 8f)); HeavyDamageFactor = Server(cfg, "Pickaxe", "HeavyDamageFactor", 1.5f, "Множитель урона тяжёлого удара.", (AcceptableValueBase)(object)Range(0.5f, 5f)); HeavyCostFactor = Server(cfg, "Pickaxe", "HeavyCostFactor", 3f, "Множитель выносливости и износа тяжёлого удара. Баланс: быстрее добыча, но тяжёлым ударом не выгоднее расходуется прочность.", (AcceptableValueBase)(object)Range(1f, 10f)); HeavyAnimation = Server(cfg, "Pickaxe", "HeavyAnimation", "swing_pickaxe", "Триггер анимации тяжёлого удара (вторичная атака). У ванильных кирок вторичной атаки нет; по умолчанию — тот же замах, что у обычного удара (swing_pickaxe), он точно есть в аниматоре игрока для кирки. Пусто — тяжёлого удара нет. Другие имена (например, sledge_attack, axe_secondary) не проверялись в игре."); WideDigRadius = Server(cfg, "Pickaxe", "WideDigRadius", 3f, "Радиус ямы в режиме «широкая копка», м. 0 — режим выключен.", (AcceptableValueBase)(object)Range(0f, 6f)); Light = Server(cfg, "Pickaxe", "Light", value: true, "Кирка светит, пока в руке (как факел)."); PickaxePickupRange = Server(cfg, "Pickaxe", "PickupRange", 6f, "С какого расстояния кирка подбирает добычу, м (0 — как у ванильной, стандартный подбор). Не увеличивает добычу.", (AcceptableValueBase)(object)Range(0f, 20f)); ChopDamage = Server(cfg, "Axe", "ChopDamage", 95f, "Урон рубкой (m_chop); у основы из чёрного металла — 95. Боевой урон и уровень не меняются.", (AcceptableValueBase)(object)Range(1f, 500f)); LogAreaRadius = Server(cfg, "Axe", "LogAreaRadius", 2f, "Радиус разделки: удар по лежащему бревну задевает все брёвна и половинки в радиусе, м. Стоящие деревья — по одному. Древесины столько же.", (AcceptableValueBase)(object)Range(0.5f, 6f)); DirectedFall = Server(cfg, "Axe", "DirectedFall", value: true, "Дерево падает от игрока."); NoSelfLogDamage = Server(cfg, "Axe", "NoSelfLogDamage", value: true, "Падающий ствол не ранит владельца топора: удар ствола (HitType.Tree) не проходит NoSelfLogSeconds секунд после его удара этим топором по дереву или бревну, если игрок не дальше NoSelfLogRadius от места этого удара. Чей ствол, игра не сообщает: в этом окне и радиусе не ранит и чужой ствол. Других игроков и существ стволы бьют как обычно."); NoSelfLogSeconds = Server(cfg, "Axe", "NoSelfLogSeconds", 10f, "Сколько секунд после своего удара по дереву или бревну действует защита от стволов.", (AcceptableValueBase)(object)Range(1f, 60f)); NoSelfLogRadius = Server(cfg, "Axe", "NoSelfLogRadius", 15f, "Защита от стволов действует, только пока игрок не дальше этого расстояния (м) от точки своего последнего удара по дереву или бревну. Баланс: меньше — уже зона, в которой игрока не ранит и чужой ствол.", (AcceptableValueBase)(object)Range(3f, 50f)); Uproot = Server(cfg, "Axe", "Uproot", value: true, "Разрешить режим корчевания: пень разрушается вместе с деревом и отдаёт свою древесину. false — режим недоступен."); Careful = Server(cfg, "Axe", "Careful", value: true, "Разрешить бережный режим: удары не повреждают постройки игроков и саженцы. false — режим недоступен."); Forester = Server(cfg, "Axe", "Forester", value: true, "«Лесник»: при наличии семени того же дерева в инвентаре на месте срубленного сажается саженец, семя тратится. Сажает только при корчевании (иначе пень не даст саженцу вырасти) и если место годится по ванильным условиям роста. Баланс: лес не вырубается насовсем, но каждый саженец стоит семени. Без таблицы ForesterTrees ничего не сажает."); ForesterTrees = Server(cfg, "Axe", "ForesterTrees", "Beech1=Beech_Sapling:BeechSeeds,Birch1=Birch_Sapling:BirchSeeds,Birch2=Birch_Sapling:BirchSeeds,Oak1=Oak_Sapling:Acorn,FirTree=FirTree_Sapling:FirCone,FirTree_big=FirTree_big_Sapling:FirConeFrost,Pinetree_01=PineTree_Sapling:PineCone", "Таблица «Лесника»: Дерево=Саженец:Семя через запятую (имена префабов). По умолчанию — ванильные пары l-1.0.21; деревьев без ванильного саженца (болотное, побеги Иггдрасиля, деревья Пепельных земель, снежные ели и сосны, осенние берёзы) в таблице нет. Пусто — «Лесник» ничего не сажает."); AxePickupRange = Server(cfg, "Axe", "PickupRange", 6f, "С какого расстояния топор подбирает добычу, м (0 — стандартный подбор). Прибавки к древесине нет.", (AcceptableValueBase)(object)Range(0f, 20f)); SizeModifier = cfg.Bind<KeyCode>("Keys", "SizeModifier", (KeyCode)308, "Клиентская (не рассылается). Колесо мыши при зажатой клавише листает размер мотыги (и не крутит камеру и деталь). EAQS использует LeftAlt только для перетаскивания своей панели, где инструмент размер не листает."); ModeKey = cfg.Bind<KeyCode>("Keys", "ModeKey", (KeyCode)107, "Клиентская. Переключение режима инструмента в руке. По умолчанию K: G занята ванильным радиальным меню, H — быстрым слотом 2 (EAQS, модпак)."); ResetKey = cfg.Bind<KeyCode>("Keys", "ResetKey", (KeyCode)108, "Клиентская. Сброс фиксации высоты мотыги."); } internal static float[] Sizes(SizeSlot slot) { return slot switch { SizeSlot.RaiseRadius => HoeSizes.RaiseRadius.Parse(RaiseRadii.Value), SizeSlot.RaiseStep => HoeSizes.RaiseStep.Parse(RaiseSteps.Value), SizeSlot.PathWidth => HoeSizes.PathWidth.Parse(PathWidths.Value), SizeSlot.PaveWidth => HoeSizes.PaveWidth.Parse(PaveWidths.Value), _ => HoeSizes.Level.Parse(LevelRadii.Value), }; } internal static float[] Stamina() { return HoeSizes.Stamina.Parse(StaminaFactors.Value); } internal static ForestryTable Forestry() { string value = ForesterTrees.Value; if (value != _forestryText) { _forestryText = value; _forestry = ForestryTable.Parse(value); if (_forestry.Errors.Count > 0) { Plugin.Log.LogWarning((object)("Sansara Tools: Axe.ForesterTrees — пропущены записи: " + string.Join("; ", _forestry.Errors.ToArray()))); } } return _forestry; } internal static void WarnBadLists() { WarnList("Hoe.LevelRadii", LevelRadii.Value, HoeSizes.Level); WarnList("Hoe.RaiseRadii", RaiseRadii.Value, HoeSizes.RaiseRadius); WarnList("Hoe.RaiseSteps", RaiseSteps.Value, HoeSizes.RaiseStep); WarnList("Hoe.PathWidths", PathWidths.Value, HoeSizes.PathWidth); WarnList("Hoe.PaveWidths", PaveWidths.Value, HoeSizes.PaveWidth); WarnList("Hoe.StaminaFactors", StaminaFactors.Value, HoeSizes.Stamina); } private static void WarnList(string name, string text, SizeSpec spec) { if (!Warned.TryGetValue(name, out var value) || !(value == text)) { Warned[name] = text; if (!SizeList.TryParse(text, spec.Fallback, spec.Min, spec.Max, out var _)) { Plugin.Log.LogWarning((object)$"Sansara Tools: {name} = «{text}» — нет подходящих чисел ({spec.Min}–{spec.Max}), действует значение по умолчанию {spec.Text}."); } } } } internal static class ToolState { internal static readonly HoeState Hoe = new HoeState(); internal static readonly PickaxeState Pickaxe = new PickaxeState(); internal static readonly AxeState Axe = new AxeState(); internal static bool SharpEdge { get { if (ToolConfig.Enabled.Value) { return Hoe.SharpEdge; } return false; } } internal static PickaxeMode PickaxeModeNow { get { if (!ToolConfig.Enabled.Value || (Pickaxe.Mode == PickaxeMode.WideDig && ToolConfig.WideDigRadius.Value <= 0f)) { return PickaxeMode.Normal; } return Pickaxe.Mode; } } internal static bool UprootNow { get { if (ToolConfig.Enabled.Value && ToolConfig.Uproot.Value) { return Axe.Uproot; } return false; } } internal static bool CarefulNow { get { if (ToolConfig.Enabled.Value && ToolConfig.Careful.Value) { return Axe.Careful; } return false; } } } internal static class ToolInput { private static bool _reading; private static int _heldFrame = -1; private static Player _heldPlayer; private static ToolKind _held; internal static ToolKind HeldKind() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return ToolKind.None; } int frameCount = Time.frameCount; if (frameCount != _heldFrame || localPlayer != _heldPlayer) { _heldFrame = frameCount; _heldPlayer = localPlayer; _held = ToolItems.KindOf(((Humanoid)localPlayer).RightItem); } return _held; } private static bool GameUiOpen() { if (!Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen() && !StoreGui.IsVisible()) { return TextInput.IsVisible(); } return true; } internal static void Tick() { //IL_0037: 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_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value) { return; } ToolKind toolKind = HeldKind(); if (toolKind == ToolKind.None || GameUiOpen()) { return; } if (ZInput.GetKeyDown(ToolConfig.ModeKey.Value, false)) { CycleMode(toolKind); } if (toolKind != ToolKind.Hoe) { return; } if (ZInput.GetKeyDown(ToolConfig.ResetKey.Value, false)) { ToolState.Hoe.ResetHeight(); Say("Мотыга: высота не зафиксирована, следующий удар «Выровнять» её запомнит"); } if (ZInput.GetKey(ToolConfig.SizeModifier.Value, false)) { float num = ReadWheel(); if (num != 0f) { StepSize((num > 0f) ? 1 : (-1)); } } } internal static bool ShouldSwallowWheel() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (_reading || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value) { return false; } if (HeldKind() != ToolKind.Hoe || GameUiOpen()) { return false; } return ZInput.GetKey(ToolConfig.SizeModifier.Value, false); } private static float ReadWheel() { _reading = true; try { return ZInput.GetMouseScrollWheel(); } finally { _reading = false; } } private static void StepSize(int delta) { HoeState hoe = ToolState.Hoe; SizeSlot activeSlot = hoe.ActiveSlot; float[] array = ToolConfig.Sizes(activeSlot); int num = hoe.Sizes.Step(activeSlot, delta, array.Length); string text = HoeControl.AfterSizeStep(); Say("Мотыга: " + ToolTexts.SlotName(activeSlot) + " " + ToolTexts.Meters(array[num]) + " (" + (num + 1) + "/" + array.Length + ")" + text); } private static void CycleMode(ToolKind kind) { switch (kind) { case ToolKind.Hoe: HoeControl.CycleMode(); break; case ToolKind.Pickaxe: { PickaxeMode mode = ToolState.Pickaxe.CycleMode(ToolConfig.WideDigRadius.Value > 0f); Say("Кирка: режим — " + ToolTexts.PickaxeModeName(mode)); break; } case ToolKind.Axe: { bool value = ToolConfig.Uproot.Value; bool value2 = ToolConfig.Careful.Value; if (!value && !value2) { Say("Топор: режимы отключены сервером"); break; } ToolState.Axe.CycleMode(value, value2); Say("Топор: корчевание " + ToolTexts.OnOff(ToolState.Axe.Uproot) + ", бережный " + ToolTexts.OnOff(ToolState.Axe.Careful)); break; } } } private static void Say(string text) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } } internal static class ToolItems { private static ItemDrop _hoe; private static ItemDrop _pickaxe; private static ItemDrop _axe; private static GameObject _hoeGo; private static GameObject _pickaxeGo; private static GameObject _axeGo; private static bool _dirty; private static ItemData _lastItem; private static SharedData _lastShared; private static GameObject _lastDrop; private static ToolKind _lastKind; internal const string RepairStation = "blackforge"; internal static void Register() { PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabs; } private static void OnVanillaPrefabs() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabs; _hoe = Make("SansaraHoe", "Hoe", "Мотыга Ивальди", "Мотыга, выкованная для больших строек: ровняет землю широким кругом и запоминает высоту. Не добывает больше, но экономит часы работы."); _pickaxe = Make("SansaraPickaxe", "PickaxeBlackMetal", "Кирка Синдри", "Кирка, которая берёт жилу целиком: один удар скалывает всё вокруг точки попадания, тяжёлый удар — ещё шире. Добычи с жилы столько же, сколько у обычной кирки."); _axe = Make("SansaraAxe", "AxeBlackMetal", "Топор Вёлунда", "Топор, который валит лес без остатка: разделывает брёвна разом, роняет деревья от дровосека и умеет корчевать пни. Древесины даёт столько же, сколько обычный."); _hoeGo = (((Object)(object)_hoe != (Object)null) ? ((Component)_hoe).gameObject : null); _pickaxeGo = (((Object)(object)_pickaxe != (Object)null) ? ((Component)_pickaxe).gameObject : null); _axeGo = (((Object)(object)_axe != (Object)null) ? ((Component)_axe).gameObject : null); _lastItem = null; ApplyConfig(); } private static ItemDrop Make(string prefab, string basePrefab, string displayName, string description) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown CustomItem val = new CustomItem(prefab, basePrefab); if ((Object)(object)val.ItemDrop == (Object)null) { Plugin.Log.LogError((object)("Sansara Tools: не удалось создать " + prefab + " из " + basePrefab + ".")); return null; } SharedData shared = val.ItemDrop.m_itemData.m_shared; shared.m_name = displayName; shared.m_description = description; if (ItemManager.Instance.AddItem(val)) { AddRepairRecipe(prefab); Plugin.Log.LogInfo((object)("Sansara Tools: предмет " + prefab + " (основа " + basePrefab + ") зарегистрирован, ремонт — blackforge.")); return val.ItemDrop; } Plugin.Log.LogError((object)("Sansara Tools: Jotunn не принял предмет " + prefab + ".")); return null; } private static void AddRepairRecipe(string prefab) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_001d: 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_002b: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown CustomRecipe val = new CustomRecipe(new RecipeConfig { Name = "Recipe_" + prefab, Item = prefab, Amount = 1, Enabled = false, CraftingStation = "blackforge", RepairStation = "blackforge", MinStationLevel = 1, Requirements = (RequirementConfig[])(object)new RequirementConfig[0] }); if (!ItemManager.Instance.AddRecipe(val)) { Plugin.Log.LogWarning((object)("Sansara Tools: Jotunn не принял рецепт ремонта " + prefab + " — ремонт этого предмета недоступен.")); } } internal static void ShareWithPrefab(ItemData item) { if (item == null) { return; } GameObject dropPrefab = item.m_dropPrefab; if (dropPrefab != null) { ItemDrop val = ((dropPrefab == _hoeGo) ? _hoe : ((dropPrefab == _pickaxeGo) ? _pickaxe : ((dropPrefab == _axeGo) ? _axe : null))); if ((Object)(object)val != (Object)null && item.m_shared != val.m_itemData.m_shared) { item.m_shared = val.m_itemData.m_shared; } } } internal static void MarkDirty() { _dirty = true; } internal static void ApplyIfDirty() { if (_dirty) { _dirty = false; ApplyConfig(); } } internal static void ApplyConfig() { HoeItem.Apply(_hoe); PickaxeItem.Apply(_pickaxe); AxeItem.Apply(_axe); ToolConfig.WarnBadLists(); } internal static ToolKind KindOf(ItemData item) { if (item == null) { return ToolKind.None; } if (item == _lastItem && item.m_shared == _lastShared && item.m_dropPrefab == _lastDrop) { return _lastKind; } ToolKind num = Classify(item); _lastItem = item; _lastShared = item.m_shared; _lastDrop = item.m_dropPrefab; _lastKind = num; return num; } private static ToolKind Classify(ItemData item) { if (item.m_shared != null) { if ((Object)(object)_hoe != (Object)null && item.m_shared == _hoe.m_itemData.m_shared) { return ToolKind.Hoe; } if ((Object)(object)_pickaxe != (Object)null && item.m_shared == _pickaxe.m_itemData.m_shared) { return ToolKind.Pickaxe; } if ((Object)(object)_axe != (Object)null && item.m_shared == _axe.m_itemData.m_shared) { return ToolKind.Axe; } } GameObject dropPrefab = item.m_dropPrefab; if (dropPrefab != null) { if (dropPrefab == _hoeGo) { return ToolKind.Hoe; } if (dropPrefab == _pickaxeGo) { return ToolKind.Pickaxe; } if (dropPrefab == _axeGo) { return ToolKind.Axe; } } ToolKind toolKind = ToolNames.Kind(((Object)(object)dropPrefab != (Object)null) ? ((Object)dropPrefab).name : null); if (toolKind != ToolKind.None || item.m_shared == null) { return toolKind; } return item.m_shared.m_name switch { "Мотыга Ивальди" => ToolKind.Hoe, "Кирка Синдри" => ToolKind.Pickaxe, "Топор Вёлунда" => ToolKind.Axe, _ => ToolKind.None, }; } } [HarmonyPatch(typeof(ItemDrop), "Awake")] internal static class ItemDropSharePatch { private static void Postfix(ItemDrop __instance) { ToolItems.ShareWithPrefab(__instance.m_itemData); } } internal static class ToolPickup { private static Player _player; private static float _original; private static bool _applied; internal static void Tick() { Player localPlayer = Player.m_localPlayer; if (_applied && localPlayer != _player) { _applied = false; _player = null; } if ((Object)(object)localPlayer == (Object)null) { return; } float num = 0f;