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 WispShovel v1.0.1
WispShovel.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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using WispShovel.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace WispShovel.Valheim { public sealed class AreaPreview : MonoBehaviour { private static readonly FieldInfo PlaceMask = AccessTools.Field(typeof(Player), "m_placeRayMask"); private readonly Vector3[] points = (Vector3[])(object)new Vector3[64]; private readonly float[] offsetsX = new float[64]; private readonly float[] offsetsZ = new float[64]; private readonly float[] relativeHeights = new float[64]; private ShovelControls? controls; private Func<Vector3, Area, bool>? canApply; private LineRenderer? line; private Material? material; private float nextUpdate; private bool sampledValid; private bool sampled; public void Initialize(ShovelControls input, Func<Vector3, Area, bool> actionCheck) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown if ((Object)(object)controls != (Object)null) { throw new InvalidOperationException("Area preview is already initialized."); } if (!Object.op_Implicit((Object)(object)input)) { throw new ArgumentNullException("input"); } controls = input; canApply = actionCheck ?? throw new ArgumentNullException("actionCheck"); if ((int)SystemInfo.graphicsDeviceType != 4) { Shader val = Shader.Find("Sprites/Default"); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("No suitable preview shader is available."); } material = new Material(val); GameObject val2 = new GameObject("WispShovelAreaPreview"); val2.transform.SetParent(((Component)this).transform, false); line = val2.AddComponent<LineRenderer>(); ((Renderer)line).sharedMaterial = material; line.useWorldSpace = true; line.loop = true; line.positionCount = points.Length; LineRenderer? obj = line; float startWidth = (line.endWidth = 0.035f); obj.startWidth = startWidth; ((Renderer)line).enabled = false; } } private void Update() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) if (line == null || !Object.op_Implicit((Object)(object)line) || (Object)(object)controls == (Object)null || !controls.IsControllable || !controls.PreviewEnabled || !Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { if (line != null && Object.op_Implicit((Object)(object)line)) { ((Renderer)line).enabled = false; } sampled = false; return; } if (!TryGetTarget(out var center, out var area)) { ((Renderer)line).enabled = false; sampled = false; return; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)area.ForwardX, 0f, (float)area.ForwardZ); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(val.z, 0f, 0f - val.x); if (!sampled || Time.unscaledTime >= nextUpdate) { nextUpdate = Time.unscaledTime + 0.1f; sampledValid = canApply != null && canApply(center, area); float num8 = default(float); for (int i = 0; i < points.Length; i++) { float num2; float num3; if (area.Shape == AreaShape.Circle) { float num = (float)i * (float)Math.PI * 2f / (float)points.Length; num2 = Mathf.Cos(num) * (float)area.Radius; num3 = Mathf.Sin(num) * (float)area.Radius; } else { int num4 = i / 16; float num5 = (float)(i % 16) / 16f; float num6 = (float)area.Width / 2f; float num7 = (float)area.Length / 2f; num2 = num4 switch { 2 => Mathf.Lerp(num6, 0f - num6, num5), 1 => num6, 0 => Mathf.Lerp(0f - num6, num6, num5), _ => 0f - num6, }; num3 = num4 switch { 2 => num7, 1 => Mathf.Lerp(0f - num7, num7, num5), 0 => 0f - num7, _ => Mathf.Lerp(num7, 0f - num7, num5), }; } offsetsX[i] = num2; offsetsZ[i] = num3; if (Heightmap.GetHeight(center + val2 * num2 + val * num3, ref num8)) { relativeHeights[i] = num8 - center.y + 0.05f; continue; } sampledValid = false; relativeHeights[i] = 0.05f; } sampled = true; } for (int j = 0; j < points.Length; j++) { Vector3 val3 = center + val2 * offsetsX[j] + val * offsetsZ[j]; val3.y = center.y + relativeHeights[j]; points[j] = val3; } line.SetPositions(points); LineRenderer? obj = line; Color startColor = (line.endColor = (sampledValid ? Color.green : Color.red)); obj.startColor = startColor; ((Renderer)line).enabled = true; } public bool TryGetTarget(out Vector3 center, out Area area) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) center = default(Vector3); area = default(Area); if ((Object)(object)controls == (Object)null || !controls.IsControllable || !Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } Transform transform = ((Component)GameCamera.instance).transform; Player localPlayer = Player.m_localPlayer; int num = (int)PlaceMask.GetValue(localPlayer); RaycastHit val = default(RaycastHit); if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, num) || !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) || Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody) || !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponent<Heightmap>()) || Vector3.Distance(((Character)localPlayer).GetEyePoint(), ((RaycastHit)(ref val)).point) >= localPlayer.m_maxPlaceDistance) { return false; } Vector3 lookDir = ((Character)localPlayer).GetLookDir(); lookDir.y = 0f; if (((Vector3)(ref lookDir)).sqrMagnitude < 0.0001f) { return false; } ((Vector3)(ref lookDir)).Normalize(); center = ((RaycastHit)(ref val)).point; area = controls.State.AreaFacing(lookDir.x, lookDir.z); return true; } private void OnDestroy() { if (line != null && Object.op_Implicit((Object)(object)line)) { Object.Destroy((Object)(object)((Component)line).gameObject); } if (Object.op_Implicit((Object)(object)material)) { Object.Destroy((Object)(object)material); } } } internal static class ConfigLayout { internal static void Initialize(ConfigFile file) { file.SettingChanged += delegate { Save(file); }; Save(file); } private static void Save(ConfigFile file) { try { file.Save(); Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); string text = ""; string[] array = File.ReadAllLines(file.ConfigFilePath); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("[") && text3.EndsWith("]")) { text = text3.Substring(1, text3.Length - 2); if (!dictionary.ContainsKey(text)) { dictionary.Add(text, new List<string>()); } continue; } switch (text) { case "": case "Recipe": case "Durability": case "Dig": continue; } if (!text3.StartsWith("# Setting type:") && !text3.StartsWith("# Acceptable values:") && (!(text == "General") || !(text3 == "# Default value: false")) && !text3.StartsWith("DurableActionSaves =") && !text3.StartsWith("ActionCooldown =") && !text3.StartsWith("Height =") && !text3.StartsWith("MinHeight =") && !text3.StartsWith("MaxHeight =") && !text3.Contains("Save the character and world for every action")) { dictionary[text].Add(text2); } } StringBuilder stringBuilder = new StringBuilder(); array = new string[5] { "General", "Area", "Controls", "Raise", "Visual" }; foreach (string text4 in array) { if (!dictionary.TryGetValue(text4, out var value)) { continue; } stringBuilder.Append('[').Append(text4).AppendLine("]"); foreach (string item in value) { stringBuilder.AppendLine(item); } stringBuilder.AppendLine(); } File.WriteAllText(file.ConfigFilePath, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } catch (Exception ex) { Debug.LogError((object)("WispShovel: could not save configuration: " + ex)); } } } internal readonly struct TerrainRevision { internal readonly ZDOID Id; internal readonly uint Revision; internal TerrainRevision(ZDOID id, uint revision) { //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) Id = id; Revision = revision; } } internal sealed class TerrainActionFailedException : Exception { public TerrainActionFailedException(Exception inner) : base("Terrain action was rolled back before saving.", inner) { } } internal sealed class TerrainOutcomeIndeterminateException : Exception { public TerrainOutcomeIndeterminateException(Exception inner) : base("Terrain action outcome is indeterminate.", inner) { } } internal static class LocalTerrainMutation { private sealed class Chunk { public Heightmap Map; public TerrainComp Compiler; public float[] Level; public float[] Smooth; public bool[] ModifiedHeight; public Color[] Paint; public bool[] ModifiedPaint; public float[]? LevelBefore; public float[]? SmoothBefore; public bool[]? HeightBefore; public Color[]? PaintBefore; public bool[]? PaintModifiedBefore; public readonly List<Sample> Samples = new List<Sample>(); } private struct Sample { public int Index; public int X; public int Y; public float Level; public float Smooth; public float Height; public bool Modified; public Color Paint; public Color VisiblePaint; } private static readonly FieldInfo Initialized = RequiredField("m_initialized"); private static readonly FieldInfo HeightmapField = RequiredField("m_hmap"); private static readonly FieldInfo Width = RequiredField("m_width"); private static readonly FieldInfo Level = RequiredField("m_levelDelta"); private static readonly FieldInfo Smooth = RequiredField("m_smoothDelta"); private static readonly FieldInfo ModifiedHeight = RequiredField("m_modifiedHeight"); private static readonly FieldInfo Paint = RequiredField("m_paintMask"); private static readonly FieldInfo ModifiedPaint = RequiredField("m_modifiedPaint"); private static readonly FieldInfo Operations = RequiredField("m_operations"); private static readonly FieldInfo LastPoint = RequiredField("m_lastOpPoint"); private static readonly FieldInfo LastRadius = RequiredField("m_lastOpRadius"); private static readonly MethodInfo Save = AccessTools.Method(typeof(TerrainComp), "Save", new Type[1] { typeof(bool) }, (Type[])null) ?? throw new MissingMethodException("TerrainComp.Save(bool)"); private static readonly MethodInfo RaiseTerrain = AccessTools.Method(typeof(TerrainComp), "RaiseTerrain", new Type[5] { typeof(Vector3), typeof(float), typeof(float), typeof(bool), typeof(float) }, (Type[])null) ?? throw new MissingMethodException("TerrainComp.RaiseTerrain"); private static readonly MethodInfo LevelTerrain = AccessTools.Method(typeof(TerrainComp), "LevelTerrain", new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null) ?? throw new MissingMethodException("TerrainComp.LevelTerrain"); private static readonly MethodInfo PaintCleared = AccessTools.Method(typeof(TerrainComp), "PaintCleared", new Type[3] { typeof(Vector3), typeof(Vector3), typeof(Settings) }, (Type[])null) ?? throw new MissingMethodException("TerrainComp.PaintCleared"); private const float Epsilon = 0.0001f; private static FieldInfo RequiredField(string name) { return AccessTools.Field(typeof(TerrainComp), name) ?? throw new MissingFieldException("TerrainComp", name); } internal static bool Apply(Vector3 center, Area area, ToolMode mode, float magnitude) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return ApplyCore(center, area, mode, magnitude, serverAuthorized: false); } catch (TerrainOutcomeIndeterminateException) { throw; } catch (Exception inner) { throw new TerrainActionFailedException(inner); } } internal static bool ApplyServerAuthorized(Vector3 center, Area area, ToolMode mode, float magnitude) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return ApplyCore(center, area, mode, magnitude, serverAuthorized: true); } catch (TerrainOutcomeIndeterminateException) { throw; } catch (Exception inner) { throw new TerrainActionFailedException(inner); } } internal static bool ApplyOwnerAuthorized(Vector3 center, Area area, ToolMode mode, float magnitude, List<TerrainRevision> revisions) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (revisions == null) { throw new ArgumentNullException("revisions"); } try { return ApplyCore(center, area, mode, magnitude, serverAuthorized: false, ownerAuthorized: true, revisions); } catch (TerrainOutcomeIndeterminateException) { throw; } catch (Exception inner) { throw new TerrainActionFailedException(inner); } } private static bool ApplyCore(Vector3 center, Area area, ToolMode mode, float magnitude, bool serverAuthorized, bool ownerAuthorized = false, List<TerrainRevision>? revisions = null) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_0878: Unknown result type (might be due to invalid IL or missing references) //IL_0749: Unknown result type (might be due to invalid IL or missing references) //IL_074e: Unknown result type (might be due to invalid IL or missing references) //IL_0a45: Unknown result type (might be due to invalid IL or missing references) //IL_0a4a: Unknown result type (might be due to invalid IL or missing references) //IL_0a4c: Unknown result type (might be due to invalid IL or missing references) //IL_0a55: Unknown result type (might be due to invalid IL or missing references) //IL_08eb: Unknown result type (might be due to invalid IL or missing references) //IL_0929: Unknown result type (might be due to invalid IL or missing references) //IL_092e: Unknown result type (might be due to invalid IL or missing references) //IL_0933: Unknown result type (might be due to invalid IL or missing references) //IL_0937: Unknown result type (might be due to invalid IL or missing references) //IL_093e: Unknown result type (might be due to invalid IL or missing references) //IL_0946: Unknown result type (might be due to invalid IL or missing references) //IL_094d: Unknown result type (might be due to invalid IL or missing references) //IL_075b: Unknown result type (might be due to invalid IL or missing references) //IL_0754: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_0651: Unknown result type (might be due to invalid IL or missing references) //IL_0658: Unknown result type (might be due to invalid IL or missing references) //IL_0a6c: Unknown result type (might be due to invalid IL or missing references) //IL_0a75: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0760: Unknown result type (might be due to invalid IL or missing references) //IL_0770: Unknown result type (might be due to invalid IL or missing references) //IL_0777: Unknown result type (might be due to invalid IL or missing references) //IL_077e: Unknown result type (might be due to invalid IL or missing references) //IL_0785: Unknown result type (might be due to invalid IL or missing references) //IL_078c: Unknown result type (might be due to invalid IL or missing references) //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_0a8c: Unknown result type (might be due to invalid IL or missing references) //IL_0a95: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0661: Unknown result type (might be due to invalid IL or missing references) //IL_0666: Unknown result type (might be due to invalid IL or missing references) //IL_067a: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Unknown result type (might be due to invalid IL or missing references) //IL_0699: Expected O, but got Unknown //IL_06ad: Unknown result type (might be due to invalid IL or missing references) //IL_06b6: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0d50: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_06ea: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_0dd8: Unknown result type (might be due to invalid IL or missing references) //IL_0df5: Unknown result type (might be due to invalid IL or missing references) //IL_0e35: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } bool num; if (!serverAuthorized) { if (!ownerAuthorized && !ZNet.IsSinglePlayer) { goto IL_003e; } num = !Object.op_Implicit((Object)(object)Player.m_localPlayer); } else { num = !ZNet.instance.IsServer(); } if (!num) { if (float.IsNaN(magnitude) || float.IsInfinity(magnitude) || magnitude < 0.1f || magnitude > 3f) { throw new ArgumentOutOfRangeException("magnitude"); } if (!Enum.IsDefined(typeof(ToolMode), mode)) { throw new ArgumentOutOfRangeException("mode"); } float num2 = ((area.Shape == AreaShape.Circle) ? ((float)area.Radius) : ((float)Math.Sqrt(area.Width * area.Width + area.Length * area.Length) / 2f)); if (float.IsNaN(num2) || float.IsInfinity(num2) || num2 <= 0f || num2 > 32f) { return false; } if (!TerrainProtection.OutsideNoBuildLocations(center, num2)) { return false; } if (!serverAuthorized && !PrivateArea.CheckAccess(center, num2, false, true)) { return false; } List<Heightmap> list = new List<Heightmap>(); Heightmap.FindHeightmap(center, num2 + 1f, list); if (list.Count == 0) { return false; } List<Chunk> list2 = new List<Chunk>(); HashSet<Heightmap> hashSet = new HashSet<Heightmap>(); int num5 = default(int); int num6 = default(int); foreach (Heightmap item2 in list) { if (!Object.op_Implicit((Object)(object)item2) || !hashSet.Add(item2)) { continue; } TerrainComp andCreateTerrainCompiler = item2.GetAndCreateTerrainCompiler(); if (!Object.op_Implicit((Object)(object)andCreateTerrainCompiler) || !andCreateTerrainCompiler.IsOwner() || !(bool)Initialized.GetValue(andCreateTerrainCompiler) || HeightmapField.GetValue(andCreateTerrainCompiler) != item2) { return false; } Chunk chunk = new Chunk { Map = item2, Compiler = andCreateTerrainCompiler, Level = (float[])Level.GetValue(andCreateTerrainCompiler), Smooth = (float[])Smooth.GetValue(andCreateTerrainCompiler), ModifiedHeight = (bool[])ModifiedHeight.GetValue(andCreateTerrainCompiler), Paint = (Color[])Paint.GetValue(andCreateTerrainCompiler), ModifiedPaint = (bool[])ModifiedPaint.GetValue(andCreateTerrainCompiler) }; int num3 = (int)Width.GetValue(andCreateTerrainCompiler); int num4 = num3 + 1; if (num3 != item2.m_width || chunk.Level.Length != num4 * num4 || chunk.Smooth.Length != num4 * num4 || chunk.ModifiedHeight.Length != num4 * num4 || chunk.Paint.Length != num4 * num4 || chunk.ModifiedPaint.Length != num4 * num4) { throw new InvalidOperationException("Unexpected terrain compiler dimensions."); } item2.WorldToVertex(center, ref num5, ref num6); int num7 = Mathf.CeilToInt((num2 + item2.m_scale) / item2.m_scale); for (int i = Math.Max(0, num6 - num7); i <= Math.Min(num3, num6 + num7); i++) { for (int j = Math.Max(0, num5 - num7); j <= Math.Min(num3, num5 + num7); j++) { Vector3 val = ((mode == ToolMode.Road || mode == ToolMode.Path) ? item2.VertexMaskToWorld(j, i) : (((Component)item2).transform.position + new Vector3(((float)j - (float)num3 * 0.5f) * item2.m_scale, 0f, ((float)i - (float)num3 * 0.5f) * item2.m_scale))); if (!area.Contains(val.x - center.x, val.z - center.z)) { continue; } int num8 = i * num4 + j; Sample item = new Sample { Index = num8, X = j, Y = i }; if (mode == ToolMode.Road || mode == ToolMode.Path) { item.Paint = chunk.Paint[num8]; item.Modified = chunk.ModifiedPaint[num8]; Color val2 = (item.VisiblePaint = item2.GetPaintMask(j, i)); Color val3 = ((mode == ToolMode.Path) ? Heightmap.m_paintMaskDirt : Heightmap.m_paintMaskPaved); if (Mathf.Abs(val2.r - val3.r) < 0.0001f && Mathf.Abs(val2.g - val3.g) < 0.0001f && Mathf.Abs(val2.b - val3.b) < 0.0001f) { continue; } } else { item.Level = chunk.Level[num8]; item.Smooth = chunk.Smooth[num8]; item.Modified = chunk.ModifiedHeight[num8]; item.Height = item2.GetHeight(j, i); } chunk.Samples.Add(item); } } if (chunk.Samples.Count > 0) { list2.Add(chunk); } } if (list2.Count == 0) { return false; } bool flag = mode == ToolMode.Road || mode == ToolMode.Path; try { int num9 = default(int); int num10 = default(int); foreach (Chunk item3 in list2) { if (flag) { item3.Map.WorldToVertexMask(center, ref num9, ref num10); int num11 = Mathf.CeilToInt((num2 + item3.Map.m_scale) / item3.Map.m_scale); if (num9 - num11 > 0 && num10 - num11 > 0 && num9 + num11 < item3.Map.m_width && num10 + num11 < item3.Map.m_width) { item3.PaintBefore = (Color[])item3.Paint.Clone(); item3.PaintModifiedBefore = (bool[])item3.ModifiedPaint.Clone(); bool[] array = new bool[item3.Paint.Length]; foreach (Sample sample2 in item3.Samples) { array[sample2.Index] = true; } Settings val4 = new Settings { m_level = false, m_raise = false, m_smooth = false, m_paintCleared = true, m_paintType = (PaintType)((mode != ToolMode.Path) ? 2 : 0), m_paintRadius = num2 + item3.Map.m_scale, m_paintStrength = 1f, m_paintExp = 0f, m_halfOffset = false }; PaintCleared.Invoke(item3.Compiler, new object[3] { center, Vector3.zero, val4 }); for (int k = 0; k < array.Length; k++) { if (!array[k]) { item3.Paint[k] = item3.PaintBefore[k]; item3.ModifiedPaint[k] = item3.PaintModifiedBefore[k]; } } } else { foreach (Sample sample3 in item3.Samples) { Color paintMask = item3.Map.GetPaintMask(sample3.X, sample3.Y); Color val5 = ((mode == ToolMode.Path) ? Heightmap.m_paintMaskDirt : Heightmap.m_paintMaskPaved); item3.Paint[sample3.Index] = new Color(val5.r, val5.g, val5.b, paintMask.a); item3.ModifiedPaint[sample3.Index] = true; } } } if (!flag) { item3.LevelBefore = (float[])item3.Level.Clone(); item3.SmoothBefore = (float[])item3.Smooth.Clone(); item3.HeightBefore = (bool[])item3.ModifiedHeight.Clone(); if (mode == ToolMode.Level) { LevelTerrain.Invoke(item3.Compiler, new object[3] { center, num2 + item3.Map.m_scale, true }); } else { float num12 = ((mode == ToolMode.Dig) ? (-0.5f) : magnitude); RaiseTerrain.Invoke(item3.Compiler, new object[5] { center, num2 + item3.Map.m_scale, num12, true, 0f }); } int width = item3.Map.m_width; int num13 = width + 1; for (int l = 0; l <= width; l++) { for (int m = 0; m <= width; m++) { Vector3 val6 = ((Component)item3.Map).transform.position + new Vector3(((float)m - (float)width * 0.5f) * item3.Map.m_scale, 0f, ((float)l - (float)width * 0.5f) * item3.Map.m_scale); if (!area.Contains(val6.x - center.x, val6.z - center.z)) { int num14 = l * num13 + m; item3.Level[num14] = item3.LevelBefore[num14]; item3.Smooth[num14] = item3.SmoothBefore[num14]; item3.ModifiedHeight[num14] = item3.HeightBefore[num14]; } } } } item3.Map.Poke(0, flag); } foreach (Chunk item4 in list2) { bool flag2 = false; for (int num15 = item4.Samples.Count - 1; num15 >= 0; num15--) { Sample sample = item4.Samples[num15]; bool flag3; if (flag) { Color paintMask2 = item4.Map.GetPaintMask(sample.X, sample.Y); flag3 = Mathf.Abs(paintMask2.r - sample.VisiblePaint.r) > 0.0001f || Mathf.Abs(paintMask2.g - sample.VisiblePaint.g) > 0.0001f || Mathf.Abs(paintMask2.b - sample.VisiblePaint.b) > 0.0001f; } else { float num16 = item4.Map.GetHeight(sample.X, sample.Y) - sample.Height; flag3 = mode switch { ToolMode.Dig => num16 < -0.0001f, ToolMode.Level => Mathf.Abs(num16) > 0.0001f, _ => num16 > 0.0001f, }; } if (!flag3) { Restore(item4, sample, flag); item4.Samples.RemoveAt(num15); flag2 = true; } } if (flag2) { item4.Map.Poke(0, flag); } } list2.RemoveAll((Chunk c) => c.Samples.Count == 0); } catch (Exception ex) { try { foreach (Chunk item5 in list2) { if (!flag && item5.LevelBefore != null && item5.SmoothBefore != null && item5.HeightBefore != null) { Array.Copy(item5.LevelBefore, item5.Level, item5.Level.Length); Array.Copy(item5.SmoothBefore, item5.Smooth, item5.Smooth.Length); Array.Copy(item5.HeightBefore, item5.ModifiedHeight, item5.ModifiedHeight.Length); } else if (flag && item5.PaintBefore != null && item5.PaintModifiedBefore != null) { Array.Copy(item5.PaintBefore, item5.Paint, item5.Paint.Length); Array.Copy(item5.PaintModifiedBefore, item5.ModifiedPaint, item5.ModifiedPaint.Length); } else { foreach (Sample sample4 in item5.Samples) { Restore(item5, sample4, flag); } } item5.Map.Poke(0, flag); } } catch (Exception ex2) { throw new TerrainOutcomeIndeterminateException(new AggregateException(ex, ex2)); } throw; } if (list2.Count == 0) { return false; } try { foreach (Chunk item6 in list2) { Operations.SetValue(item6.Compiler, (int)Operations.GetValue(item6.Compiler) + 1); LastPoint.SetValue(item6.Compiler, center); LastRadius.SetValue(item6.Compiler, num2); Save.Invoke(item6.Compiler, new object[1] { false }); if (revisions != null) { ZNetView component = ((Component)item6.Compiler).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { throw new InvalidOperationException("Terrain ownership changed while saving."); } ZDO zDO = component.GetZDO(); revisions.Add(new TerrainRevision(zDO.m_uid, zDO.DataRevision)); ZDOMan.instance.ForceSendZDO(zDO.m_uid); } } } catch (Exception inner) { throw new TerrainOutcomeIndeterminateException(inner); } try { if (Object.op_Implicit((Object)(object)ClutterSystem.instance)) { ClutterSystem.instance.ResetGrass(center, num2); } } catch (Exception ex3) { Debug.LogWarning((object)("WispShovel: could not refresh clutter: " + ex3.Message)); } return true; } goto IL_003e; IL_003e: return false; } private static void Restore(Chunk chunk, Sample sample, bool paintOnly) { //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) if (paintOnly) { chunk.Paint[sample.Index] = sample.Paint; chunk.ModifiedPaint[sample.Index] = sample.Modified; } else { chunk.Level[sample.Index] = sample.Level; chunk.Smooth[sample.Index] = sample.Smooth; chunk.ModifiedHeight[sample.Index] = sample.Modified; } } } internal sealed class LocationProtectionIndex : IDisposable { private readonly Dictionary<string, float> radii = new Dictionary<string, float>(StringComparer.Ordinal); private bool ready; private bool disposed; internal bool Ready { get { if (ready && !disposed) { return Object.op_Implicit((Object)(object)ZoneSystem.instance); } return false; } } internal IEnumerator Initialize() { ready = false; radii.Clear(); while (!disposed && (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Object.op_Implicit((Object)(object)ZoneSystem.instance))) { yield return null; } if (disposed) { yield break; } ZoneSystem zones = ZoneSystem.instance; foreach (ZoneLocation location in zones.m_locations) { if (disposed || !Object.op_Implicit((Object)(object)zones) || (Object)(object)zones != (Object)(object)ZoneSystem.instance) { yield break; } if (location == null || !location.m_prefab.IsValid) { yield return null; continue; } string name = location.m_prefab.Name; if (radii.ContainsKey(name)) { yield return null; continue; } bool flag = false; try { location.m_prefab.Load(); flag = true; GameObject asset = location.m_prefab.Asset; Location val = (Object.op_Implicit((Object)(object)asset) ? asset.GetComponent<Location>() : null); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("Location prefab is unavailable: " + name); } float num = ((!val.m_noBuild) ? (-1f) : ((val.m_noBuildRadiusOverride > 0f) ? val.m_noBuildRadiusOverride : val.GetMaxRadius())); if (float.IsNaN(num) || float.IsInfinity(num) || (val.m_noBuild && num < 0f) || num > 4096f) { throw new InvalidOperationException("Invalid no-build radius: " + name); } radii.Add(name, num); } catch (Exception ex) { Debug.LogError((object)("WispShovel: cannot index location protection: " + ex)); yield break; } finally { if (flag) { location.m_prefab.Release(); } } yield return null; } ready = !disposed && Object.op_Implicit((Object)(object)zones) && (Object)(object)zones == (Object)(object)ZoneSystem.instance; } internal bool OutsideNoBuildLocations(Vector3 center, float areaRadius) { //IL_002c: 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_0046: 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_0079: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!ready || disposed || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || areaRadius <= 0f || areaRadius > 32f || float.IsNaN(center.x) || float.IsInfinity(center.x) || float.IsNaN(center.z) || float.IsInfinity(center.z)) { return false; } foreach (LocationInstance location in ZoneSystem.instance.GetLocationList()) { if (location.m_location == null || !location.m_location.m_prefab.IsValid || !radii.TryGetValue(location.m_location.m_prefab.Name, out var value)) { return false; } if (!(value < 0f)) { Vector3 position = location.m_position; if (float.IsNaN(position.x) || float.IsInfinity(position.x) || float.IsNaN(position.z) || float.IsInfinity(position.z)) { return false; } float num = center.x - position.x; float num2 = center.z - position.z; float num3 = value + areaRadius; if (num * num + num2 * num2 < num3 * num3) { return false; } } } return true; } public void Dispose() { disposed = true; ready = false; radii.Clear(); } } internal static class NativeShovelMenu { private static readonly Dictionary<Piece, ToolMode> Modes = new Dictionary<Piece, ToolMode>(); private static readonly Dictionary<Piece, string> Descriptions = new Dictionary<Piece, string>(); internal static PieceTable? Table { get; private set; } internal static PieceTable Create(PieceTable source, Sprite shovelIcon) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)source)) { throw new InvalidOperationException("The vanilla hoe piece table is unavailable."); } GameObject val = new GameObject("WispShovelModeTable"); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); PieceTable val2 = val.AddComponent<PieceTable>(); val2.m_hideAdvancedMenu = true; val2.m_canRemovePieces = false; string[] array = new string[5] { "$wispshovel_dig", "$wispshovel_raise", "$wispshovel_pave", "$wispshovel_level", "$wispshovel_path" }; string[] array2 = new string[5] { "", "raise_v2", "paved_road_v2", "mud_road_v2", "path_v2" }; for (int i = 0; i < array.Length; i++) { Sprite icon = shovelIcon; string text = ""; foreach (GameObject piece in source.m_pieces) { if (!Object.op_Implicit((Object)(object)piece) || ((Object)piece).name != array2[i]) { continue; } Piece component = piece.GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component)) { if (Object.op_Implicit((Object)(object)component.m_icon)) { icon = component.m_icon; } text = component.m_description; } break; } if (array2[i] != "" && text == "") { GameObject prefab = PrefabManager.Instance.GetPrefab(array2[i]); Piece val3 = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null); if (Object.op_Implicit((Object)(object)val3)) { if (Object.op_Implicit((Object)(object)val3.m_icon)) { icon = val3.m_icon; } text = val3.m_description; } } GameObject val4 = new GameObject("WispShovelMode" + i); val4.transform.SetParent(val.transform, false); Piece val5 = val4.AddComponent<Piece>(); val5.m_name = array[i]; val5.m_description = ((i == 0) ? "$wispshovel_dig_description" : text); val5.m_icon = icon; val5.m_category = (PieceCategory)0; GameObject prefab2 = PrefabManager.Instance.GetPrefab("Stone"); ItemDrop val6 = (Object.op_Implicit((Object)(object)prefab2) ? prefab2.GetComponent<ItemDrop>() : null); val5.m_resources = (Requirement[])(((i == 1 || i == 2) && Object.op_Implicit((Object)(object)val6)) ? ((Array)new Requirement[1] { new Requirement { m_resItem = val6, m_amount = 1, m_amountPerLevel = 0, m_recover = false } }) : ((Array)Array.Empty<Requirement>())); val2.m_pieces.Add(val4); Modes.Add(val5, (ToolMode)i); Descriptions.Add(val5, val5.m_description); } Table = val2; return val2; } internal static bool TryGetMode(Piece piece, out ToolMode mode) { return Modes.TryGetValue(piece, out mode); } internal static void UpdateDescription(Piece piece, string area) { if (Descriptions.TryGetValue(piece, out string value)) { piece.m_description = value + (string.IsNullOrEmpty(area) ? "" : ("\n" + area)); } } internal static void UpdateCosts(Area area, int raiseCost) { foreach (KeyValuePair<Piece, ToolMode> mode in Modes) { if (mode.Key.m_resources.Length != 0) { mode.Key.m_resources[0].m_amount = ((mode.Value == ToolMode.Road) ? area.PavingStoneCost() : raiseCost); } } } internal static void Dispose() { if (Object.op_Implicit((Object)(object)Table)) { Object.Destroy((Object)(object)((Component)Table).gameObject); } Table = null; Modes.Clear(); Descriptions.Clear(); } } internal sealed class NetworkActions : MonoBehaviour { private static readonly FieldInfo RightItem = AccessTools.Field(typeof(Humanoid), "m_rightItem"); private ShovelControls? controls; private AreaPreview? preview; private ShovelConfig? config; private TerrainNetwork? network; private GameObject? stonePrefab; private string stoneName = ""; private const float ActionDelay = 0.4f; private float nextAction; private float nextQuery; private static float BuildStamina(Player player, ItemData item) { float num = item.m_shared.m_attack.m_attackStamina * (1f + ((Character)player).GetEquipmentHomeItemModifier()); ((Character)player).GetSEMan().ModifyHomeItemStaminaUsage(num, ref num, true); return Mathf.Max(0f, num); } internal void Initialize(ShovelControls input, AreaPreview areaPreview, ShovelConfig settings, TerrainNetwork channel, GameObject stone) { if (!Object.op_Implicit((Object)(object)input) || !Object.op_Implicit((Object)(object)areaPreview) || !Object.op_Implicit((Object)(object)stone) || settings == null || channel == null) { throw new ArgumentNullException("Missing action dependency."); } ItemDrop component = stone.GetComponent<ItemDrop>(); if (!Object.op_Implicit((Object)(object)component) || component.m_itemData?.m_shared == null) { throw new InvalidOperationException("Stone prefab is not an item."); } controls = input; preview = areaPreview; config = settings; network = channel; stonePrefab = stone; stoneName = component.m_itemData.m_shared.m_name; network.Response += OnResponse; } internal bool CanApply(Vector3 center, Area area) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)controls == (Object)null || config == null || !Object.op_Implicit((Object)(object)ZNet.instance) || !controls.IsControllable || Time.time < nextAction) { return false; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)stonePrefab)) { return false; } object? value = RightItem.GetValue(localPlayer); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val == null || val.m_durability <= 0f || HasPending(((Humanoid)localPlayer).GetInventory())) { return false; } if (!((Character)localPlayer).HaveStamina(BuildStamina(localPlayer, val))) { return false; } float num = ((area.Shape == AreaShape.Circle) ? ((float)area.Radius) : ((float)Math.Sqrt(area.Width * area.Width + area.Length * area.Length) / 2f)); if (num > 0f && num <= 32f && TerrainProtection.OutsideNoBuildLocations(center, num) && PrivateArea.CheckAccess(center, num, false, true)) { return ((Humanoid)localPlayer).GetInventory().CountItems(stoneName, -1, false) >= StoneCost(controls.State.Mode, area, config, localPlayer.NoCostCheat()); } return false; } private static int StoneCost(ToolMode mode, Area area, ShovelConfig settings, bool freeBuild) { if (!freeBuild) { return mode switch { ToolMode.Road => area.PavingStoneCost(), ToolMode.Raise => settings.RaiseStoneCost.Value, _ => 0, }; } return 0; } private void Update() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0438: 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)ZNet.instance) && network != null && Time.unscaledTime >= nextQuery) { nextQuery = Time.unscaledTime + 5f; QueryPending(localPlayer); } if ((Object)(object)controls == (Object)null || (Object)(object)preview == (Object)null || config == null || network == null || !controls.IsControllable || !ZInput.GetButtonDown("Attack") || !preview.TryGetTarget(out var center, out var area)) { return; } localPlayer = Player.m_localPlayer; if (!CanApply(center, area)) { if (Object.op_Implicit((Object)(object)localPlayer) && HasPending(((Humanoid)localPlayer).GetInventory())) { Message(localPlayer, "wispshovel_wait"); return; } if (Object.op_Implicit((Object)(object)localPlayer)) { object? value = RightItem.GetValue(localPlayer); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val != null && !((Character)localPlayer).HaveStamina(BuildStamina(localPlayer, val))) { if (Object.op_Implicit((Object)(object)Hud.instance)) { Hud.instance.StaminaBarEmptyFlash(); } Message(localPlayer, "wispshovel_stamina"); return; } } if (Object.op_Implicit((Object)(object)localPlayer) && ((Humanoid)localPlayer).GetInventory().CountItems(stoneName, -1, false) < StoneCost(controls.State.Mode, area, config, localPlayer.NoCostCheat())) { Message(localPlayer, "wispshovel_stone"); } return; } ItemData val2 = (ItemData)RightItem.GetValue(localPlayer); ToolMode mode = controls.State.Mode; if (mode == ToolMode.Level && !ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyAltPlace")) { if (!Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return; } center.y = ZoneSystem.instance.GetGroundHeight(((Component)localPlayer).transform.position); } int num = StoneCost(mode, area, config, localPlayer.NoCostCheat()); int stoneReward = ((mode == ToolMode.Dig && config.EnableStoneDrops.Value) ? ((!(Random.value < 0.5f)) ? Random.Range(1, 3) : 0) : 0); float durabilityCost = mode switch { ToolMode.Level => 1f, ToolMode.Raise => 1f, ToolMode.Dig => 1f, _ => 1f, }; float magnitude = ((mode == ToolMode.Raise) ? ((float)controls.State.RaiseHeight) : 0.5f); Guid id = Guid.NewGuid(); TerrainRequest terrainRequest; try { terrainRequest = TerrainRequest.Create(id, ((Character)localPlayer).GetZDOID(), center, new Vector3((float)area.ForwardX, 0f, (float)area.ForwardZ), controls.State, magnitude, config.MaxSize.Value); } catch (ArgumentException ex) { Debug.LogWarning((object)("WispShovel: invalid area: " + ex.Message)); return; } long worldUID = ZNet.instance.GetWorldUID(); if (worldUID == 0L) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (num > 0) { int num2 = inventory.CountItems(stoneName, -1, false); if (num2 < num) { return; } inventory.RemoveItem(stoneName, num, -1, false); int num3 = num2 - inventory.CountItems(stoneName, -1, false); if (num3 != num) { if (num3 > 0) { inventory.AddItem(stonePrefab, num3); } Debug.LogError((object)"WispShovel: could not reserve the exact stone amount; action was not sent."); return; } } PendingTerrainSettlement pendingTerrainSettlement = new PendingTerrainSettlement(id, worldUID, mode, num, stoneReward, durabilityCost, terrainRequest.Write().GetArray()); pendingTerrainSettlement.Write(val2); if (!Checkpoint(localPlayer)) { pendingTerrainSettlement.Result = TerrainReply.Rejected; pendingTerrainSettlement.Write(val2); Settle(localPlayer, val2, pendingTerrainSettlement); Message(localPlayer, "wispshovel_save_error"); return; } if (!network.Send(terrainRequest)) { pendingTerrainSettlement.Result = TerrainReply.Rejected; pendingTerrainSettlement.Write(val2); Settle(localPlayer, val2, pendingTerrainSettlement); return; } nextAction = Time.time + 0.4f; localPlayer.FaceLookDirection(); ((Character)localPlayer).GetZAnim().SetTrigger(val2.m_shared.m_attack.m_attackAnimation); ((Character)localPlayer).UseStamina(BuildStamina(localPlayer, val2)); EffectList? actionEffects = ShovelItemFactory.GetActionEffects(mode); if (actionEffects != null) { actionEffects.Create(center, Quaternion.identity, (Transform)null, 1f, -1, ((Character)localPlayer).GetZDOID()); } } private static bool HasPending(Inventory inventory) { foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_customData.ContainsKey("org.wispshovel.pending.v1")) { return true; } } return false; } private void QueryPending(Player player) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (network == null || !Object.op_Implicit((Object)(object)ZNet.instance)) { return; } List<ItemData> allItems = ((Humanoid)player).GetInventory().GetAllItems(); foreach (ItemData item in allItems) { if (!PendingTerrainSettlement.TryRead(item, out PendingTerrainSettlement pending) || pending == null || pending.World != ZNet.instance.GetWorldUID()) { continue; } if (CountId(allItems, pending.Id) != 1) { Debug.LogError((object)"WispShovel: duplicate pending operation on items; settlement suspended."); continue; } if (pending.Result.HasValue && pending.Result.Value != TerrainReply.Indeterminate) { Settle(player, item, pending); break; } network.Retry(pending.RequestBytes, pending.Id, ((Character)player).GetZDOID()); } } private void OnResponse(Guid id, TerrainReply reply) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance) || reply == TerrainReply.Indeterminate) { return; } List<ItemData> allItems = ((Humanoid)localPlayer).GetInventory().GetAllItems(); if (CountId(allItems, id) != 1) { return; } foreach (ItemData item in allItems) { if (PendingTerrainSettlement.TryRead(item, out PendingTerrainSettlement pending) && pending != null && !(pending.Id != id) && pending.World == ZNet.instance.GetWorldUID()) { if (pending.Result.HasValue && pending.Result.Value != TerrainReply.Indeterminate && pending.Result.Value != reply) { Debug.LogError((object)"WispShovel: conflicting settlement results; settlement suspended."); break; } pending.Result = reply; pending.Write(item); Settle(localPlayer, item, pending); break; } } } private static int CountId(List<ItemData> items, Guid id) { int num = 0; foreach (ItemData item in items) { if (PendingTerrainSettlement.TryRead(item, out PendingTerrainSettlement pending) && pending != null && pending.Id == id) { num++; } } return num; } private void Settle(Player player, ItemData item, PendingTerrainSettlement pending) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)stonePrefab) || !pending.Result.HasValue || pending.Result == TerrainReply.Indeterminate) { return; } bool flag = pending.Result == TerrainReply.Changed; int num = (flag ? pending.StoneReward : pending.ReservedStone); Inventory inventory = ((Humanoid)player).GetInventory(); ItemData val = stonePrefab.GetComponent<ItemDrop>().m_itemData.Clone(); val.m_dropPrefab = stonePrefab; val.m_worldLevel = (byte)Game.m_worldLevel; int val2 = Math.Max(1, val.m_shared.m_maxStackSize); if (flag && num > 0) { if (!TerrainRequest.TryRead(new ZPackage(pending.RequestBytes), 100f, out TerrainRequest request) || request == null || request.Id != pending.Id || request.Mode != ToolMode.Dig) { Debug.LogError((object)"WispShovel: cannot restore the dig location; stone settlement is pending."); return; } Vector3 center = request.Center; float num2 = default(float); if (!Heightmap.GetHeight(center, ref num2)) { return; } center.y = num2 + 0.5f; while (num > 0) { int num3 = Math.Min(num, val2); if (!Object.op_Implicit((Object)(object)ItemDrop.DropItem(val, num3, center, Quaternion.identity))) { Debug.LogError((object)"WispShovel: could not spawn stone; settlement is pending."); return; } pending.RecordStoneDelivered(num3, changed: true); pending.Write(item); num -= num3; } } while (num > 0) { int num4 = 0; int num5 = Math.Min(num, val2); while (num4 < num5) { int num6 = num4 + (num5 - num4 + 1) / 2; if (inventory.CanAddItem(val, num6)) { num4 = num6; } else { num5 = num6 - 1; } } if (num4 == 0) { pending.Write(item); Checkpoint(player); Message(player, "wispshovel_make_room"); return; } int num7 = inventory.CountItems(stoneName, -1, false); inventory.AddItem(stonePrefab, num4); int num8 = Math.Max(0, Math.Min(num4, inventory.CountItems(stoneName, -1, false) - num7)); pending.RecordStoneDelivered(num8, flag); pending.Write(item); num -= num8; if (num8 != num4) { Checkpoint(player); Debug.LogError((object)"WispShovel: incomplete stone settlement; will retry."); return; } } if (flag && !pending.DurabilityApplied) { item.m_durability = Mathf.Max(0f, item.m_durability - pending.DurabilityCost); pending.DurabilityApplied = true; } item.m_customData.Remove("org.wispshovel.pending.v1"); if (!Checkpoint(player)) { pending.Write(item); } } private bool Checkpoint(Player player) { if (config != null) { return true; } if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)Game.instance) || SaveSystem.HasSessionFlag((SaveSystemSessionFlags)1)) { return false; } try { PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile == null) { return false; } playerProfile.SavePlayerData(player); return playerProfile.Save(); } catch (Exception ex) { Debug.LogError((object)("WispShovel: character checkpoint failed: " + ex)); return false; } } private static void Message(Player player, string key) { ((Character)player).Message((MessageType)2, TranslationFiles.Text(key), 0, (Sprite)null, false); } private void OnDestroy() { if (network != null) { network.Response -= OnResponse; } } } internal sealed class PendingTerrainSettlement { internal const string Key = "org.wispshovel.pending.v1"; internal Guid Id { get; private set; } internal long World { get; private set; } internal ToolMode Mode { get; private set; } internal int ReservedStone { get; private set; } internal int StoneReward { get; private set; } internal float DurabilityCost { get; private set; } internal TerrainReply? Result { get; set; } internal bool DurabilityApplied { get; set; } internal byte[] RequestBytes { get; private set; } internal void RecordStoneDelivered(int amount, bool changed) { if (amount < 0 || amount > (changed ? StoneReward : ReservedStone)) { throw new ArgumentOutOfRangeException("amount"); } if (changed) { StoneReward -= amount; } else { ReservedStone -= amount; } } internal PendingTerrainSettlement(Guid id, long world, ToolMode mode, int reservedStone, int stoneReward, float durabilityCost, byte[] requestBytes) { if (id == Guid.Empty || world == 0L || !Enum.IsDefined(typeof(ToolMode), mode) || reservedStone < 0 || reservedStone > 10000 || stoneReward < 0 || stoneReward > 10000 || float.IsNaN(durabilityCost) || float.IsInfinity(durabilityCost) || durabilityCost < 0f || durabilityCost > 100000f || (mode != ToolMode.Raise && mode != ToolMode.Road && reservedStone != 0) || (mode != ToolMode.Dig && stoneReward != 0) || requestBytes == null || requestBytes.Length < 32 || requestBytes.Length > 128) { throw new ArgumentException("Invalid pending terrain settlement."); } Id = id; World = world; Mode = mode; ReservedStone = reservedStone; StoneReward = stoneReward; DurabilityCost = durabilityCost; RequestBytes = (byte[])requestBytes.Clone(); } internal void Write(ItemData item) { item.m_customData["org.wispshovel.pending.v1"] = string.Join("|", "1", Id.ToString("N"), World.ToString(CultureInfo.InvariantCulture), ((int)Mode).ToString(CultureInfo.InvariantCulture), ReservedStone.ToString(CultureInfo.InvariantCulture), StoneReward.ToString(CultureInfo.InvariantCulture), DurabilityCost.ToString("R", CultureInfo.InvariantCulture), ((int)(Result ?? TerrainReply.Indeterminate)).ToString(CultureInfo.InvariantCulture), DurabilityApplied ? "1" : "0", Convert.ToBase64String(RequestBytes)); } internal static bool TryRead(ItemData item, out PendingTerrainSettlement? pending) { pending = null; if (!item.m_customData.TryGetValue("org.wispshovel.pending.v1", out var value) || value == null || value.Length > 512) { return false; } string[] array = value.Split('|'); if (array.Length != 10 || array[0] != "1" || !Guid.TryParseExact(array[1], "N", out var result) || !long.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(array[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || !int.TryParse(array[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4) || !int.TryParse(array[5], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result5) || !float.TryParse(array[6], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6) || !byte.TryParse(array[7], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result7) || !Enum.IsDefined(typeof(TerrainReply), result7) || (array[8] != "0" && array[8] != "1")) { return false; } try { pending = new PendingTerrainSettlement(result, result2, (ToolMode)result3, result4, result5, result6, Convert.FromBase64String(array[9])); pending.Result = (TerrainReply)result7; pending.DurabilityApplied = array[8] == "1"; return true; } catch (Exception ex) when (ex is ArgumentException || ex is FormatException) { return false; } } } [BepInPlugin("org.wispshovel.valheim", "WispShovel", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private ShovelConfig? settings; private ShovelVisuals? visuals; private RecipeAndDurabilityPatches? rules; private ShovelAttackGuard? attackGuard; private CustomItem? registeredItem; private TerrainNetwork? terrainNetwork; private ShovelControls? controls; private AreaPreview? preview; private NetworkActions? actions; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "WispShovel.cfg"), true); val.SaveOnConfigSet = false; settings = new ShovelConfig(val); ConfigLayout.Initialize(val); SynchronizationManager.Instance.RegisterCustomConfig(val); terrainNetwork = new TerrainNetwork((MonoBehaviour)(object)this, settings); TranslationFiles.Load(); PrefabManager.OnVanillaPrefabsAvailable += RegisterItem; ((BaseUnityPlugin)this).Logger.LogWarning((object)"WispShovel has not been verified in Valheim. Use a separate test world first."); } private void RegisterItem() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Invalid comparison between Unknown and I4 PrefabManager.OnVanillaPrefabsAvailable -= RegisterItem; try { if (settings == null) { throw new InvalidOperationException("Configuration is unavailable."); } visuals = new ShovelVisuals(); CustomItem val = ShovelItemFactory.Create(settings, visuals.Icon, visuals.DigIcon); visuals.Apply(val.ItemPrefab); rules = new RecipeAndDurabilityPatches(settings, val.Recipe.Recipe); attackGuard = new ShovelAttackGuard(); if (!ItemManager.Instance.AddItem(val)) { throw new InvalidOperationException("Jötunn rejected the custom item."); } registeredItem = val; OnMistSettingChanged(this, EventArgs.Empty); settings.EnableMistClearing.SettingChanged += OnMistSettingChanged; settings.EnableMod.SettingChanged += OnMistSettingChanged; if ((int)SystemInfo.graphicsDeviceType != 4) { if (terrainNetwork == null) { throw new InvalidOperationException("Terrain network is unavailable."); } GameObject prefab = PrefabManager.Instance.GetPrefab("Stone"); if (!Object.op_Implicit((Object)(object)prefab)) { throw new InvalidOperationException("Vanilla Stone prefab is unavailable."); } controls = ((Component)this).gameObject.AddComponent<ShovelControls>(); preview = ((Component)this).gameObject.AddComponent<AreaPreview>(); actions = ((Component)this).gameObject.AddComponent<NetworkActions>(); controls.Initialize(settings); preview.Initialize(controls, actions.CanApply); actions.Initialize(controls, preview, settings, terrainNetwork, prefab); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"WispShovel item and terrain handlers registered."); } catch (Exception ex) { if (Object.op_Implicit((Object)(object)actions)) { Object.Destroy((Object)(object)actions); } if (Object.op_Implicit((Object)(object)preview)) { Object.Destroy((Object)(object)preview); } if (Object.op_Implicit((Object)(object)controls)) { Object.Destroy((Object)(object)controls); } if (registeredItem == null) { NativeShovelMenu.Dispose(); terrainNetwork?.Dispose(); rules?.Dispose(); rules = null; attackGuard?.Dispose(); attackGuard = null; visuals?.Dispose(); visuals = null; } ((BaseUnityPlugin)this).Logger.LogError((object)("Could not register WispShovel: " + ex)); } } private void OnMistSettingChanged(object sender, EventArgs args) { if (settings == null || registeredItem == null) { return; } Demister[] array = Resources.FindObjectsOfTypeAll<Demister>(); foreach (Demister val in array) { if (Object.op_Implicit((Object)(object)val) && ((Object)((Component)val).gameObject).name == "WispShovelMistClear") { ((Component)val).gameObject.SetActive(settings.EnableMod.Value && settings.EnableMistClearing.Value); } } } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterItem; if (settings != null) { settings.EnableMistClearing.SettingChanged -= OnMistSettingChanged; settings.EnableMod.SettingChanged -= OnMistSettingChanged; } if (Object.op_Implicit((Object)(object)actions)) { Object.Destroy((Object)(object)actions); } if (Object.op_Implicit((Object)(object)preview)) { Object.Destroy((Object)(object)preview); } if (Object.op_Implicit((Object)(object)controls)) { Object.Destroy((Object)(object)controls); } terrainNetwork?.Dispose(); attackGuard?.Dispose(); rules?.Dispose(); visuals?.Dispose(); NativeShovelMenu.Dispose(); } } public sealed class RecipeAndDurabilityPatches : IDisposable { private static readonly Dictionary<Requirement, int> Requirements = new Dictionary<Requirement, int>(); private static ShovelConfig? settings; private static Recipe? shovelRecipe; private readonly Harmony harmony; private readonly ShovelConfig config; private readonly Requirement[] recipeRequirements; private bool disposed; public RecipeAndDurabilityPatches(ShovelConfig config, Recipe recipe) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Expected O, but got Unknown if (config == null) { throw new ArgumentNullException("config"); } if ((Object)(object)recipe == (Object)null) { throw new ArgumentNullException("recipe"); } if (settings != null) { throw new InvalidOperationException("Shovel rules are already installed."); } if (recipe.m_resources == null || recipe.m_resources.Length != 4) { throw new ArgumentException("Expected requirements in Silver, Iron, RoundLog, Demister order.", "recipe"); } HashSet<Requirement> hashSet = new HashSet<Requirement>(); for (int i = 0; i < recipe.m_resources.Length; i++) { if (recipe.m_resources[i] == null || !hashSet.Add(recipe.m_resources[i])) { throw new ArgumentException("Recipe requirements must be distinct and non-null.", "recipe"); } } harmony = new Harmony("org.wispshovel.rules"); this.config = config; recipeRequirements = recipe.m_resources; settings = config; shovelRecipe = recipe; for (int j = 0; j < recipe.m_resources.Length; j++) { Requirements.Add(recipe.m_resources[j], j); } try { harmony.Patch((MethodBase)AccessTools.Method(typeof(Requirement), "GetAmount", new Type[1] { typeof(int) }, (Type[])null), new HarmonyMethod(typeof(RecipeAndDurabilityPatches), "RequirementPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ItemData), "GetMaxDurability", new Type[1] { typeof(int) }, (Type[])null), new HarmonyMethod(typeof(RecipeAndDurabilityPatches), "DurabilityPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "GetAvailableRecipes", new Type[1] { typeof(List<Recipe>).MakeByRefType() }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(RecipeAndDurabilityPatches), "AvailableRecipesPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { harmony.UnpatchSelf(); Requirements.Clear(); settings = null; shovelRecipe = null; throw; } } private void UpdateRecipeAmounts(object sender, EventArgs args) { for (int i = 0; i < recipeRequirements.Length; i++) { recipeRequirements[i].m_amount = config.GetResourceCost(1, i); } } private static bool RequirementPrefix(Requirement __instance, int __0, ref int __result) { if (settings == null || __0 < 1 || __0 > 4 || !Requirements.TryGetValue(__instance, out var value)) { return true; } __result = settings.GetResourceCost(__0, value); return false; } private static bool DurabilityPrefix(ItemData __instance, int __0, ref float __result) { if (settings == null || __0 < 1 || __0 > 4 || __instance.m_shared == null || __instance.m_shared.m_name != "$item_wispshovel") { return true; } __result = settings.Durability[__0 - 1]; return false; } private static void AvailableRecipesPostfix(Player __instance, List<Recipe> __0) { if (!((Object)(object)shovelRecipe == (Object)null) && settings != null && settings.GetResourceCost(1, 3) > 0) { ItemDrop resItem = shovelRecipe.m_resources[3].m_resItem; if (!Object.op_Implicit((Object)(object)resItem) || resItem.m_itemData?.m_shared == null || !__instance.IsKnownMaterial(resItem.m_itemData.m_shared.m_name)) { __0.Remove(shovelRecipe); } } } public void Dispose() { if (!disposed) { harmony.UnpatchSelf(); Requirements.Clear(); settings = null; shovelRecipe = null; disposed = true; } } } internal static class RemoteAccessValidator { private static readonly FieldInfo Areas = AccessTools.Field(typeof(PrivateArea), "m_allAreas") ?? throw new MissingFieldException("PrivateArea", "m_allAreas"); private static readonly FieldInfo WardPiece = AccessTools.Field(typeof(PrivateArea), "m_piece") ?? throw new MissingFieldException("PrivateArea", "m_piece"); private static readonly MethodInfo IsEnabled = RequiredMethod("IsEnabled", Type.EmptyTypes); private static readonly MethodInfo IsInside = RequiredMethod("IsInside", new Type[2] { typeof(Vector3), typeof(float) }); private static readonly MethodInfo IsPermitted = RequiredMethod("IsPermitted", new Type[1] { typeof(long) }); internal static bool TryResolveActor(long sender, ZDOID actorId, out Player? player, out long playerId) { //IL_0008: 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) player = null; playerId = 0L; if (!TryResolveIdentity(sender, actorId, out playerId) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return false; } GameObject val = ZNetScene.instance.FindInstance(actorId); if (!Object.op_Implicit((Object)(object)val)) { return false; } ZNetView component = val.GetComponent<ZNetView>(); player = val.GetComponent<Player>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || component.GetZDO().GetOwner() != sender || !Object.op_Implicit((Object)(object)player)) { return false; } return player.GetPlayerID() == playerId; } internal static bool TryResolveIdentity(long sender, ZDOID actorId, out long playerId) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) playerId = 0L; if (sender == 0L || ((ZDOID)(ref actorId)).IsNone() || !Object.op_Implicit((Object)(object)ZNet.instance) || ZDOMan.instance == null) { return false; } if (sender != ZNet.GetUID()) { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || peer.m_characterID != actorId) { return false; } } else if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).GetZDOID() != actorId) { return false; } ZDO zDO = ZDOMan.instance.GetZDO(actorId); if (zDO == null || zDO.GetOwner() != sender) { return false; } playerId = zDO.GetLong(ZDOVars.s_playerID, 0L); return playerId != 0; } internal static bool CanModify(Player player, long playerId, Vector3 center, float radius) { //IL_0013: 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_002d: 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_005a: 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_006b: 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_009f: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || playerId == 0L || !Finite(center.x) || !Finite(center.y) || !Finite(center.z) || !Finite(radius) || radius <= 0f || radius > 32f) { return false; } Vector3 eyePoint = ((Character)player).GetEyePoint(); if (playerId == 0L || !Finite(eyePoint.x) || !Finite(eyePoint.y) || !Finite(eyePoint.z) || !Finite(player.m_maxPlaceDistance) || player.m_maxPlaceDistance <= 0f || Vector3.Distance(eyePoint, center) >= player.m_maxPlaceDistance) { return false; } if (!SurroundingZonesLoaded(center, radius + 64f)) { return false; } if (!TerrainProtection.OutsideNoBuildLocations(center, radius)) { return false; } if (!(Areas.GetValue(null) is List<PrivateArea> list)) { return false; } foreach (PrivateArea item in list) { if (Object.op_Implicit((Object)(object)item) && (bool)IsEnabled.Invoke(item, null) && (bool)IsInside.Invoke(item, new object[2] { center, radius })) { object? value = WardPiece.GetValue(item); Piece val = (Piece)((value is Piece) ? value : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } if (val.GetCreator() != playerId && !(bool)IsPermitted.Invoke(item, new object[1] { playerId })) { return false; } } } return true; } private static bool SurroundingZonesLoaded(Vector3 center, float radius) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_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_007a: 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_006d: 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) ZoneSystem instance = ZoneSystem.instance; if (!Object.op_Implicit((Object)(object)instance)) { return false; } Vector2s zone = ZoneSystem.GetZone(center - new Vector3(radius, 0f, radius)); Vector2s zone2 = ZoneSystem.GetZone(center + new Vector3(radius, 0f, radius)); for (int i = zone.x; i <= zone2.x; i++) { for (int j = zone.y; j <= zone2.y; j++) { if (!instance.IsZoneLoaded(new Vector2s(i, j))) { return false; } } } return true; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static MethodInfo RequiredMethod(string name, Type[] parameters) { return AccessTools.Method(typeof(PrivateArea), name, parameters, (Type[])null) ?? throw new MissingMethodException("PrivateArea", name); } } public sealed class ShovelAttackGuard : IDisposable { private static readonly FieldInfo RightItem = AccessTools.Field(typeof(Humanoid), "m_rightItem"); private readonly Harmony harmony = new Harmony("org.wispshovel.attackguard"); public ShovelAttackGuard() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown if (RightItem == null) { throw new InvalidOperationException("Cannot find the equipped right-hand item field."); } harmony.Patch((MethodBase)AccessTools.Method(typeof(Humanoid), "StartAttack", new Type[2] { typeof(Character), typeof(bool) }, (Type[])null), new HarmonyMethod(typeof(ShovelAttackGuard), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool Prefix(Humanoid __instance, ref bool __result) { object? value = RightItem.GetValue(__instance); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val?.m_shared == null || val.m_shared.m_name != "$item_wispshovel") { return true; } __result = false; return false; } public void Dispose() { harmony.UnpatchSelf(); } } public sealed class ShovelConfig { public const bool DurableActionSaves = false; public readonly float[] Durability = new float[4] { 200f, 400f, 600f, 800f }; public const float DigCost = 1f; public const float RaiseCost = 1f; public const float RoadCost = 1f; public const float LevelCost = 1f; private static readonly int[,] recipe = new int[4, 4] { { 4, 3, 6, 1 }, { 2, 2, 4, 0 }, { 4, 3, 6, 0 }, { 6, 4, 8, 0 } }; public ConfigEntry<bool> EnableMod { get; } public ConfigEntry<bool> EnableMistClearing { get; } public ConfigEntry<bool> EnableStoneDrops { get; } public ConfigEntry<bool> EnableAreaPreview { get; } public ConfigEntry<bool> ShowToolHud { get; } public ConfigEntry<int> RaiseStoneCost { get; } public ConfigEntry<float> CircleRadius { get; } public ConfigEntry<float> SquareSize { get; } public ConfigEntry<float> RectangleWidth { get; } public ConfigEntry<float> RectangleLength { get; } public ConfigEntry<float> MaxSize { get; } public ConfigEntry<KeyboardShortcut> ShapeKey { get; } public ConfigEntry<KeyboardShortcut> RectangleSideKey { get; } public ConfigEntry<KeyCode> SizeModifier { get; } public ShovelConfig(ConfigFile file) { //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) EnableMod = file.Bind<bool>("General", "EnableMod", true, Synced("Enable WispShovel actions and mist clearing.")); EnableMistClearing = file.Bind<bool>("General", "EnableMistClearing", true, Synced("Enable mist clearing while the shovel is equipped.")); EnableStoneDrops = file.Bind<bool>("General", "EnableStoneDrops", true, Synced("Give stone only when a dig is confirmed to have changed terrain.")); EnableAreaPreview = file.Bind<bool>("General", "EnableAreaPreview", true, "Show the targeted area."); ShowToolHud = file.Bind<bool>("Visual", "ShowToolHUD", true, "Show shovel controls and current settings."); RaiseStoneCost = Integer(file, "Raise", "StoneCost", 1); CircleRadius = Float(file, "Area", "CircleRadius", 2f, 0.8f, 50f); SquareSize = Float(file, "Area", "SquareSize", 4f, 0.1f, 100f); RectangleLength = Float(file, "Area", "RectangleLength", 5f, 0.1f, 100f); RectangleWidth = Float(file, "Area", "RectangleWidth", 2f, 0.1f, 100f); MaxSize = Float(file, "Area", "MaxSize", 8f, 1.6f, 100f, synced: true); ShapeKey = file.Bind<KeyboardShortcut>("Controls", "ShapeKey", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), "Cycle the area shape."); RectangleSideKey = file.Bind<KeyboardShortcut>("Controls", "RectangleSideKey", new KeyboardShortcut((KeyCode)118, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Change the adjustable rectangle side."); SizeModifier = file.Bind<KeyCode>("Controls", "SizeModifier", (KeyCode)308, "Hold with the mouse wheel to change area size."); } public ItemRules ReadItemRules() { ResourceCost[] array = new ResourceCost[4]; float[] array2 = new float[4]; for (int i = 0; i < 4; i++) { array[i] = new ResourceCost(recipe[i, 0], recipe[i, 1], recipe[i, 2], recipe[i, 3]); array2[i] = Durability[i]; } return new ItemRules(array, array2); } public int GetResourceCost(int quality, int resource) { if (quality < 1 || quality > 4) { throw new ArgumentOutOfRangeException("quality"); } if (resource < 0 || resource > 3) { throw new ArgumentOutOfRangeException("resource"); } return recipe[quality - 1, resource]; } private static ConfigDescription Synced(string description) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } }); } private static ConfigEntry<float> Float(ConfigFile f, string section, string key, float value, float min, float max, bool synced = false) { //IL_0038: 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_0045: Expected O, but got Unknown //IL_0045: 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_004f: Expected O, but got Unknown return f.Bind<float>(section, key, value, synced ? new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } }) : new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())); } private static ConfigEntry<int> Integer(ConfigFile f, string section, string key, int value) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown return f.Bind<int>(section, key, value, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } } public sealed class ShovelControls : MonoBehaviour { private static readonly FieldInfo RightItem = AccessTools.Field(typeof(Humanoid), "m_rightItem"); private static readonly FieldInfo PlacementGhost = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly MethodInfo BuildInput = AccessTools.Method(typeof(Player), "UpdateBuildGuiInput", (Type[])null, (Type[])null); private static ShovelControls? active; private ShovelConfig? config; private Harmony? harmony; private int scrollFrame = -1; private TMP_Text? controlHints; public ToolState State { get; private set; } = new ToolState(); public bool IsControllable { get { if (CanControl()) { return !Hud.IsPieceSelectionVisible(); } return false; } } public bool PreviewEnabled { get { if (config != null) { return config.EnableAreaPreview.Value; } return false; } } public void Initialize(ShovelConfig settings) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown if ((Object)(object)active != (Object)null || config != null) { throw new InvalidOperationException("Shovel controls are already initialized."); } config = settings ?? throw new ArgumentNullException("settings"); State = new ToolState(settings.CircleRadius.Value, settings.SquareSize.Value, settings.RectangleWidth.Value, settings.RectangleLength.Value, settings.MaxSize.Value); settings.MaxSize.SettingChanged += OnMaximumChanged; harmony = new Harmony("org.wispshovel.controls"); active = this; try { harmony.Patch((MethodBase)AccessTools.Method(typeof(ZInput), "GetMouseScrollWheel", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ShovelControls), "ScrollPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(PieceTable), "UpdateAvailable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ShovelControls), "AvailablePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "UpdatePlacement", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ShovelControls), "PlacementPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ShovelControls), "GhostPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "SetSelectedPiece", new Type[1] { typeof(Vector2Int) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ShovelControls), "SelectionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { Unsubscribe(settings); harmony.UnpatchSelf(); active = null; config = null; throw; } } private void Unsubscribe(ShovelConfig settings) { settings.MaxSize.SettingChanged -= OnMaximumChanged; } private void OnMaximumChanged(object sender, EventArgs args) { if (config != null) { State.SetMaximumSize(config.MaxSize.Value); } } private bool CanControl() { Player localPlayer = Player.m_localPlayer; if (config == null || !config.EnableMod.Value || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting()) { return false; } if (Console.IsVisible() || (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus()) || TextInput.IsVisible() || InventoryGui.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible() || (Object.op_Implicit((Object)(object)TextViewer.instance) && TextViewer.instance.IsVisible())) { return false; } object? value = RightItem.GetValue(localPlayer); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val?.m_shared != null && val.m_shared.m_name == "$item_wispshovel") { return val.m_equipped; } return false; } private static bool Down(KeyboardShortcut shortcut) { //IL_0002: 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_002a: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, false)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if (!ZInput.GetKey(modifier, false)) { return false; } } return true; } private void Update() { //IL_0028: 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) if (IsControllable && config != null) { SyncSelection(); ZInput.GetMouseScrollWheel(); if (Down(config.RectangleSideKey.Value)) { State.ToggleRectangleSide(); } else if (Down(config.ShapeKey.Value)) { State.CycleShape(); } NativeShovelMenu.UpdateCosts(State.AreaFacing(0.0, 1.0), config.RaiseStoneCost.Value); Piece val = (Object.op_Implicit((Object)(object)NativeShovelMenu.Table) ? NativeShovelMenu.Table.GetSelectedPiece() : null); if (Object.op_Implicit((Object)(object)val)) { NativeShovelMenu.UpdateDescription(val, config.ShowToolHud.Value ? Description() : ""); } } } private static void ScrollPostfix(ref float __result) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) ShovelControls shovelControls = active; if (shovelControls != null && Object.op_Implicit((Object)(object)shovelControls) && shovelControls.IsControllable && shovelControls.config != null && __result != 0f && ZInput.GetKey(shovelControls.config.SizeModifier.Value, false)) { if (shovelControls.scrollFrame != Time.frameCount) { shovelControls.scrollFrame = Time.frameCount; int steps = ((__result > 0f) ? 1 : (-1)); shovelControls.State.AdjustSize(steps); shovelControls.SaveState(); } __result = 0f; } } private static void AvailablePrefix(PieceTable __instance, ref bool __3) { if ((Object)(object)__instance == (Object)(object)NativeShovelMenu.Table) { __3 = true; } } private static bool IsShovel(Player player) { if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)player.GetBuildTool() == (Object)(object)NativeShovelMenu.Table) { return Object.op_Implicit((Object)(object)NativeShovelMenu.Table); } return false; } private static bool PlacementPrefix(Player __instance, bool __0) { if (!IsShovel(__instance)) { return true; } if (__0 && Object.op_Implicit((Object)(object)Hud.instance)) { BuildInput.Invoke(__instance, null); } return false; } private static bool GhostPrefix(Player __instance) { if (!IsShovel(__instance)) { return true; } object? value = PlacementGhost.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } PlacementGhost.SetValue(__instance, null); return false; } private static void SelectionPostfix(Player __instance) { if (IsShovel(__instance) && Object.op_Implicit((Object)(object)active)) { active.SyncSelection(); } } private void SyncSelection() { Piece val = (Object.op_Implicit((Object)(object)NativeShovelMenu.Table) ? NativeShovelMenu.Table.GetSelectedPiece() : null); if (Object.op_Implicit((Object)(object)val) && NativeShovelMenu.TryGetMode(val, out var mode)) { State.SelectMode(mode); } } private void LateUpdate() { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00cd: Unknown result type (might be due to invalid IL or missing references) Hud instance = Hud.instance; if (!IsControllable || config == null || !config.ShowToolHud.Value || !Object.op_Implicit((Object)(object)instance) || !instance.m_buildHud.activeInHierarchy) { if (Object.op_Implicit((Object)(object)controlHints)) { ((Component)controlHints).gameObject.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)controlHints)) { TMP_Text pieceDescription = instance.m_pieceDescription; controlHints = Object.Instantiate<TMP_Text>(pieceDescription, pieceDescription.transform.parent, false); ((Object)controlHints).name = "WispShovelControlHints"; RectTransform rectTransform = controlHints.rectTransform; rectTransform.anchoredPosition += new Vector2(535f, -120f); rectTransform.sizeDelta = new Vector2(300f, 160f); controlHints.alignment = (TextAlignmentOptions)257; } ((Component)controlHints).gameObject.SetActive(true); controlHints.text = TranslationFiles.Text("wispshovel_shape") + ": <color=yellow>" + Shortcut(config.ShapeKey.Value) + "</color>\n" + TranslationFiles.Text("wispshovel_side") + ": <color=yellow>" + Shortcut(config.RectangleSideKey.Value) + "</color>\n" + TranslationFiles.Text("wispshovel_size") + ": <color=yellow>" + KeyName(config.SizeModifier.Value) + " + " + TranslationFiles.Text("wispshovel_wheel") + "</color>"; if (State.Mode == ToolMode.Level) { TMP_Text? obj = controlHints;