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 TunnelheimCompanion v0.8.3
plugins/TunnelheimBuildingFix.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("TunnelheimBuildingFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.8.3.0")] [assembly: AssemblyInformationalVersion("0.8.3")] [assembly: AssemblyProduct("TunnelheimBuildingFix")] [assembly: AssemblyTitle("TunnelheimBuildingFix")] [assembly: AssemblyVersion("0.8.3.0")] [module: RefSafetyRules(11)] 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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TunnelheimBuildingFix { internal static class AcceptedLoweringPlan { internal struct Step { internal float Reference; internal float Target; internal Step(float r, float t) { Reference = r; Target = t; } } internal static List<Step> Create(float top, float accepted) { if (float.IsNaN(top) || float.IsInfinity(top) || float.IsNaN(accepted) || float.IsInfinity(accepted) || top - accepted > 128f) { throw new ArgumentException("Unsupported surface heights"); } List<Step> list = new List<Step>(); float num = top; while (num > accepted + 0.0001f) { float num2 = Math.Max(accepted, num - 7.5f); list.Add(new Step(num, num2)); num = num2; } return list; } } internal static class AcceptedSurfacePlan { internal struct Step { internal float Reference; internal float Target; internal Step(float r, float t) { Reference = r; Target = t; } } internal static List<Step> Create(float before, float accepted, float top, bool allowRaise) { if (!Finite(before) || !Finite(accepted) || !Finite(top) || Math.Abs(accepted - top) > 128f) { throw new ArgumentException("Unsupported accepted surface height"); } List<Step> list = new List<Step>(); if (Math.Abs(accepted - before) < 0.0001f) { return list; } bool flag = accepted < before; if (flag && accepted >= top - 0.0001f) { return list; } if (!flag && (!allowRaise || accepted <= top + 0.0001f)) { return list; } float num = top; while (Math.Abs(accepted - num) > 0.0001f) { float num2 = (flag ? Math.Max(accepted, num - 7.5f) : Math.Min(accepted, num + 7.5f)); list.Add(new Step(num, num2)); num = num2; } return list; } internal static bool Exterior(float hit, float top) { if (Finite(hit) && Finite(top)) { return hit >= top - 0.75f; } return false; } internal static bool Finite(float x) { if (!float.IsNaN(x)) { return !float.IsInfinity(x); } return false; } internal static bool NativeOnlyAction(string name) { if (name != "LevelWall" && name != "LevelCeiling") { return name != "CarveStairs"; } return false; } } public static class CanalCutLimits { public const double Minimum = 0.25; public const double Maximum = 3.0; public const double Default = 0.75; public static void Validate(double size) { if (!RouteMath.Finite(size) || size < 0.25 || size > 3.0) { throw new ArgumentException("Canal cut size must be 0.25 to 3 metres."); } } public static IEnumerable<double> Radii(double size) { Validate(size); yield return size; double[] array = new double[8] { 2.5, 2.0, 1.5, 1.0, 0.75, 0.5, 0.35, 0.25 }; foreach (double num in array) { if (num < size - 1E-08) { yield return num; } } } } internal sealed class CanalMode : MonoBehaviour { internal sealed class DigState { internal bool Value; } private static BaseUnityPlugin owner = null; private static BaseUnityPlugin upstream = null; private static Type world = null; private static Type opType = null; private static Type chunk = null; private static MethodInfo shaped = null; private static MethodInfo makeCarve = null; private static MethodInfo seed = null; private static MethodInfo known = null; private static MethodInfo column = null; private static MethodInfo primary = null; private static MethodInfo typing = null; private static MethodInfo modifier = null; private static FieldInfo registry = null; private static FieldInfo square = null; private static FieldInfo straight = null; private static FieldInfo key = null; private static FieldInfo undoKey = null; private static FieldInfo straightKey = null; private static ConfigEntry<bool> featureEnabled = null; private static ConfigEntry<float> cutSize = null; private static FieldInfo locations = null; private static readonly ManualLogSource Log = Logger.CreateLogSource("Centerline Canal"); private static bool selected; private static float nextMessage; private static int lastFrame = -1; [ThreadStatic] private static object? plannedOp; internal static float CutSize { get { float value = cutSize.Value; if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Mathf.Clamp(value, 0.25f, 3f); } return 0.75f; } set { CanalCutLimits.Validate(value); cutSize.Value = value; } } internal static bool Selected => selected; internal static void Install(BaseUnityPlugin plugin, BaseUnityPlugin tunnel, Harmony h) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Expected O, but got Unknown //IL_03aa: Expected O, but got Unknown //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Expected O, but got Unknown //IL_044f: Expected O, but got Unknown //IL_044f: Expected O, but got Unknown owner = plugin; upstream = tunnel; Assembly assembly = ((object)tunnel).GetType().Assembly; world = assembly.GetType("ValheimTunneling.VoxelWorld", throwOnError: true); opType = assembly.GetType("ValheimTunneling.VoxelOp", throwOnError: true); chunk = assembly.GetType("ValheimTunneling.VoxelChunk", throwOnError: true); featureEnabled = plugin.Config.Bind<bool>("Canal", "Enabled", true, "Experimental local centerline planner. Confirm a guide, then excavate with ordinary pickaxe strikes."); cutSize = plugin.Config.Bind<float>("Canal", "CutSize", 0.75f, new ConfigDescription("Canal-only maximum sphere radius and depth per accepted dig, 0.25-3 m. Larger cuts retain normal per-swing costs and per-dig stone drops. Smaller cutters are used near banks/bed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>())); locations = AccessTools.Field(typeof(Location), "s_allLocations") ?? throw new Exception("Missing protected location registry"); if (!typeof(IEnumerable<Location>).IsAssignableFrom(locations.FieldType)) { throw new Exception("Changed protected location registry"); } registry = AccessTools.Field(world, "s_syncs") ?? throw new Exception("Missing Canal sync registry"); if (!typeof(IDictionary).IsAssignableFrom(registry.FieldType)) { throw new Exception("Changed Canal sync registry contract"); } square = NeedField(world, "SquareDig", typeof(bool)); straight = NeedField(world, "DigStraight", typeof(bool)); Type type = ((object)tunnel).GetType(); key = NeedField(type, "_squareDigKey", typeof(ConfigEntry<KeyCode>)); undoKey = NeedField(type, "_undoKey", typeof(ConfigEntry<KeyCode>)); straightKey = NeedField(type, "_digStraightKey", typeof(ConfigEntry<KeyCode>)); typing = Need(type, "IsTyping", Type.EmptyTypes); modifier = Need(type, "ModifierHeld", Type.EmptyTypes); shaped = Need(world, "ShapedDig", new Type[4] { typeof(Character), typeof(Vector3), typeof(Vector3), typeof(float) }); makeCarve = Need(opType, "MakeCarve", new Type[2] { typeof(Vector3), typeof(float) }); seed = Need(world, "SeedHeight", new Type[2] { typeof(float), typeof(float) }); known = Need(world, "HasSavedTunnel", new Type[1] { typeof(Vector3) }); column = Need(world, "IsVoxelColumnAt", new Type[2] { typeof(float), typeof(float) }); primary = Need(world, "PrimarySync", new Type[1] { typeof(Vector2Int) }); if (shaped.ReturnType != opType || makeCarve.ReturnType != opType) { throw new Exception("Changed Canal operation contract"); } h.Patch((MethodBase)Need(type, "Update", Type.EmptyTypes), new HarmonyMethod(typeof(CanalMode), "ShapeBefore", (Type[])null), new HarmonyMethod(typeof(CanalMode), "ShapeAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); h.Patch((MethodBase)Need(world, "Dig", new Type[5] { typeof(Character), typeof(Vector3), typeof(Vector3), typeof(TerrainOp), typeof(ItemData) }), new HarmonyMethod(typeof(CanalMode), "BeforeDig", (Type[])null) { priority = 0 }, (HarmonyMethod)null, new HarmonyMethod(typeof(CanalMode), "ReplaceShape", (Type[])null), new HarmonyMethod(typeof(CanalMode), "AfterDig", (Type[])null), (HarmonyMethod)null); RoutePlanner.Install(plugin, h); ((Component)plugin).gameObject.AddComponent<CanalMode>(); selected = false; Log.LogInfo((object)"Centerline Canal: native sphere save/undo/network format retained; local guides are not shared plans."); } private static MethodInfo Need(Type t, string n, Type[] a) { return AccessTools.Method(t, n, a, (Type[])null) ?? throw new Exception("Missing Canal contract " + n); } private static FieldInfo NeedField(Type t, string n, Type value) { FieldInfo fieldInfo = AccessTools.Field(t, n); if (fieldInfo == null || fieldInfo.FieldType != value) { throw new Exception("Changed Canal field " + n); } return fieldInfo; } private static KeyCode Key(FieldInfo f) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return ((ConfigEntry<KeyCode>)f.GetValue(upstream)).Value; } private static void ShapeBefore(out int __state) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) __state = -1; if (featureEnabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && !(bool)typing.Invoke(null, null) && !(bool)modifier.Invoke(null, null) && (int)Key(key) != 0 && ZInput.GetKeyDown(Key(key), false) && !ZInput.GetKeyDown(Key(undoKey), false) && !ZInput.GetKeyDown(Key(straightKey), false)) { KeyboardShortcut value = owner.Config.Bind<KeyboardShortcut>("Excavation", "ToggleKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), (ConfigDescription)null).Value; if (((KeyboardShortcut)(ref value)).MainKey == Key(key)) { selected = false; RoutePlanner.Close(); Warn("Canal shape key conflicts with excavation toggle."); } else { __state = (selected ? 2 : (((bool)square.GetValue(null)) ? 1 : 0)); } } } private static void ShapeAfter(int __state) { if (__state >= 0) { Choose((__state + 1) % 3); } } internal static void Choose(int mode) { selected = mode == 2; square.SetValue(null, mode == 1); plannedOp = null; if (selected) { RoutePlanner.Open(); } else { RoutePlanner.Close(); } Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, selected ? "Canal: plot and confirm a centerline." : ((mode == 1) ? "Pickaxe: square digs" : "Pickaxe: round digs"), 0, (Sprite)null, false); } } private static bool LocalCanal(Character a) { if (featureEnabled.Value && selected && ExcavationMode.Enabled && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)a == (Object)(object)Player.m_localPlayer; } return false; } internal static bool TerrainCollider(Collider c) { if (!((Object)(object)((Component)c).GetComponent<Heightmap>() != (Object)null)) { return (Object)(object)((Component)c).GetComponentInParent(chunk) != (Object)null; } return true; } internal static float Surface(Vector3 at) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) float num = float.NegativeInfinity; RaycastHit[] array = Physics.RaycastAll(new Vector3(at.x, 200f, at.z), Vector3.down, 400f, LayerMask.GetMask(new string[2] { "terrain", "static_solid" }), (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val = array[i]; if (TerrainCollider(((RaycastHit)(ref val)).collider)) { num = Mathf.Max(num, ((RaycastHit)(ref val)).point.y); } } if (float.IsNegativeInfinity(num)) { throw new Exception("Terrain not loaded; move closer or shorten route."); } return num; } internal static void Ready(Vector3 at) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) bool loaded = (bool)column.Invoke(null, new object[2] { at.x, at.z }); bool saved = (bool)known.Invoke(null, new object[1] { at }); Vector2Int val = default(Vector2Int); ((Vector2Int)(ref val))..ctor(Mathf.FloorToInt(at.x / 16f), Mathf.FloorToInt(at.z / 16f)); bool registered = ((IDictionary)registry.GetValue(null)).Contains(val); object obj = primary.Invoke(null, new object[1] { val }); bool valid = false; bool built = false; bool pending = false; bool unreadable = false; if (obj != null) { valid = (bool)AccessTools.Property(obj.GetType(), "IsValid").GetValue(obj, null); built = (bool)AccessTools.Property(obj.GetType(), "Built").GetValue(obj, null); pending = (bool)AccessTools.Property(obj.GetType(), "IsPending").GetValue(obj, null); unreadable = (bool)AccessTools.Property(obj.GetType(), "Unreadable").GetValue(obj, null); } if (!CanalReadiness.CanEdit(saved, registered, loaded, obj != null, valid, built, pending, unreadable)) { throw new Exception("Terrain is still loading or synchronizing."); } } private unsafe static bool BeforeDig(Character attacker, Vector3 point, TerrainOp op, ItemData weapon, out DigState? __state) { //IL_0081: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) __state = null; plannedOp = null; if (!LocalCanal(attacker)) { return true; } if (lastFrame == Time.frameCount) { return false; } lastFrame = Time.frameCount; try { if (RoutePlanner.AttackBlocking) { throw new Exception("Confirm guide and close planner before excavating."); } RouteSurface routeSurface = RoutePlanner.Guide ?? throw new Exception("No confirmed guide. Cycle back to Canal to plot or load one."); if (weapon == null || (Object)(object)op == (Object)null || weapon.m_shared.m_damages.m_pickaxe <= 0f) { throw new Exception("Canal requires a pickaxe terrain strike."); } Ready(point); float num = Surface(point); if (Mathf.Abs(num - point.y) > 1.1f) { throw new Exception("Canal cuts start at the upper surface; use Round or Square underground."); } if (!routeSurface.TryCut(point.x, point.z, num, CutSize, out var centerY, out var radius)) { throw new Exception("Bank target reached, or outside confirmed guide."); } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(point.x, (float)centerY, point.z); float num2 = (float)radius; float num3 = num2 + 1f; foreach (Location item in (IEnumerable<Location>)locations.GetValue(null)) { if ((Object)(object)item != (Object)null && item.m_noBuild && item.IsInside(val, num3, true)) { throw new Exception("Canal cut overlaps a protected location."); } } for (float num4 = val.x - num3; num4 <= val.x + num3 + 0.01f; num4 += 0.5f) { for (float num5 = val.z - num3; num5 <= val.z + num3 + 0.01f; num5 += 0.5f) { Vector3 val2 = new Vector3(num4, val.y, num5); Ready(val2); if (Location.IsInsideNoBuildLocation(val2)) { throw new Exception("Protected location."); } if ((float)seed.Invoke(null, new object[2] { num4, num5 }) - (val.y - num2) > 63f) { throw new Exception("Tunnelheim depth limit."); } } } if (!PrivateArea.CheckAccess(val, num3, true, false)) { throw new Exception("Protected Canal cut."); } plannedOp = makeCarve.Invoke(null, new object[2] { val, num2 }); __state = new DigState { Value = (bool)straight.GetValue(null) }; straight.SetValue(null, false); ManualLogSource log = Log; string[] obj = new string[9] { "CENTERLINE CUT guide=", routeSurface.Revision.ToString(), " center=", null, null, null, null, null, null }; Vector3 val3 = val; obj[3] = ((object)(*(Vector3*)(&val3))/*cast due to .constrained prefix*/).ToString(); obj[4] = " radius="; obj[5] = num2.ToString(); obj[6] = " requestedSize="; obj[7] = CutSize.ToString(); obj[8] = " one native sphere/cost/drop/save/undo"; log.LogInfo((object)string.Concat(obj)); return true; } catch (Exception ex) { Warn(ex.GetBaseException().Message); return false; } } private static Exception? AfterDig(Exception? __exception, DigState? __state) { if (__state != null) { straight.SetValue(null, __state.Value); } plannedOp = null; return __exception; } public static object Shape(Character a, Vector3 p, Vector3 d, float size) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (LocalCanal(a)) { if (plannedOp == null) { throw new Exception("Missing Canal operation"); } return plannedOp; } return shaped.Invoke(null, new object[4] { a, p, d, size }); } private static IEnumerable<CodeInstruction> ReplaceShape(IEnumerable<CodeInstruction> source) { List<CodeInstruction> list = source.ToList(); CodeInstruction[] array = list.Where((CodeInstruction x) => CodeInstructionExtensions.Calls(x, shaped)).ToArray(); if (array.Length != 1) { throw new Exception("Expected one ShapedDig call"); } DynamicMethod dynamicMethod = new DynamicMethod("CompanionCanalShape", opType, new Type[4] { typeof(Character), typeof(Vector3), typeof(Vector3), typeof(float) }, typeof(CanalMode), skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); for (int num = 0; num < 4; num++) { iLGenerator.Emit(OpCodes.Ldarg, num); } iLGenerator.Emit(OpCodes.Call, AccessTools.Method(typeof(CanalMode), "Shape", (Type[])null, (Type[])null)); iLGenerator.Emit(OpCodes.Unbox_Any, opType); iLGenerator.Emit(OpCodes.Ret); array[0].operand = dynamicMethod; return list; } private static void Warn(string message) { if (!(Time.realtimeSinceStartup < nextMessage)) { nextMessage = Time.realtimeSinceStartup + 1f; Log.LogWarning((object)message); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } } } public static class CanalPlanMath { public static double CutBottom(double exposedSurface, double targetFloor) { if (double.IsNaN(exposedSurface) || double.IsInfinity(exposedSurface) || double.IsNaN(targetFloor) || double.IsInfinity(targetFloor)) { throw new ArgumentException("Invalid Canal surface"); } return Math.Max(targetFloor, Math.Ceiling(exposedSurface - 0.001) - 2.0); } public static double BankFloor(double lateral, double width, double bed, double slope) { return bed + Math.Max(Math.Abs(lateral) - width / 2.0, 0.0) / slope; } public static bool Cell(double x, double z, double size, double width, double length, double bed, double slope, out double cx, out double cz, out double floor) { cx = (Math.Floor(x / size) + 0.5) * size; cz = (0.0 - length) / 2.0 + (Math.Floor((z + length / 2.0) / size) + 0.5) * size; floor = BankFloor(Math.Abs(cx) + size / 2.0, width, bed, slope); return Math.Abs(cz) + size / 2.0 <= length / 2.0 + 0.0001; } public static double Resolve(double width, double length, double bed, double slope, double maxWidth, Func<double, double, double> height) { double num = Math.Max(bed + 2.0, Math.Ceiling(height(0.0, 0.0) + 2.0)); for (int i = 0; i < 8; i++) { double num2 = width / 2.0 + (num - bed) * slope; if (num2 * 2.0 > maxWidth) { throw new InvalidOperationException("Surrounding hillside exceeds the configured Canal opening width; choose a lower route."); } double num3 = bed; for (double num4 = 0.0 - Math.Ceiling(num2); num4 <= Math.Ceiling(num2); num4 += 1.0) { for (double num5 = (0.0 - length) / 2.0; num5 <= length / 2.0; num5 += 1.0) { double num6 = height(num4, num5); if (double.IsNaN(num6) || double.IsInfinity(num6)) { throw new InvalidOperationException("Canal terrain is not loaded; move closer and retry."); } num3 = Math.Max(num3, num6); } } double num7 = Math.Ceiling(num3 + 2.0); if (num7 <= num) { return num; } num = num7; } throw new InvalidOperationException("Canal hillside bound did not converge; choose a lower route."); } } public static class CanalReadiness { public static bool CanEdit(bool saved, bool registered, bool loaded, bool primary, bool valid, bool built, bool pending, bool unreadable) { if (!saved && !registered && !primary) { return true; } if (loaded && primary && valid && built && !pending) { return !unreadable; } return false; } } internal static class CanalUi { internal sealed class Scope : IDisposable { private readonly GUISkin previous; private readonly Color color; private readonly Color background; private readonly Color content; internal Scope() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_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_0028: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) previous = GUI.skin; color = GUI.color; background = GUI.backgroundColor; content = GUI.contentColor; Ensure(); GUI.skin = skin; GUI.color = (GUI.backgroundColor = (GUI.contentColor = Color.white)); } public void Dispose() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) GUI.skin = previous; GUI.color = color; GUI.backgroundColor = background; GUI.contentColor = content; } } private static GUISkin? skin; private static GUIStyle? section; private static GUIStyle? muted; private static GUIStyle? primary; private static GUIStyle? danger; private static GUIStyle? marker; private static readonly List<Texture2D> textures = new List<Texture2D>(); private static readonly Color Gold = new Color(0.87f, 0.72f, 0.42f); private static readonly Color Text = new Color(0.91f, 0.87f, 0.76f); internal static string FontName { get { if (!((Object)(object)skin != (Object)null) || !((Object)(object)skin.font != (Object)null)) { return "default"; } return ((Object)skin.font).name; } } private static Texture2D Texture(Color fill, Color border) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false) { name = "Companion UI", hideFlags = (HideFlags)61, filterMode = (FilterMode)0 }; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { bool flag = j < 1 || i < 1 || j > 14 || i > 14; float num = (float)((j * 7 + i * 3) % 5) * 0.002f; val.SetPixel(j, i, (Color)(flag ? border : new Color(fill.r + num, fill.g + num, fill.b + num, fill.a))); } } val.Apply(); textures.Add(val); return val; } private static void Paint(GUIStyle s, Texture2D normal, Texture2D hover, Color color) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) GUIStyleState[] array = (GUIStyleState[])(object)new GUIStyleState[2] { s.normal, s.onNormal }; foreach (GUIStyleState obj in array) { obj.background = normal; obj.textColor = color; } array = (GUIStyleState[])(object)new GUIStyleState[6] { s.hover, s.active, s.focused, s.onHover, s.onActive, s.onFocused }; foreach (GUIStyleState obj2 in array) { obj2.background = hover; obj2.textColor = Color.white; } } private static void Ensure() { //IL_00c8: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0177: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Expected O, but got Unknown //IL_01f8: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Expected O, but got Unknown //IL_026b: Expected O, but got Unknown //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Expected O, but got Unknown //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Expected O, but got Unknown //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Expected O, but got Unknown //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Expected O, but got Unknown //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Expected O, but got Unknown //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Expected O, but got Unknown //IL_0348: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: 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_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Expected O, but got Unknown //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Expected O, but got Unknown //IL_03f1: Expected O, but got Unknown //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_0433: 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) //IL_0442: Expected O, but got Unknown //IL_0442: 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_0451: Expected O, but got Unknown //IL_0456: Expected O, but got Unknown //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_04a0: Expected O, but got Unknown //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Expected O, but got Unknown //IL_04eb: Expected O, but got Unknown //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_051f: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Expected O, but got Unknown //IL_0534: Expected O, but got Unknown //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0564: Expected O, but got Unknown //IL_057d: Unknown result type (might be due to invalid IL or missing references) //IL_0591: Unknown result type (might be due to invalid IL or missing references) //IL_0596: Unknown result type (might be due to invalid IL or missing references) //IL_05a2: Expected O, but got Unknown //IL_05a9: Unknown result type (might be due to invalid IL or missing references) //IL_05bd: Unknown result type (might be due to invalid IL or missing references) //IL_05c7: Expected O, but got Unknown //IL_05df: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_0608: Unknown result type (might be due to invalid IL or missing references) //IL_0610: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Expected O, but got Unknown //IL_0632: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)skin != (Object)null)) { skin = Object.Instantiate<GUISkin>(GUI.skin); ((Object)skin).hideFlags = (HideFlags)61; Font val = (from f in Resources.FindObjectsOfTypeAll<Font>() where ((Object)f).name.IndexOf("Averia", StringComparison.OrdinalIgnoreCase) >= 0 orderby (((Object)f).name.IndexOf("Italic", StringComparison.OrdinalIgnoreCase) < 0) ? ((((Object)f).name.IndexOf("Bold", StringComparison.OrdinalIgnoreCase) >= 0) ? 2 : 0) : 3, (((Object)f).name.IndexOf("Regular", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0 select f).FirstOrDefault(); if ((Object)(object)val != (Object)null) { skin.font = val; } Texture2D val2 = Texture(new Color(0.075f, 0.067f, 0.052f, 0.98f), new Color(0.42f, 0.34f, 0.19f)); Texture2D val3 = Texture(new Color(0.2f, 0.16f, 0.105f, 0.99f), new Color(0.43f, 0.35f, 0.2f)); Texture2D val4 = Texture(new Color(0.34f, 0.26f, 0.13f), Gold); Texture2D normal = Texture(new Color(0.25f, 0.1f, 0.075f), new Color(0.58f, 0.29f, 0.2f)); Texture2D hover = Texture(new Color(0.39f, 0.15f, 0.09f), new Color(0.85f, 0.44f, 0.25f)); skin.window = new GUIStyle(skin.window) { font = skin.font, fontSize = 22, fontStyle = (FontStyle)1, alignment = (TextAnchor)1, padding = new RectOffset(16, 16, 42, 14), border = new RectOffset(2, 2, 2, 2) }; Paint(skin.window, val2, val2, Gold); skin.label = new GUIStyle(skin.label) { font = skin.font, fontSize = 15, wordWrap = true, richText = false, padding = new RectOffset(2, 2, 3, 3), margin = new RectOffset(2, 2, 2, 3) }; skin.label.normal.textColor = Text; skin.button = new GUIStyle(skin.button) { font = skin.font, fontSize = 15, wordWrap = true, alignment = (TextAnchor)4, padding = new RectOffset(8, 8, 7, 7), margin = new RectOffset(3, 3, 4, 4), border = new RectOffset(2, 2, 2, 2), fixedHeight = 0f }; Paint(skin.button, val3, val4, Text); skin.box = new GUIStyle(skin.box) { padding = new RectOffset(8, 8, 6, 6), border = new RectOffset(2, 2, 2, 2) }; Paint(skin.box, val2, val2, Text); Texture2D val5 = Texture(new Color(0.12f, 0.1f, 0.07f), new Color(0.36f, 0.29f, 0.16f)); Texture2D normal2 = Texture(Gold, new Color(0.95f, 0.84f, 0.57f)); skin.horizontalSlider = new GUIStyle(skin.horizontalSlider) { fixedHeight = 8f, margin = new RectOffset(8, 8, 10, 10), border = new RectOffset(2, 2, 2, 2) }; Paint(skin.horizontalSlider, val5, val5, Text); skin.horizontalSliderThumb = new GUIStyle(skin.horizontalSliderThumb) { fixedWidth = 15f, fixedHeight = 20f, overflow = new RectOffset(0, 0, 6, 6), border = new RectOffset(2, 2, 2, 2) }; Paint(skin.horizontalSliderThumb, normal2, val4, Text); skin.verticalScrollbar = new GUIStyle(skin.verticalScrollbar) { fixedWidth = 12f, border = new RectOffset(1, 1, 1, 1) }; Paint(skin.verticalScrollbar, val5, val5, Text); skin.verticalScrollbarThumb = new GUIStyle(skin.verticalScrollbarThumb) { fixedWidth = 12f, border = new RectOffset(1, 1, 1, 1) }; Paint(skin.verticalScrollbarThumb, val3, val4, Text); section = new GUIStyle(skin.label) { fontSize = 16, fontStyle = (FontStyle)1, margin = new RectOffset(2, 2, 12, 5) }; section.normal.textColor = Gold; muted = new GUIStyle(skin.label) { fontSize = 13 }; muted.normal.textColor = new Color(0.73f, 0.71f, 0.64f); primary = new GUIStyle(skin.button) { fontStyle = (FontStyle)1 }; Paint(primary, val4, val3, Gold); danger = new GUIStyle(skin.button); Paint(danger, normal, hover, new Color(1f, 0.81f, 0.7f)); marker = new GUIStyle(skin.box) { font = skin.font, fontSize = 15, alignment = (TextAnchor)4 }; Paint(marker, val2, val2, new Color(1f, 0.55f, 0.95f)); } } internal static void Section(string text) { GUILayout.Label(text, section, Array.Empty<GUILayoutOption>()); } internal static void Hint(string text) { GUILayout.Label(text, muted, Array.Empty<GUILayoutOption>()); } internal static bool Primary(string text) { return GUILayout.Button(text, primary, Array.Empty<GUILayoutOption>()); } internal static bool Danger(string text) { return GUILayout.Button(text, danger, Array.Empty<GUILayoutOption>()); } internal static void Marker(Rect rect, string text) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GUI.Label(rect, text, marker); } internal static void Release() { foreach (Texture2D texture in textures) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } textures.Clear(); if ((Object)(object)skin != (Object)null) { Object.Destroy((Object)(object)skin); } skin = null; section = (muted = (primary = (danger = (marker = null)))); } } internal static class CompatibilityGuard { internal static MethodInfo Require(Type? type, string name, Type result, Type[] parameters, string[]? names = null) { if (type == null) { throw new InvalidOperationException("Missing required type for " + name); } MethodInfo method = type.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); if (method == null || !method.IsStatic || method.ReturnType != result || (names != null && !(from p in method.GetParameters() select p.Name).SequenceEqual<string>(names))) { throw new InvalidOperationException("Unsupported method contract: " + type.FullName + "." + name); } return method; } } internal static class DryPlacement { private delegate bool FloodQuery(Vector3 point, out float level); private static Func<Vector3, bool>? dug; private static FloodQuery? flood; private static Func<Vector3, float>? density; private static ConfigEntry<bool>? enabled; private static readonly MethodInfo Ray = AccessTools.Method(typeof(Physics), "Raycast", new Type[5] { typeof(Vector3), typeof(Vector3), typeof(RaycastHit).MakeByRefType(), typeof(float), typeof(int) }, (Type[])null); private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); internal static bool Enabled { get { if (enabled != null) { return enabled.Value; } return false; } set { if (enabled != null) { enabled.Value = value; } } } internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony) { //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown Type type = upstream.GetType("ValheimTunneling.VoxelWorld"); MethodInfo method = CompatibilityGuard.Require(type, "IsDugSpace", typeof(bool), new Type[1] { typeof(Vector3) }); MethodInfo method2 = CompatibilityGuard.Require(type, "TryGetFloodLevel", typeof(bool), new Type[2] { typeof(Vector3), typeof(float).MakeByRefType() }); MethodInfo method3 = CompatibilityGuard.Require(type, "SampleDensity", typeof(float), new Type[1] { typeof(Vector3) }); density = (Func<Vector3, float>)Delegate.CreateDelegate(typeof(Func<Vector3, float>), method3); dug = (Func<Vector3, bool>)Delegate.CreateDelegate(typeof(Func<Vector3, bool>), method); flood = (FloodQuery)Delegate.CreateDelegate(typeof(FloodQuery), method2); enabled = plugin.Config.Bind<bool>("Building", "CorrectDryTunnelWaterRay", true, "Ignore stale water-plane hits only inside confirmed dry excavated space when aiming a piece forbidden in water. All native validation remains active."); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "PieceRayTest", new Type[6] { typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(Piece).MakeByRefType(), typeof(Heightmap).MakeByRefType(), typeof(Collider).MakeByRefType(), typeof(bool) }, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { throw new InvalidOperationException("Unsupported PieceRayTest contract"); } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DryPlacement), "Transpile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> input) { List<CodeInstruction> list = input.ToList(); if (list.Count((CodeInstruction val2) => CodeInstructionExtensions.Calls(val2, Ray)) != 1) { throw new InvalidOperationException("Expected one native placement ray"); } foreach (CodeInstruction i in list) { if (CodeInstructionExtensions.Calls(i, Ray)) { CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels.AddRange(i.labels); i.labels.Clear(); val.blocks.AddRange(i.blocks); i.blocks.Clear(); yield return val; i.operand = AccessTools.Method(typeof(DryPlacement), "Cast", (Type[])null, (Type[])null); } yield return i; } } private static bool IsDry(Vector3 point) { //IL_001a: 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_0039: Unknown result type (might be due to invalid IL or missing references) float level; if (dug != null && flood != null && density != null && dug(point) && density(point) < 0f) { return !flood(point, out level); } return false; } private static bool Cast(Vector3 origin, Vector3 direction, out RaycastHit hit, float distance, int mask, Player player) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) bool flag = Physics.Raycast(origin, direction, ref hit, distance, mask); if (!Enabled || !flag || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null) { return flag; } int num = LayerMask.NameToLayer("Water"); GameObject val = Ghost.Invoke(player); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 == (Object)null || !val2.m_noInWater || val2.m_waterPiece || ((Component)((RaycastHit)(ref hit)).collider).gameObject.layer != num) { return flag; } try { if (!IsDry(((RaycastHit)(ref hit)).point)) { return flag; } RaycastHit[] array = Physics.RaycastAll(origin, direction, distance, mask); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num2 = 0; num2 < array2.Length; num2++) { RaycastHit val3 = array2[num2]; if (((RaycastHit)(ref val3)).distance < ((RaycastHit)(ref hit)).distance - 0.001f) { continue; } if (((Component)((RaycastHit)(ref val3)).collider).gameObject.layer == num) { if (!IsDry(((RaycastHit)(ref val3)).point)) { return flag; } continue; } if (!IsDry(((RaycastHit)(ref val3)).point - ((Vector3)(ref direction)).normalized * 0.05f)) { return flag; } hit = val3; return true; } } catch (Exception) { } return flag; } } internal sealed class ExcavationMode : MonoBehaviour { private static readonly ExcavationSessionState session = new ExcavationSessionState(); private static MethodInfo worldIdentity = null; private static ConfigEntry<KeyboardShortcut>? toggleKey; private static readonly ManualLogSource Log = Logger.CreateLogSource("Tunnelheim excavation mode"); [ThreadStatic] private static int voxelDamageDepth; private static bool tunnelingEnabled { get { return session.Enabled; } set { session.SetExplicit(value); } } internal static bool Enabled { get { EnsureSession(); return tunnelingEnabled; } } internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown //IL_021b: Expected O, but got Unknown //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown //IL_028b: 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) session.Reset(); if (plugin.Config.Bind<bool>("Excavation", "EnabledOnStart", false, "Deprecated and ignored: every new local player/world session starts OFF. Press F4 to opt in. Config reload does not change an active session.").Value) { Log.LogWarning((object)"Legacy EnabledOnStart=true is ignored; excavation starts OFF and requires explicit F4 opt-in."); } worldIdentity = AccessTools.Method(typeof(ZNet), "GetWorldUID", (Type[])null, (Type[])null) ?? throw new Exception("Missing world identity for safe excavation sessions"); toggleKey = plugin.Config.Bind<KeyboardShortcut>("Excavation", "ToggleKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), "Default F4 approved after local keybind audit; configurable. Choose an unused shortcut to toggle only this local player's excavation interception."); MethodInfo methodInfo = CompatibilityGuard.Require(upstream.GetType("ValheimTunneling.PickaxeDigPatch"), "Prefix", typeof(bool), new Type[5] { typeof(Vector3), typeof(GameObject), typeof(Character), typeof(ItemData), typeof(GameObject).MakeByRefType() }, new string[5] { "hitPoint", "prefab", "character", "weapon", "__result" }); MethodInfo methodInfo2 = CompatibilityGuard.Require(upstream.GetType("ValheimTunneling.VoxelWorld"), "Dig", typeof(void), new Type[5] { typeof(Character), typeof(Vector3), typeof(Vector3), typeof(TerrainOp), typeof(ItemData) }, new string[5] { "attacker", "point", "swingDir", "op", "weapon" }); NativeSurfaceSync.Install(plugin, upstream, harmony); HoeMode.Install(upstream, harmony); harmony.Patch((MethodBase)AccessTools.Method(upstream.GetType("ValheimTunneling.VoxelChunk"), "Damage", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ExcavationMode), "BeginVoxelDamage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ExcavationMode), "EndVoxelDamage", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ExcavationMode), "AllowExcavation", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ExcavationMode), "BypassDig", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((Component)plugin).gameObject.AddComponent<ExcavationMode>(); Log.LogInfo((object)("Installed local excavation mode; tunnelingEnabled=" + tunnelingEnabled + "; hotkey=" + ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString())); } private static bool EnsureSession() { Player localPlayer = Player.m_localPlayer; string current = ""; if ((Object)(object)localPlayer != (Object)null && worldIdentity != null && (Object)(object)ZNet.instance != (Object)null) { current = Convert.ToInt64(worldIdentity.Invoke(ZNet.instance, null)) + ":" + localPlayer.GetPlayerID() + ":" + ((Object)localPlayer).GetInstanceID(); } if (!session.Observe(current)) { return false; } RoutePlanner.Close(); Log.LogInfo((object)"New local player/world session: tunneling OFF; explicit F4 opt-in required."); if ((Object)(object)localPlayer != (Object)null && (Object)(object)MessageHud.instance != (Object)null) { ((Character)localPlayer).Message((MessageType)2, "Tunneling OFF - press F4 to enable excavation", 0, (Sprite)null, false); } return true; } private static bool IsLocalOff(Character c) { EnsureSession(); return ExcavationPolicy.IsLocalOff(tunnelingEnabled, (Object)(object)Player.m_localPlayer != (Object)null, (Object)(object)c == (Object)(object)Player.m_localPlayer); } private static bool AllowExcavation(Character attacker, Vector3 point, TerrainOp op, ItemData weapon) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!IsLocalOff(attacker)) { return true; } if (voxelDamageDepth > 0) { NativeSurfaceSync.MineSurface(attacker, point, op, weapon); } return false; } private static bool BypassDig(Character character, ref bool __result) { if (!IsLocalOff(character)) { return true; } __result = true; return false; } private static void BeginVoxelDamage(HitData hit, out bool __state) { __state = hit != null && IsLocalOff(hit.GetAttacker()) && hit.m_damage.m_pickaxe > 0f && !hit.m_ranged; if (__state) { voxelDamageDepth++; } } private static Exception? EndVoxelDamage(Exception? __exception, bool __state) { if (__state) { voxelDamageDepth--; } return __exception; } internal static void SetEnabled(bool value) { EnsureSession(); tunnelingEnabled = value; Log.LogInfo((object)("Local tunneling=" + (value ? "ON" : "OFF; native mining"))); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, value ? "Tunneling ON" : "Tunneling OFF - native mining and exterior hoe", 0, (Sprite)null, false); } } private void Update() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (EnsureSession() || toggleKey == null) { return; } KeyboardShortcut value = toggleKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && !((Object)(object)Player.m_localPlayer == (Object)null) && !Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !TextInput.IsVisible()) { value = toggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { SetEnabled(!tunnelingEnabled); } } } } internal static class ExcavationPolicy { internal static bool IsLocalOff(bool enabled, bool localPlayerExists, bool samePlayer) { return !enabled && localPlayerExists && samePlayer; } } internal sealed class ExcavationSessionState { private string identity = ""; internal bool Enabled { get; private set; } internal bool Observe(string current) { current = current ?? ""; if (current == identity) { return false; } identity = current; Enabled = false; return true; } internal void SetExplicit(bool value) { Enabled = value; } internal void Reset() { identity = ""; Enabled = false; } } internal static class HoeMode { private sealed class ActionInfo { internal string Name = ""; internal int Alias; internal Settings Native; internal Settings Accepted; } private static ObjectDB? db; private static readonly Dictionary<string, ActionInfo> actions = new Dictionary<string, ActionInfo>(); private static readonly Dictionary<int, ActionInfo> aliases = new Dictionary<int, ActionInfo>(); private static readonly HashSet<Settings> accepted = new HashSet<Settings>(); private static readonly ManualLogSource Log = Logger.CreateLogSource("Hoe mode"); [ThreadStatic] private static ActionInfo? active; private static Vector3 lastAim; private static Player? aimPlayer; private static int aimFrame = -1; private static MethodInfo updateGhost = null; private static FieldInfo ghost = null; internal static bool Active => active != null; internal static bool Matches(TerrainOp op) { if (active != null) { return Utils.GetPrefabName(((Object)((Component)op).gameObject).name) == active.Name; } return false; } internal static bool IsAccepted(Settings s) { return accepted.Contains(s); } internal static void Install(Assembly upstream, Harmony harmony) { //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01b3: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown updateGhost = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null) ?? throw new Exception("Missing placement refresh"); ghost = AccessTools.Field(typeof(Player), "m_placementGhost") ?? throw new Exception("Missing placement ghost"); MethodInfo methodInfo = AccessTools.Method(typeof(Settings), "Serialize", new Type[2] { typeof(ZPackage), typeof(GameObject) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Settings), "Deserialize", new Type[1] { typeof(ZPackage) }, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(Settings) || !methodInfo2.IsStatic || AccessTools.Method(typeof(ZPackage), "GetPos", (Type[])null, (Type[])null) == null || AccessTools.Method(typeof(ZPackage), "SetPos", new Type[1] { typeof(int) }, (Type[])null) == null) { throw new Exception("Changed native terrain request contract"); } harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "TryPlacePiece", new Type[1] { typeof(Piece) }, (Type[])null), new HarmonyMethod(typeof(HoeMode), "BeforePlace", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HoeMode), "AfterPlace", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "PieceRayTest", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(HoeMode), "AimObserved", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HoeMode), "Serialize", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(HoeMode), "Deserialize", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"0.5 candidate: OFF hoe uses marked native requests; ON retains upstream shaping."); } private static void Catalog() { //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown if ((Object)(object)ObjectDB.instance == (Object)null) { throw new Exception("Hoe prefabs not ready"); } if ((Object)(object)db == (Object)(object)ObjectDB.instance && actions.Count > 0) { return; } db = ObjectDB.instance; actions.Clear(); aliases.Clear(); accepted.Clear(); GameObject itemPrefab = db.GetItemPrefab("Hoe"); PieceTable obj = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces); if ((Object)(object)obj == (Object)null) { throw new Exception("Native hoe table missing"); } TerrainOp val = default(TerrainOp); TerrainOp val2 = default(TerrainOp); foreach (GameObject piece in obj.m_pieces) { if ((Object)(object)piece == (Object)null || (Object)(object)piece.GetComponent<TerrainOp>() == (Object)null) { continue; } string prefabName = Utils.GetPrefabName(((Object)piece).name); if (AcceptedSurfacePlan.NativeOnlyAction(prefabName)) { string text = ((prefabName == "AddEarth") ? "raise_v2" : ((prefabName == "SmoothSurface") ? "mud_road_v2" : prefabName)); if (!db.TryGetTerrainOp(StringExtensionMethods.GetStableHashCode(text), ref val)) { throw new Exception("Unknown native hoe action " + text); } int stableHashCode = StringExtensionMethods.GetStableHashCode("local.tunnelheim.nativehoe.0.5/" + prefabName); if (db.TryGetTerrainOp(stableHashCode, ref val2) || aliases.ContainsKey(stableHashCode)) { throw new Exception("Hoe request identifier collision"); } Settings val3 = new Settings(); FieldInfo[] fields = typeof(Settings).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(val3, fieldInfo.GetValue(val.m_settings)); } ActionInfo value = new ActionInfo { Name = prefabName, Alias = stableHashCode, Native = val.m_settings, Accepted = val3 }; actions.Add(prefabName, value); aliases.Add(stableHashCode, value); accepted.Add(val3); } } } private static void AimObserved(Player __instance, bool __result, Vector3 point) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (__result) { aimPlayer = __instance; lastAim = point; aimFrame = Time.frameCount; } } private static bool BeforePlace(Player __instance, Piece piece, ref bool __result, out ActionInfo? __state) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) __state = active; if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || ExcavationMode.Enabled || (Object)(object)piece == (Object)null) { return true; } ItemData val = (ItemData)AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null).Invoke(__instance, null); if (val == null || (Object)(object)val.m_dropPrefab == (Object)null || Utils.GetPrefabName(((Object)val.m_dropPrefab).name) != "Hoe") { return true; } string prefabName = Utils.GetPrefabName(((Object)((Component)piece).gameObject).name); if ((Object)(object)((Component)piece).GetComponent<TerrainOp>() == (Object)null) { return true; } try { if (!AcceptedSurfacePlan.NativeOnlyAction(prefabName)) { throw new Exception("This wall, ceiling or stair tool requires tunneling ON."); } Catalog(); if (!actions.TryGetValue(prefabName, out ActionInfo value)) { throw new Exception("Unsupported hoe action; use tunneling ON."); } updateGhost.Invoke(__instance, new object[1] { true }); if ((int)__instance.GetPlacementStatus() != 0) { return true; } if ((Object)(object)aimPlayer != (Object)(object)__instance || aimFrame != Time.frameCount) { throw new Exception("No current terrain aim; retry."); } if (!NativeSurfaceSync.IsExterior(lastAim)) { throw new Exception("Interior hoe shaping requires tunneling ON."); } GameObject val2 = (GameObject)ghost.GetValue(__instance); if ((Object)val2 == (Object)null) { throw new Exception("No placement preview; retry."); } NativeSurfaceSync.PreflightHoe(val2.transform.position, value.Accepted); active = value; return true; } catch (Exception ex) { __result = false; ((Character)__instance).Message((MessageType)2, ex.GetBaseException().Message, 0, (Sprite)null, false); Log.LogWarning((object)("OFF hoe rejected before placement/resource debit: " + ex.GetBaseException().Message)); return false; } } private static Exception? AfterPlace(Exception? __exception, ActionInfo? __state) { active = __state; return __exception; } private static bool Serialize(ZPackage pkg, GameObject prefab) { if (active == null || Utils.GetPrefabName(((Object)prefab).name) != active.Name) { return true; } pkg.Write(active.Alias); return false; } private static bool Deserialize(ZPackage pkg, ref Settings __result) { int pos = pkg.GetPos(); int key = pkg.ReadInt(); pkg.SetPos(pos); try { Catalog(); } catch (Exception ex) { Log.LogWarning((object)("Hoe request catalog unavailable: " + ex.Message)); return true; } if (!aliases.TryGetValue(key, out ActionInfo value)) { return true; } pkg.ReadInt(); __result = value.Accepted; return false; } } internal static class NativeSurfaceSync { internal sealed class CaptureState { internal Heightmap Hmap; internal bool Hoe; internal Settings Modifier; internal Vector3 Position; internal List<Cell> Cells = new List<Cell>(); internal Dictionary<Vector2Int, object> Records = new Dictionary<Vector2Int, object>(); } internal struct Cell { internal int X; internal int Z; internal float Native; internal float Top; internal Color Paint; } private static Type world = null; private static Type opType = null; private static MethodInfo sample = null; private static MethodInfo top = null; private static MethodInfo isColumn = null; private static MethodInfo apply = null; private static MethodInfo make = null; private static MethodInfo sync = null; private static MethodInfo begin = null; private static MethodInfo end = null; private static FieldInfo hmapField = null; private static FieldInfo initializedField = null; private static ObjectDB? cachedDb; private static readonly HashSet<Settings> stock = new HashSet<Settings>(); private static readonly ManualLogSource Log = Logger.CreateLogSource("Native surface reconciliation"); private static float nextMessage; private static MethodInfo saved = null; private static MethodInfo primary = null; private static bool failed; internal static void Install(BaseUnityPlugin plugin, Assembly upstream, Harmony harmony) { //IL_04ef: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Expected O, but got Unknown //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Expected O, but got Unknown //IL_0532: Expected O, but got Unknown world = upstream.GetType("ValheimTunneling.VoxelWorld", throwOnError: true); opType = upstream.GetType("ValheimTunneling.VoxelOp", throwOnError: true); sample = Need(world, "SeedHeight", new Type[3] { typeof(Heightmap), typeof(float), typeof(float) }); top = Need(world, "TryTopSurface", new Type[3] { typeof(Vector3), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType() }); isColumn = Need(world, "IsVoxelColumnAt", new Type[2] { typeof(float), typeof(float) }); apply = Need(world, "ApplySaved", new Type[2] { opType, typeof(Vector2Int) }); make = Need(opType, "MakeTerrainSized", new Type[4] { typeof(int), typeof(Vector3), typeof(float), typeof(Settings) }); sync = Need(world, "GetOrCreateSync", new Type[1] { typeof(Vector2Int) }); saved = Need(world, "HasSavedTunnel", new Type[1] { typeof(Vector3) }); primary = Need(world, "PrimarySync", new Type[1] { typeof(Vector2Int) }); begin = Need(world, "BeginBatch", Type.EmptyTypes); end = Need(world, "EndBatchQueued", Type.EmptyTypes); hmapField = AccessTools.Field(typeof(TerrainComp), "m_hmap") ?? throw new Exception("TerrainComp heightmap field missing"); initializedField = AccessTools.Field(typeof(TerrainComp), "m_initialized") ?? throw new Exception("TerrainComp initialization field missing"); MethodInfo methodInfo = Need(world, "OnTerrainOp", new Type[1] { typeof(TerrainOp) }); MethodInfo methodInfo2 = Need(typeof(TerrainComp), "DoOperation", new Type[3] { typeof(Vector3), typeof(Vector3), typeof(Settings) }); MethodInfo method = Need(typeof(Heightmap), "Regenerate", Type.EmptyTypes); Type type = upstream.GetType("ValheimTunneling.VoxelColumnSync", throwOnError: true); Contract(sample, typeof(float), isStatic: true); Contract(top, typeof(bool), isStatic: true); Contract(isColumn, typeof(bool), isStatic: true); Contract(apply, typeof(void), isStatic: true); Contract(make, opType, isStatic: true); Contract(sync, type, isStatic: true); Contract(primary, type, isStatic: true); Contract(saved, typeof(bool), isStatic: true); Contract(begin, typeof(void), isStatic: true); Contract(end, typeof(void), isStatic: true); Contract(methodInfo, typeof(bool), isStatic: true); Contract(methodInfo2, typeof(void), isStatic: false); Contract(method, typeof(void), isStatic: false); Contract(Need(type, "SendOps", new Type[1] { typeof(List<>).MakeGenericType(opType) }), typeof(void), isStatic: false); string[] array = new string[4] { "IsValid", "Unreadable", "Built", "IsPending" }; foreach (string text in array) { PropertyInfo propertyInfo = AccessTools.Property(type, text); if (propertyInfo == null || propertyInfo.PropertyType != typeof(bool) || propertyInfo.GetGetMethod(nonPublic: true) == null) { throw new Exception("Missing record property contract " + text); } } if (hmapField.FieldType != typeof(Heightmap) || initializedField.FieldType != typeof(bool)) { throw new Exception("Native terrain field contract changed"); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(NativeSurfaceSync), "UseAcceptedNativeResult", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(NativeSurfaceSync), "Capture", (Type[])null), new HarmonyMethod(typeof(NativeSurfaceSync), "Reconcile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"EXPERIMENT: native accepted lowering -> upstream TerrainSized records; no boundary exclusion zone."); } private static void Contract(MethodInfo method, Type result, bool isStatic) { if (method.ReturnType != result || method.IsStatic != isStatic) { throw new Exception("Changed method contract " + method.DeclaringType?.ToString() + "." + method.Name); } } private static MethodInfo Need(Type type, string name, Type[] args) { return AccessTools.Method(type, name, args, (Type[])null) ?? throw new Exception("Missing contract " + type?.ToString() + "." + name); } private static bool IsStock(Settings settings) { if ((Object)(object)ObjectDB.instance == (Object)null) { return false; } if ((Object)(object)cachedDb != (Object)(object)ObjectDB.instance) { cachedDb = ObjectDB.instance; stock.Clear(); foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop component = item.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData.m_shared.m_damages.m_pickaxe <= 0f) { continue; } GameObject spawnOnHitTerrain = component.m_itemData.m_shared.m_spawnOnHitTerrain; if (!((Object)(object)spawnOnHitTerrain == (Object)null) && !((Object)spawnOnHitTerrain).name.EndsWith("_VVMC", StringComparison.Ordinal)) { TerrainOp componentInChildren = spawnOnHitTerrain.GetComponentInChildren<TerrainOp>(); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.m_settings.m_raise && componentInChildren.m_settings.m_raiseDelta < 0f && !componentInChildren.m_settings.m_level && !componentInChildren.m_settings.m_smooth) { stock.Add(componentInChildren.m_settings); } } } } return stock.Contains(settings); } private static bool IsStockOp(TerrainOp op) { TerrainOp val = default(TerrainOp); if ((Object)(object)op != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.TryGetTerrainOp(StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(((Object)((Component)op).gameObject).name)), ref val)) { return IsStock(val.m_settings); } return false; } private static bool UseAcceptedNativeResult(TerrainOp op, ref bool __result) { if (!IsStockOp(op) && !HoeMode.Matches(op)) { return true; } __result = false; return false; } private static bool Capture(TerrainComp __instance, Vector3 pos, Settings modifier, out CaptureState? __state) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) __state = null; if (!IsStock(modifier) && !HoeMode.IsAccepted(modifier)) { return true; } try { if (failed) { throw new Exception("Previous reconciliation failed; stop this experimental test"); } __state = CaptureCore(__instance, pos, modifier); return true; } catch (Exception ex) { Log.LogWarning((object)("Native edit skipped before mutation; retry required: " + ex.Message)); if ((Object)(object)Player.m_localPlayer != (Object)null && Time.realtimeSinceStartup >= nextMessage) { nextMessage = Time.realtimeSinceStartup + 2f; ((Character)Player.m_localPlayer).Message((MessageType)2, failed ? "Terrain synchronization failed; stop this test and check the log." : "Tunnel terrain is still synchronizing; retry when ready.", 0, (Sprite)null, false); } return false; } } private unsafe static CaptureState? CaptureCore(TerrainComp __instance, Vector3 pos, Settings modifier) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) if ((!IsStock(modifier) && !HoeMode.IsAccepted(modifier)) || !(bool)initializedField.GetValue(__instance)) { return null; } Heightmap val = (Heightmap)hmapField.GetValue(__instance); if ((Object)(object)val == (Object)null) { throw new Exception("Native heightmap unavailable"); } CaptureState captureState = new CaptureState { Hmap = val, Hoe = HoeMode.IsAccepted(modifier), Modifier = modifier, Position = pos }; float num = Mathf.Ceil(modifier.GetRadius() / val.m_scale) * val.m_scale + 2f * val.m_scale; int num2 = Mathf.FloorToInt((pos.x - num) / 0.5f); int num3 = Mathf.CeilToInt((pos.x + num) / 0.5f); int num4 = Mathf.FloorToInt((pos.z - num) / 0.5f); int num5 = Mathf.CeilToInt((pos.z + num) / 0.5f); HashSet<Vector2Int> hashSet = new HashSet<Vector2Int>(); Vector3 val2 = default(Vector3); Vector2Int val3 = default(Vector2Int); Vector3 val4 = default(Vector3); for (int i = num4; i <= num5; i++) { for (int j = num2; j <= num3; j++) { ((Vector3)(ref val2))..ctor((float)j * 0.5f, pos.y, (float)i * 0.5f); ((Vector2Int)(ref val3))..ctor(Mathf.FloorToInt(val2.x / 16f), Mathf.FloorToInt(val2.z / 16f)); bool flag = (bool)isColumn.Invoke(null, new object[2] { val2.x, val2.z }); if (hashSet.Add(val3)) { ((Vector3)(ref val4))..ctor(((float)((Vector2Int)(ref val3)).x + 0.5f) * 16f, pos.y, ((float)((Vector2Int)(ref val3)).y + 0.5f) * 16f); bool flag2 = (bool)saved.Invoke(null, new object[1] { val4 }); if (flag2 && !flag) { Vector2Int val5 = val3; throw new Exception("Saved tunnel column is not loaded: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString()); } if (flag) { object obj = primary.Invoke(null, new object[1] { val3 }); if (obj == null && flag2) { Vector2Int val5 = val3; throw new Exception("Saved tunnel record is unavailable or unreadable: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString()); } if (obj == null) { obj = sync.Invoke(null, new object[1] { val3 }); } bool recordValid = (bool)AccessTools.Property(obj.GetType(), "IsValid").GetValue(obj, null); bool unreadable = (bool)AccessTools.Property(obj.GetType(), "Unreadable").GetValue(obj, null); bool replayed = (bool)AccessTools.Property(obj.GetType(), "Built").GetValue(obj, null); bool pending = (bool)AccessTools.Property(obj.GetType(), "IsPending").GetValue(obj, null); if (!SurfaceReadinessPolicy.CanReconcile(flag2, flag, pending, recordValid, unreadable, replayed)) { Vector2Int val5 = val3; throw new Exception("Tunnel data is not ready: " + ((object)(*(Vector2Int*)(&val5))/*cast due to .constrained prefix*/).ToString()); } captureState.Records.Add(val3, obj); } } if (flag && val.IsPointInside(val2, 0f)) { object[] array = new object[3] { val2, Vector3.zero, Vector3.zero }; if (!(bool)top.Invoke(null, array)) { throw new InvalidOperationException("Voxel top unavailable for native edit"); } captureState.Cells.Add(new Cell { X = j, Z = i, Native = (float)sample.Invoke(null, new object[3] { val, val2.x, val2.z }), Top = ((Vector3)array[1]).y, Paint = val.GetPaintMask(val2) }); } } } if (captureState.Cells.Count <= 0) { return null; } return captureState; } private static void Reconcile(TerrainComp __instance, CaptureState? __state) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0287: 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_0293: 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_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: 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_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Expected O, but got Unknown //IL_030b: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } Need(typeof(Heightmap), "Regenerate", Type.EmptyTypes).Invoke(__state.Hmap, null); Dictionary<Vector2Int, IList> dictionary = new Dictionary<Vector2Int, IList>(); int num = 0; begin.Invoke(null, null); try { Vector2Int key = default(Vector2Int); foreach (Cell cell in __state.Cells) { float num2 = (float)cell.X * 0.5f; float num3 = (float)cell.Z * 0.5f; float num4 = (float)sample.Invoke(null, new object[3] { __state.Hmap, num2, num3 }); if (float.IsNaN(num4) || float.IsInfinity(num4)) { throw new Exception("Non-finite accepted native height"); } List<AcceptedSurfacePlan.Step> list = AcceptedSurfacePlan.Create(cell.Native, num4, cell.Top, __state.Hoe); bool flag = __state.Hoe && __state.Modifier.m_paintCleared && (__state.Hmap.GetPaintMask(new Vector3(num2, num4, num3)) != cell.Paint || list.Count > 0); if (list.Count == 0 && !flag) { continue; } ((Vector2Int)(ref key))..ctor(Mathf.FloorToInt(num2 / 16f), Mathf.FloorToInt(num3 / 16f)); if (!dictionary.TryGetValue(key, out var value)) { value = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(opType)); dictionary.Add(key, value); } foreach (AcceptedSurfacePlan.Step item in list) { float reference = item.Reference; float target = item.Target; Settings val = new Settings { m_level = false, m_raise = true, m_raiseRadius = 0.01f, m_raiseDelta = target - reference, m_raisePower = 0f, m_square = false, m_smooth = false, m_paintCleared = false }; object value2 = make.Invoke(null, new object[4] { StringExtensionMethods.GetStableHashCode("digg"), (object)new Vector3(num2, reference, num3), 0f, val }); value.Add(value2); num++; } if (flag) { Settings val2 = new Settings { m_level = false, m_raise = false, m_smooth = false, m_paintCleared = true, m_paintRadius = 0.01f, m_square = false, m_paintType = __state.Modifier.m_paintType }; float num5 = ((list.Count > 0) ? num4 : cell.Top); value.Add(make.Invoke(null, new object[4] { StringExtensionMethods.GetStableHashCode("digg"), (object)new Vector3(num2, num5, num3), 0f, val2 })); num++; } } foreach (KeyValuePair<Vector2Int, IList> item2 in dictionary) { foreach (object item3 in item2.Value) { apply.Invoke(null, new object[2] { item3, item2.Key }); } object obj = __state.Records[item2.Key]; Need(obj.GetType(), "SendOps", new Type[1] { typeof(List<>).MakeGenericType(opType) }).Invoke(obj, new object[1] { item2.Value }); } } catch (Exception ex) { failed = true; Log.LogError((object)("EXPERIMENT FAILED after native edit; preserve checkpoint and stop testing: " + ex)); throw; } finally { end.Invoke(null, null); } Log.LogInfo((object)("ACCEPTED native surface hmap=" + ((object)((Component)__state.Hmap).transform.position/*cast due to .constrained prefix*/).ToString() + " records=" + num + " columns=" + dictionary.Count + "; existing upstream replay/snapshot format")); } internal static bool IsExterior(Vector3 point) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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) if (!(bool)isColumn.Invoke(null, new object[2] { point.x, point.z })) { return true; } object[] array = new object[3] { point, Vector3.zero, Vector3.zero }; if (!(bool)top.Invoke(null, array)) { throw new Exception("Tunnel surface unavailable; retry when ready."); } return AcceptedSurfacePlan.Exterior(point.y, ((Vector3)array[1]).y); } internal static void PreflightHoe(Vector3 point, Settings settings) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) List<Heightmap> list = new List<Heightmap>(); Heightmap.FindHeightmap(point, settings.GetRadius() + 2f, list); if (list.Count == 0) { throw new Exception("Terrain is not loaded; retry when ready."); } foreach (Heightmap item in list) { TerrainComp andCreateTerrainCompiler = item.GetAndCreateTerrainCompiler(); if (!(bool)initializedField.GetValue(andCreateTerrainCompiler)) { throw new Exception("Terrain is still initializing; retry when ready."); } CaptureCore(andCreateTerrainCompiler, point, settings); } } internal static void MineSurface(Character attacker, Vector3 point, TerrainOp op, ItemData weapon) { //IL_0014: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (weapon == null || !IsStockOp(op)) { return; } object[] array = new object[3] { point, Vector3.zero, Vector3.zero }; if (!(bool)top.Invoke(null, array)) { throw new Exception("Cannot identify voxel surface"); } Vector3 val = (Vector3)array[1]; if (point.y < val.y - 0.75f) { if (Time.realtimeSinceStartup >= nextMessage) { nextMessage = Time.realtimeSinceStartup + 2f; attacker.Message((MessageType)2, "Interior rock requires tunneling ON; ore mining remains enabled.", 0, (Sprite)null, false); } } else { Attack.SpawnOnHitTerrain(point, weapon.m_shared.m_spawnOnHitTerrain, attacker, 0f, weapon, (ItemData)null, false); } } } internal sealed class PlannerCaptureState { private bool armed; private int releaseFrames; internal bool Capturing { get; private set; } internal bool Draining { get; private set; } internal bool Blocking { get { if (!Capturing) { return Draining; } return true; } } internal void Tick(bool visible, bool focused, bool otherUi, bool modal, bool held, bool mouseHeld) { bool capturing = Capturing; if (!visible || !focused || otherUi) { Capturing = false; armed = false; } else { if (!held) { armed = true; } Capturing = modal || (held && armed); } if (capturing && !Capturing) { Draining = true; releaseFrames = 2; } if (Draining && !Capturing && !mouseHeld) { if (releaseFrames > 0) { releaseFrames--; } else { Draining = false; } } } internal void Suspend() { if (Capturing) { Draining = true; releaseFrames = 2; } Capturing = false; armed = false; } } [BepInPlugin("local.tunnelheim.buildingfix", "Tunnelheim Companion Experimental", "0.8.3")] [BepInDependency("sam.valheim.tunneling", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.tunnelheim.buildingfix"; private Harmony? harmony; private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("sam.valheim.tunneling", out var value) || value.Metadata.Version != new Version(1, 0, 0)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Unverified Tunnelheim version; no patches applied."); return; } harmony = new Harmony("local.tunnelheim.buildingfix"); try { DryPlacement.Install((BaseUnityPlugin)(object)this, ((object)value.Instance).GetType().Assembly, harmony); ExcavationMode.Install((BaseUnityPlugin)(object)this, ((object)value.Instance).GetType().Assembly, harmony); CanalMode.Install((BaseUnityPlugin)(object)this, value.Instance, harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Local excavation toggle and dry tunnel water-ray correction installed; native placement validation retained."); } catch (Exception ex) { harmony.UnpatchSelf(); ExcavationMode[] components = ((Component)this).GetComponents<ExcavationMode>(); for (int i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } CanalMode[] components2 = ((Component)this).GetComponents<CanalMode>(); for (int i = 0; i < components2.Length; i++) { Object.Destroy((Object)(object)components2[i]); } RoutePlanner[] components3 = ((Component)this).GetComponents<RoutePlanner>(); for (int i = 0; i < components3.Length; i++) { Object.Destroy((Object)(object)components3[i]); } ((BaseUnityPlugin)this).Logger.LogError((object)("Companion disabled after incompatible hooks; upstream Tunnelheim remains active. F4/Canal controls disabled: " + ex)); } } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } public static class RouteCodec { private const int Magic = 1195591764; public static byte[] Encode(RouteSurface s, string identity) { s.Validate(); if (identity == null || identity.Length < 1 || identity.Length > 96) { throw new ArgumentException("Invalid guide identity"); } using MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true)) { binaryWriter.Write(1195591764); binaryWriter.Write(1); binaryWriter.Write(identity); binaryWriter.Write(s.Revision); binaryWriter.Write(s.NX); binaryWriter.Write(s.NZ); binaryWriter.Write(s.X0); binaryWriter.Write(s.Z0); binaryWriter.Write(s.Step); binaryWriter.Write(s.Sea); binaryWriter.Write(s.Settings.BottomWidth); binaryWriter.Write(s.Settings.Depth); binaryWriter.Write(s.Settings.BankRun); binaryWriter.Write(s.Controls.Length); RoutePoint[] controls = s.Controls; for (int i = 0; i < controls.Length; i++) { RoutePoint routePoint = controls[i]; binaryWriter.Write(routePoint.X); binaryWriter.Write(routePoint.Z); } for (int j = 0; j < s.Heights.Length; j++) {