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 HearthBelow v0.6.1
HearthBelow.dll
Decompiled a month 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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HearthBelow.Diagnostics; using HearthBelow.Digging; using HearthBelow.Patches; using HearthBelow.Util; using HearthBelow.VoxelMagic; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HearthBelow")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Azumatt")] [assembly: AssemblyProduct("HearthBelow")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("0.6.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.1.0")] [module: UnverifiableCode] [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 LocalizationManager { [PublicAPI] public class Localizer { private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors; private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts; private static readonly ConditionalWeakTable<Localization, string> localizationLanguage; private static readonly List<WeakReference<Localization>> localizationObjects; private static BaseUnityPlugin? _plugin; private static readonly List<string> fileExtensions; private static BaseUnityPlugin plugin { get { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown if (_plugin == null) { IEnumerable<TypeInfo> source; try { List<TypeInfo> list = new List<TypeInfo>(); list.AddRange(Assembly.GetExecutingAssembly().DefinedTypes); source = new <>z__ReadOnlyList<TypeInfo>(list); } catch (ReflectionTypeLoadException ex) { source = from type in ex.Types where type != null select type.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo type) => type.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(type))); } return _plugin; } } public static event Action? OnLocalizationComplete; private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out string value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> value2)) { text = value2.Aggregate(text, (string current, KeyValuePair<string, Func<string>> processor) => current.Replace("{" + processor.Key + "}", processor.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull { if (convertConfigValue == null) { convertConfigValue = (T value) => value.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += delegate { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value); UpdatePlaceholderText(Localization.instance, key); } } public static void AddText(string key, string text) { List<WeakReference<Localization>> list = new List<WeakReference<Localization>>(); foreach (WeakReference<Localization> localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference<Localization> item in list) { localizationObjects.Remove(item); } } public static void Load() { _ = plugin; } public static void LoadLocalizationLater(Localization __instance) { LoadLocalization(Localization.instance, __instance.GetSelectedLanguage()); } public static void SafeCallLocalizeComplete() { Localizer.OnLocalizationComplete?.Invoke(); } private static void LoadLocalization(Localization __instance, string language) { if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference<Localization>(__instance)); } localizationLanguage.Add(__instance, language); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string item in from path in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where fileExtensions.IndexOf(Path.GetExtension(path)) >= 0 select path) { string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' }); if (array.Length >= 2) { string text = array[1]; if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } } byte[] array2 = LoadTranslationFromAssembly("English"); if (array2 == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array2)); if (dictionary2 == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text2 = null; if (language != "English") { if (dictionary.TryGetValue(language, out var value)) { text2 = File.ReadAllText(value); } else { byte[] array3 = LoadTranslationFromAssembly(language); if (array3 != null) { text2 = Encoding.UTF8.GetString(array3); } } } if (text2 == null && dictionary.TryGetValue("English", out var value2)) { text2 = File.ReadAllText(value2); } if (text2 != null) { foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair<string, string> item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>(); loadedTexts = new Dictionary<string, Dictionary<string, string>>(); localizationLanguage = new ConditionalWeakTable<Localization, string>(); localizationObjects = new List<WeakReference<Localization>>(); fileExtensions = new List<string>(2) { ".json", ".yml" }; Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static byte[]? LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string resourceName) => resourceName.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } public static class LocalizationManagerVersion { public const string Version = "1.4.1"; } } namespace HearthBelow { [BepInPlugin("Azumatt.HearthBelow", "HearthBelow", "0.6.1")] public class HearthBelowPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } public enum DigShape { Sphere, Cube } public enum DigStyle { Gradual, Blast } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] public string? Category; [UsedImplicitly] public Action<ConfigEntryBase>? CustomDrawer; } internal const string ModName = "HearthBelow"; internal const string ModVersion = "0.6.1"; internal const string Author = "Azumatt"; private const string ModGUID = "Azumatt.HearthBelow"; private static string ConfigFileName = "Azumatt.HearthBelow.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("Azumatt.HearthBelow"); internal static Harmony HarmonyInstance; public static readonly ManualLogSource HearthBelowLogger; private static readonly ConfigSync ConfigSync; private FileSystemWatcher? _watcher; private readonly object _reloadLock = new object(); private DateTime _lastConfigReloadTime; private const long ReloadDelayTicks = 10000000L; internal static ConfigFile ConfigFile; private static ConfigEntry<Toggle> _serverConfigLocked; internal static ConfigEntry<Toggle> VoxelDigging; internal static ConfigEntry<DigStyle> DigMode; internal static ConfigEntry<float> DigDepthPerHit; internal static ConfigEntry<float> CarveRadius; internal static ConfigEntry<DigShape> CarveShape; internal static ConfigEntry<float> CaveDepth; internal static ConfigEntry<Toggle> ToolDepthLimits; internal static ConfigEntry<string> ToolTierDepthList; internal static ConfigEntry<string> ToolTierSizeList; internal static ConfigEntry<Toggle> ExtendToolTierLimits; internal static ConfigEntry<int> MaxOpsPerZone; internal static ConfigEntry<string> UndergroundEnvironment; internal static ConfigEntry<float> UndergroundEnvironmentDepth; internal static ConfigEntry<Toggle> UndergroundPainting; internal static ConfigEntry<float> CaveWeatherCover; internal static ConfigEntry<string> CaveWeatherParticles; internal static ConfigEntry<Toggle> AllowDigCustomization; internal static ConfigEntry<Toggle> DropUnsupportedTerrain; internal static ConfigEntry<float> MaxPlayerCarveRadius; internal static ConfigEntry<float> RadiusCostScaling; internal static ConfigEntry<float> DigYieldScaling; internal static ConfigEntry<Toggle> RemoveModsClearsCaves; internal static ConfigEntry<Toggle> DigPreview; internal static ConfigEntry<Toggle> DigPreviewHideRunning; internal static ConfigEntry<float> DigReadoutTimeout; internal static ConfigEntry<Toggle> DigReadoutToolName; internal static ConfigEntry<KeyboardShortcut> DigPreviewToggleKey; internal static ConfigEntry<Toggle> DigPreviewFill; internal static ConfigEntry<Color> DigPreviewOutlineColor; internal static ConfigEntry<float> DigPreviewFillCenterAlpha; internal static ConfigEntry<float> DigPreviewFillEdgeAlpha; internal static ConfigEntry<Toggle> DigPreviewImpact; internal static ConfigEntry<float> DigPreviewImpactSize; internal static ConfigEntry<Toggle> DigPreviewOutline; internal static ConfigEntry<Color> DigPreviewColor; internal static ConfigEntry<float> DigPreviewWidth; internal static ConfigEntry<KeyboardShortcut> DigControlsModifier; internal static ConfigEntry<KeyboardShortcut> DigShapeKey; internal static ConfigEntry<KeyboardShortcut> DigModeKey; internal static ConfigEntry<float> DigSizeStep; internal static ConfigEntry<float> SavedDigRadius; internal static ConfigEntry<DigShape> SavedDigShape; internal static ConfigEntry<DigStyle> SavedDigMode; private static bool _environmentChoicesOpen; private static Vector2 _environmentChoicesScroll; internal static bool LocalPlayerIsAdmin => ConfigSync.IsAdmin; public void Awake() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Expected O, but got Unknown //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Expected O, but got Unknown //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Expected O, but got Unknown //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Expected O, but got Unknown //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Expected O, but got Unknown //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Expected O, but got Unknown //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Expected O, but got Unknown //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Expected O, but got Unknown //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Expected O, but got Unknown //IL_04f5: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Expected O, but got Unknown //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Expected O, but got Unknown //IL_05a6: Unknown result type (might be due to invalid IL or missing references) //IL_05b1: Expected O, but got Unknown //IL_05e3: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Expected O, but got Unknown //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_063d: Expected O, but got Unknown //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_067e: Expected O, but got Unknown //IL_06b0: Unknown result type (might be due to invalid IL or missing references) //IL_06ba: Expected O, but got Unknown //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_06f6: Expected O, but got Unknown //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Expected O, but got Unknown //IL_0776: Unknown result type (might be due to invalid IL or missing references) //IL_0780: Expected O, but got Unknown //IL_07a0: Unknown result type (might be due to invalid IL or missing references) //IL_07c6: Unknown result type (might be due to invalid IL or missing references) //IL_07d0: Expected O, but got Unknown //IL_0802: Unknown result type (might be due to invalid IL or missing references) //IL_080c: Expected O, but got Unknown //IL_0830: Unknown result type (might be due to invalid IL or missing references) //IL_0856: Unknown result type (might be due to invalid IL or missing references) //IL_0860: Expected O, but got Unknown //IL_08a4: Unknown result type (might be due to invalid IL or missing references) //IL_08ae: Expected O, but got Unknown //IL_08f2: Unknown result type (might be due to invalid IL or missing references) //IL_08fc: Expected O, but got Unknown //IL_092e: Unknown result type (might be due to invalid IL or missing references) //IL_0938: Expected O, but got Unknown //IL_097c: Unknown result type (might be due to invalid IL or missing references) //IL_0986: Expected O, but got Unknown //IL_09b8: Unknown result type (might be due to invalid IL or missing references) //IL_09c2: Expected O, but got Unknown //IL_09e6: Unknown result type (might be due to invalid IL or missing references) //IL_0a0c: Unknown result type (might be due to invalid IL or missing references) //IL_0a16: Expected O, but got Unknown //IL_0a5a: Unknown result type (might be due to invalid IL or missing references) //IL_0a64: Expected O, but got Unknown //IL_0a7e: Unknown result type (might be due to invalid IL or missing references) //IL_0aa4: Unknown result type (might be due to invalid IL or missing references) //IL_0aae: Expected O, but got Unknown //IL_0ac5: Unknown result type (might be due to invalid IL or missing references) //IL_0aeb: Unknown result type (might be due to invalid IL or missing references) //IL_0af5: Expected O, but got Unknown //IL_0b0c: Unknown result type (might be due to invalid IL or missing references) //IL_0b32: Unknown result type (might be due to invalid IL or missing references) //IL_0b3c: Expected O, but got Unknown //IL_0b80: Unknown result type (might be due to invalid IL or missing references) //IL_0b8a: Expected O, but got Unknown //IL_0bbf: Unknown result type (might be due to invalid IL or missing references) //IL_0bc9: Expected O, but got Unknown //IL_0bfa: Unknown result type (might be due to invalid IL or missing references) //IL_0c04: Expected O, but got Unknown //IL_0c35: Unknown result type (might be due to invalid IL or missing references) //IL_0c3f: Expected O, but got Unknown ConfigFile = ((BaseUnityPlugin)this).Config; Localizer.Load(); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, new ConfigDescription("If on, the configuration is locked and can be changed by server admins only.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 100 } })); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); VoxelDigging = config("2 - Digging", "Voxel Digging", Toggle.On, new ConfigDescription("Master switch. If on, pickaxes carve real holes and tunnels into the terrain - dig sideways into a hillside, hollow out a mountain. If off, digging works like vanilla.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 90 } })); DigMode = config("2 - Digging", "Dig Mode", DigStyle.Gradual, new ConfigDescription("Gradual takes a shallow bite in the direction you swing, so repeated hits dig in predictably like vanilla terrain edits do. Blast removes the full Carve Radius in a single hit.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 89 } })); DigDepthPerHit = config("2 - Digging", "Dig Depth Per Hit", 0.75f, new ConfigDescription("Gradual mode only. How many meters a single pickaxe hit bites into the surface.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 88 } })); CarveRadius = config("2 - Digging", "Carve Radius", 1.6f, new ConfigDescription("How wide the hole from one pickaxe hit is, in meters. The terrain is sampled every meter, so radii under 1 can miss every sample and report that the ground is too hard.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 87 } })); CarveShape = config("2 - Digging", "Dig Shape", DigShape.Cube, new ConfigDescription("Cube digs flat floors, walls and ceilings, which is great for building. Sphere digs round, organic looking caves.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 86 } })); CaveDepth = config("2 - Digging", "Max Cave Depth", 128f, new ConfigDescription("How many meters below the original terrain surface you can dig, no matter the tool. Keep this at or above the deepest Tool Tier Depth Limit (default 128 = blackmetal) or the top tiers get silently cut short. Higher values use more memory per dug-out zone. Avoid changing this on a world that already has deep caves.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 256f), new object[1] { new ConfigurationManagerAttributes { Order = 85 } })); ToolDepthLimits = config("2 - Digging", "Tool Depth Limits", Toggle.On, new ConfigDescription("If on, better pickaxes dig deeper (see Tool Tier Depth Limits). Digging at a tool's limit leaves a flat, even floor - swapping to a lower tier pickaxe on purpose is a handy way to line up floors for building. If off, every pickaxe digs to Max Cave Depth.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 84 } })); ToolTierDepthList = config("2 - Digging", "Tool Tier Depth Limits", "0:8,1:16,2:48,3:128", new ConfigDescription("Tier:meters pairs, comma separated. Tier is the pickaxe's tool tier - the same stat that decides which ores it can mine - so modded pickaxes fit in automatically. Vanilla: 0 = antler/stone, 1 = bronze, 2 = iron, 3 = blackmetal. The defaults are tuned around two anchors: 8m is vanilla's own dig limit (so antler/stone feel vanilla), and 16m is where the cave ambience kicks in - bronze digs to the edge of the dark, iron is the first pickaxe that takes you properly into it, and blackmetal reaches the digging floor. Tiers not listed here follow Extend Tool Tier Limits.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 83 } })); ToolTierSizeList = config("2 - Digging", "Tool Tier Size Limits", "", new ConfigDescription("The partner to Tool Tier Depth Limits, for how wide a hole a pickaxe can make. Tier:meters pairs, comma separated, measured across - diameter for a sphere, edge length for a cube - so \"0:3,1:4,2:5,3:6\" walks antler up to blackmetal. Leave this empty and only Max Player Carve Radius limits size.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 82 } })); ExtendToolTierLimits = config("2 - Digging", "Extend Tool Tier Limits", Toggle.On, new ConfigDescription("What happens to a pickaxe whose tool tier is not in the two lists above - a modded flametal pick at tier 4, say. If on, its limit is worked out from the tiers that are listed, following the same step they already climb by, so tier 4 on the default depth list reaches 208m. If off, an unlisted tier digs with no tool limit at all.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 82 } })); MaxOpsPerZone = config("2 - Digging", "Max Carves Per Zone", 5000, new ConfigDescription("Safety cap on how many dig operations a single 64x64m zone can store. Normal play won't get anywhere near this.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 20000), new object[1] { new ConfigurationManagerAttributes { Order = 82 } })); AllowDigCustomization = config("2 - Digging", "Allow Dig Customization", Toggle.On, new ConfigDescription("If on, players can change their own carve radius, dig shape and dig mode on the fly with the dig controls, within the limit set below. If off, everyone digs with the Carve Radius, Dig Shape and Dig Mode set here and the controls do nothing.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 81 } })); RadiusCostScaling = config("2 - Digging", "Radius Cost Scaling", 2f, new ConfigDescription("How much harder a bigger dig is on you. A swing's stamina and tool wear are scaled by how much more rock it takes than a default swing, so a wide blast costs several times a narrow scoop and a small dig costs less. 3 makes the cost track the removed volume exactly, 1 is gentle, 0 turns it off and every swing costs the vanilla amount no matter the radius. The scaling tops out at 100x a default swing. Vanilla's own skill discount, equipment modifiers and status effects still apply on top.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 79 } })); DigYieldScaling = config("2 - Digging", "Dig Yield Scaling", 3f, new ConfigDescription("How much a bigger dig pays out. A swing's stone and ore drops are scaled by how much more rock it took out than a default swing, the same way Radius Cost Scaling scales what it costs you. 3 makes the drop track the removed volume exactly, so the yield per cubic meter is the same whatever size you dig at, 1 is gentle, 0 turns it off and every swing drops the vanilla amount no matter the radius. A dig smaller than the Carve Radius still drops what vanilla would - this only ever scales a payout up. The scaling tops out at 100x a default swing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 79 } })); RemoveModsClearsCaves = config("2 - Digging", "Remove Terrain Modifications Clears Caves", Toggle.On, new ConfigDescription("If another terrain mod offers a \"remove terrain modifications\" tool (Searica's AdvancedTerrainModifiers has one), using it also clears this zone's caves, the same as the 'hearthbelow restore' command. Without this the tool resets the heightmap but the cave stays, because a dug zone is not drawn from that heightmap. Careful either way: restoring a zone entombs anything built in its caves.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 78 } })); DropUnsupportedTerrain = config("2 - Digging", "Drop Unsupported Terrain", Toggle.On, new ConfigDescription("Carving has no idea what holds a mountain up, so slicing a chunk out from under an overhang leaves it hanging in mid air. On, a swing also drops any lump of rock it just cut free, along with whatever ore vein was resting on it. Only looks 12m around the hit, so a genuinely huge slab is left where it is - it might be your roof.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 81 } })); MaxPlayerCarveRadius = config("2 - Digging", "Max Player Carve Radius", 3f, new ConfigDescription("The widest carve radius a player is allowed to pick with the dig controls, in meters. This is the admin cap - it is enforced again on the zone's owner, so a client cannot talk its way past it. Raising it lets people scoop out big rooms fast, which is handy for base builders and much less vanilla; every extra meter also costs more remeshing per swing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), new object[1] { new ConfigurationManagerAttributes { Order = 80 } })); UndergroundEnvironment = config("3 - Underground", "Underground Environment", "Darklands_dark", new ConfigDescription("Ambience/weather while you are deep inside a cave, applied the same way vanilla dungeons do it (fades in and out like a weather change). Configuration Manager lists the environments available to the vanilla env command and still accepts typed modded environment names. Not case sensitive. Leave empty to keep the outside weather underground.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 79, CustomDrawer = DrawEnvironment } }), synchronizedSetting: false); UndergroundEnvironmentDepth = config("3 - Underground", "Underground Environment Depth", 16f, new ConfigDescription("How many meters below the original surface you must be before the cave ambience starts. Keeps shallow dugouts and walk-in basements feeling like the outdoors. The default 16 lines up with the bronze pickaxe's depth limit, so darkness arrives with iron-tier digging.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 32f), new object[1] { new ConfigurationManagerAttributes { Order = 78 } }), synchronizedSetting: false); UndergroundPainting = config("3 - Underground", "Underground Painting", Toggle.On, new ConfigDescription("Let hoe paths/paving paint cave floors. Heads up: the game stores terrain paint top-down with no depth, so a painted cave floor also shows on the ground directly above the cave. Turn off if clean surfaces matter more to you than paintable cave floors.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 77 } })); CaveWeatherCover = config("3 - Underground", "Cave Weather Shelter Cover", 0.6f, new ConfigDescription("How enclosed a spot has to be before rain and snow stop reaching you, as a fraction of vanilla's 17 cover rays that must hit rock (vanilla asks 0.8 for a roofed house). Lower it if weather still reaches too far into your caves, raise it if it cuts out too soon after you step inside.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 75 } }), synchronizedSetting: false); CaveWeatherParticles = config("3 - Underground", "Cave Weather Particles", "rain,snow,sleet,hail,ash", new ConfigDescription("Which of an environment's particle effects rock overhead switches off, matched as comma separated pieces of their names. An environment ships one list holding everything it shows - Rain's is Rain, GroundMist, FogClouds and OceanMist - so this is what separates weather falling out of the sky from ambient effects a cave is meant to keep. Add a name here if another mod's weather still follows you underground.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 74 } }), synchronizedSetting: false); DigPreview = clientConfig("4 - Dig Controls", "Dig Preview", Toggle.On, new ConfigDescription("Show a projected outline on the ground where your next pickaxe swing will bite, sized and shaped to your current dig settings.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 69 } })); DigPreviewHideRunning = clientConfig("4 - Dig Controls", "Hide Preview While Running", Toggle.On, new ConfigDescription("Drop the overlay while you are running, so the paint is not sliding around under you as you travel. It comes straight back when you stop.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 74 } })); DigReadoutTimeout = clientConfig("4 - Dig Controls", "Dig Readout Timeout", 4f, new ConfigDescription("Seconds the line of text under the overlay stays up after something changes, before it fades out. The overlay itself is unaffected. 0 keeps the text up the whole time a pickaxe is out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), new object[1] { new ConfigurationManagerAttributes { Order = 73 } })); DigReadoutToolName = clientConfig("4 - Dig Controls", "Dig Readout Tool Name", Toggle.Off, new ConfigDescription("Include the pickaxe's name in that line. Off by default - you know what you are holding.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 72 } })); DigPreviewToggleKey = clientConfig<KeyboardShortcut>("4 - Dig Controls", "Toggle Dig Preview", new KeyboardShortcut((KeyCode)98, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), new ConfigDescription("Turns the overlay off and on while you play, without opening the config. Works whether it is currently showing or not, and is remembered between sessions.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 71 } })); DigPreviewFill = clientConfig("4 - Dig Controls", "Dig Preview Fill", Toggle.On, new ConfigDescription("Wash the ground inside the ring, so the dig reads as an area rather than a hairline.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 70 } })); DigPreviewOutlineColor = clientConfig<Color>("4 - Dig Controls", "Dig Preview Outline Color", new Color(0.5059f, 0.5804f, 0.7059f, 1f), new ConfigDescription("Colour of the ring and the impact mark. These carry the read, so keep them brighter than the fill.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 67 } })); DigPreviewFillCenterAlpha = clientConfig("4 - Dig Controls", "Dig Preview Fill Center Alpha", 0.1f, new ConfigDescription("How opaque the wash is at the middle of the dig, as a fraction of the fill colour's own alpha.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 66 } })); DigPreviewFillEdgeAlpha = clientConfig("4 - Dig Controls", "Dig Preview Fill Edge Alpha", 0.42f, new ConfigDescription("The same at the rim. Higher than the centre gives the vanilla-ish look of a ring that fades inward.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 65 } })); DigPreviewImpact = clientConfig("4 - Dig Controls", "Dig Preview Impact Marker", Toggle.On, new ConfigDescription("Mark the exact spot the pickaxe head would connect with the terrain, worked out before you swing rather than after. Within about 0.15m of where the hit actually lands.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 69 } })); DigPreviewImpactSize = clientConfig("4 - Dig Controls", "Dig Preview Impact Marker Size", 0.14f, new ConfigDescription("Radius of that mark, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 68 } })); DigPreviewOutline = clientConfig("4 - Dig Controls", "Dig Preview Outline", Toggle.On, new ConfigDescription("Outline the dig. With the Footprint fill this is traced from the painted patch itself, so it follows the real edge on any surface. The other fills fall back to a flat ring pressed against the surface you aim at, which does not know your swing angle.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 68 } })); DigPreviewColor = clientConfig<Color>("4 - Dig Controls", "Dig Preview Color", new Color(0.2392f, 0.302f, 0.4039f, 1f), new ConfigDescription("Colour of the dig preview outline. It brightens while you hold the dig controls modifier.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 68 } })); DigPreviewWidth = clientConfig("4 - Dig Controls", "Dig Preview Line Width", 0.03f, new ConfigDescription("Thickness of the preview outline in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.3f), new object[1] { new ConfigurationManagerAttributes { Order = 67 } })); DigControlsModifier = clientConfig<KeyboardShortcut>("4 - Dig Controls", "Dig Controls Modifier", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription("Hold this to open the dig mode bar. While it is held, the mouse wheel resizes your dig and the two keys below switch shape and mode. Keyboard and mouse only - gamepad is not wired up yet.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 67 } })); DigShapeKey = clientConfig<KeyboardShortcut>("4 - Dig Controls", "Cycle Dig Shape", new KeyboardShortcut((KeyCode)122, Array.Empty<KeyCode>()), new ConfigDescription("Switches between sphere and cube digging. Only fires while the modifier is held, so it will not fight whatever else this key does.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 66 } })); DigModeKey = clientConfig<KeyboardShortcut>("4 - Dig Controls", "Cycle Dig Mode", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), new ConfigDescription("Switches between gradual and blast digging. Only fires while the modifier is held.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 65 } })); DigSizeStep = clientConfig("4 - Dig Controls", "Dig Size Step", 0.2f, new ConfigDescription("How many meters across one notch of the mouse wheel changes your dig by - the same measure the bar and the readout show, so a step of 0.2 walks 2.0m, 2.2m, 2.4m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), new object[1] { new ConfigurationManagerAttributes { Order = 64 } })); SavedDigRadius = clientConfig("4 - Dig Controls", "Saved Dig Radius", 0f, new ConfigDescription("Your current carve radius, remembered between sessions. 0 means you have not changed it yet and the server's Carve Radius is used.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } })); SavedDigShape = clientConfig("4 - Dig Controls", "Saved Dig Shape", DigShape.Cube, new ConfigDescription("Your current dig shape, remembered between sessions.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } })); SavedDigMode = clientConfig("4 - Dig Controls", "Saved Dig Mode", DigStyle.Gradual, new ConfigDescription("Your current dig mode, remembered between sessions.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } })); Assembly executingAssembly = Assembly.GetExecutingAssembly(); HarmonyInstance = _harmony; _harmony.PatchAll(executingAssembly); SetupWatcher(); ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { SaveWithRespectToConfigSet(); _watcher?.Dispose(); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; _watcher = fileSystemWatcher; } private void ReadConfigValues(object sender, FileSystemEventArgs eventArgs) { DateTime now = DateTime.Now; if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { HearthBelowLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { HearthBelowLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); HearthBelowLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { HearthBelowLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } _lastConfigReloadTime = now; } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private ConfigEntry<T> clientConfig<T>(string group, string name, T value, ConfigDescription description) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, new ConfigDescription(description.Description + " [Not Synced with Server]", description.AcceptableValues, description.Tags)); } private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } private static void DrawEnvironment(ConfigEntryBase configEntry) { //IL_0097: 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) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = (string)configEntry.BoxedValue; string text2 = GUILayout.TextField(text, Array.Empty<GUILayoutOption>()); if (text2 != text) { configEntry.BoxedValue = text2; } if (GUILayout.Button(_environmentChoicesOpen ? "▲" : "▼", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) })) { _environmentChoicesOpen = !_environmentChoicesOpen; } GUILayout.EndHorizontal(); EnvMan instance = EnvMan.instance; if (_environmentChoicesOpen && (Object)(object)instance != (Object)null) { _environmentChoicesScroll = GUILayout.BeginScrollView(_environmentChoicesScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(180f) }); if (GUILayout.Button("(Outside weather)", Array.Empty<GUILayoutOption>())) { configEntry.BoxedValue = ""; _environmentChoicesOpen = false; } foreach (EnvSetup environment in instance.m_environments) { if (GUILayout.Button(environment.m_name, Array.Empty<GUILayoutOption>())) { configEntry.BoxedValue = environment.m_name; _environmentChoicesOpen = false; } } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } static HearthBelowPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; HarmonyInstance = null; HearthBelowLogger = Logger.CreateLogSource("HearthBelow"); ConfigSync = new ConfigSync("Azumatt.HearthBelow") { DisplayName = "HearthBelow", CurrentVersion = "0.6.1", MinimumRequiredVersion = "0.6.1", ModRequired = true }; ConfigFile = null; _serverConfigLocked = null; VoxelDigging = null; DigMode = null; DigDepthPerHit = null; CarveRadius = null; CarveShape = null; CaveDepth = null; ToolDepthLimits = null; ToolTierDepthList = null; ToolTierSizeList = null; ExtendToolTierLimits = null; MaxOpsPerZone = null; UndergroundEnvironment = null; UndergroundEnvironmentDepth = null; UndergroundPainting = null; CaveWeatherCover = null; CaveWeatherParticles = null; AllowDigCustomization = null; DropUnsupportedTerrain = null; MaxPlayerCarveRadius = null; RadiusCostScaling = null; DigYieldScaling = null; RemoveModsClearsCaves = null; DigPreview = null; DigPreviewHideRunning = null; DigReadoutTimeout = null; DigReadoutToolName = null; DigPreviewToggleKey = null; DigPreviewFill = null; DigPreviewOutlineColor = null; DigPreviewFillCenterAlpha = null; DigPreviewFillEdgeAlpha = null; DigPreviewImpact = null; DigPreviewImpactSize = null; DigPreviewOutline = null; DigPreviewColor = null; DigPreviewWidth = null; DigControlsModifier = null; DigShapeKey = null; DigModeKey = null; DigSizeStep = null; SavedDigRadius = null; SavedDigShape = null; SavedDigMode = null; } } internal static class ToggleExtensions { internal static bool IsOn(this HearthBelowPlugin.Toggle toggle) { return toggle == HearthBelowPlugin.Toggle.On; } internal static bool IsOff(this HearthBelowPlugin.Toggle toggle) { return toggle == HearthBelowPlugin.Toggle.Off; } internal static bool IsOn(this ConfigEntry<HearthBelowPlugin.Toggle> entry) { return entry.Value == HearthBelowPlugin.Toggle.On; } internal static bool IsOff(this ConfigEntry<HearthBelowPlugin.Toggle> entry) { return entry.Value == HearthBelowPlugin.Toggle.Off; } internal static HearthBelowPlugin.Toggle ToToggle(this bool value) { if (!value) { return HearthBelowPlugin.Toggle.Off; } return HearthBelowPlugin.Toggle.On; } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class RegisterAndCheckVersion { private static void Prefix(ZNetPeer peer, ref ZNet __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown HearthBelowPlugin.HearthBelowLogger.LogDebug((object)"Registering version RPC handler"); peer.m_rpc.Register<ZPackage>("HearthBelow_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_HearthBelow_Version); HearthBelowPlugin.HearthBelowLogger.LogInfo((object)"Invoking version check"); ZPackage val = new ZPackage(); val.Write("0.6.1"); peer.m_rpc.Invoke("HearthBelow_VersionCheck", new object[1] { val }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] public static class VerifyClient { private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance) { if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc)) { return true; } HearthBelowPlugin.HearthBelowLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting")); rpc.Invoke("Error", new object[1] { 3 }); return false; } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] public class ShowConnectionError { private static void Postfix(FejdStartup __instance) { if (__instance.m_connectionFailedPanel.activeSelf) { __instance.m_connectionFailedError.fontSizeMax = 25f; __instance.m_connectionFailedError.fontSizeMin = 15f; TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + HearthBelowPlugin.ConnectionError; } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] public static class RemoveDisconnectedPeerFromVerified { private static void Prefix(ZNetPeer peer, ref ZNet __instance) { if (__instance.IsServer()) { HearthBelowPlugin.HearthBelowLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list")); RpcHandlers.ValidatedPeers.Remove(peer.m_rpc); } } } public static class RpcHandlers { public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); public static void RPC_HearthBelow_Version(ZRpc connection, ZPackage package) { string text = package.ReadString(); HearthBelowPlugin.HearthBelowLogger.LogInfo((object)("Version check, local: 0.6.1, remote: " + text)); if (text != "0.6.1") { HearthBelowPlugin.ConnectionError = "HearthBelow Installed: 0.6.1\n Needed: " + text; if (ZNet.instance.IsServer()) { HearthBelowPlugin.HearthBelowLogger.LogWarning((object)("Peer (" + connection.m_socket.GetHostName() + ") has incompatible version, disconnecting...")); connection.Invoke("Error", new object[1] { 3 }); } } else if (!ZNet.instance.IsServer()) { HearthBelowPlugin.HearthBelowLogger.LogInfo((object)"Received same version from server!"); } else { HearthBelowPlugin.HearthBelowLogger.LogInfo((object)("Adding peer (" + connection.m_socket.GetHostName() + ") to validated list")); ValidatedPeers.Add(connection); } } } } namespace HearthBelow.VoxelMagic { public enum VoxelOpType : byte { Carve, Fill, Flatten, Scoop, Smooth, Raise, Prune } public enum VoxelOpShape : byte { Sphere, Cube, Box } public enum VoxelOpOrigin : byte { Tool, Console } public struct CarveOp { public readonly struct Key : IEquatable<Key> { private readonly int _id; private readonly float _x; private readonly float _y; private readonly float _z; public Key(int id, Vector3 point) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) _id = id; _x = point.x; _y = point.y; _z = point.z; } public bool Equals(Key other) { if (_id == other._id && _x == other._x && _y == other._y) { return _z == other._z; } return false; } public override bool Equals(object? obj) { if (obj is Key other) { return Equals(other); } return false; } public override int GetHashCode() { int num = _id * 397; float x = _x; int num2 = (num ^ x.GetHashCode()) * 397; x = _y; int num3 = (num2 ^ x.GetHashCode()) * 397; x = _z; return num3 ^ x.GetHashCode(); } } public int Id; public long Sequence; public byte Type; public byte Shape; public Vector3 Point; public float Radius; public Vector3 Direction; public float Depth; public float Power; public float FloorHeight; public Key DedupKey => new Key(Id, Point); public bool IsCarve { get { byte type = Type; if (type == 0 || type == 3) { return true; } return false; } } public bool IsCube => Shape == 1; public bool IsBox => Shape == 2; public bool IsPlane { get { byte type = Type; if (type == 2 || (uint)(type - 4) <= 1u) { return true; } return false; } } public float Reach { get { if (Type != 3) { return Radius; } return Mathf.Max(Radius, Depth); } } public void Write(ZPackage package) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) package.Write(Id); package.Write(Sequence); package.Write(Type); package.Write(Shape); package.Write(Point); package.Write(Radius); package.Write(FloorHeight); if (Type == 3) { package.Write(Direction); package.Write(Depth); } else if (IsBox) { package.Write(Direction); } else if (Type == 5) { package.Write(Depth); package.Write(Power); } } public static CarveOp Read(ZPackage package) { return Read(package, 8); } public static CarveOp Read(ZPackage package, int version) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) CarveOp result = new CarveOp { Id = package.ReadInt(), Sequence = ((version >= 7) ? package.ReadLong() : 0), Type = (byte)((version >= 2) ? package.ReadByte() : 0), Shape = (byte)((version >= 3) ? package.ReadByte() : 0), Point = package.ReadVector3(), Radius = package.ReadSingle(), FloorHeight = ((version >= 5) ? package.ReadSingle() : float.NegativeInfinity) }; if (result.Type == 3 && version >= 4) { result.Direction = package.ReadVector3(); result.Depth = package.ReadSingle(); } else if (result.IsBox && version >= 8) { result.Direction = package.ReadVector3(); } else if (result.Type == 5 && version >= 6) { result.Depth = package.ReadSingle(); result.Power = package.ReadSingle(); } return result; } } public enum CarveDataState { Empty, Ok, Unreadable } public static class CarveData { public const int Version = 8; public static readonly int ZdoKey = StringExtensionMethods.GetStableHashCode("HearthBelow_VoxelOps"); private static readonly HashSet<int> WarnedPayloads = new HashSet<int>(); public static byte[] Serialize(List<CarveOp> operations) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(8); val.Write(operations.Count); foreach (CarveOp operation in operations) { operation.Write(val); } return Utils.Compress(val.GetArray()); } public static CarveDataState Read(byte[]? bytes, out List<CarveOp> operations) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown operations = new List<CarveOp>(); if (bytes == null || bytes.Length == 0) { return CarveDataState.Empty; } try { ZPackage val = new ZPackage(Utils.Decompress(bytes)); int num = val.ReadInt(); if (num > 8) { WarnOnce(bytes, $"Voxel data version {num} is newer than this build supports. " + "Leaving this zone's data untouched - digging here is disabled until you run a build that understands it."); return CarveDataState.Unreadable; } int num2 = val.ReadInt(); List<CarveOp> list = new List<CarveOp>(num2); for (int i = 0; i < num2; i++) { list.Add(CarveOp.Read(val, num)); } operations = list; return CarveDataState.Ok; } catch (Exception ex) { WarnOnce(bytes, "Failed to parse voxel data (" + ex.Message + "). Leaving this zone's data untouched."); return CarveDataState.Unreadable; } } private static void WarnOnce(byte[] payload, string message) { int num = payload.Length; for (int i = 0; i < payload.Length; i += 64) { num = num * 31 + payload[i]; } if (WarnedPayloads.Add(num)) { HearthBelowPlugin.HearthBelowLogger.LogWarning((object)message); } } } public static class DistantLod { private const float StripRange = 192f; private static readonly List<Heightmap> LodMaps = new List<Heightmap>(); private static readonly HashSet<Heightmap> Pending = new HashSet<Heightmap>(); private static readonly Dictionary<Heightmap, List<int>> PristineTriangles = new Dictionary<Heightmap, List<int>>(); private static int _lastTickFrame = -1; private static readonly List<Vector3> StripVertices = new List<Vector3>(); private static readonly List<int> KeptTriangles = new List<int>(); private static readonly HashSet<Vector2Int> ActiveZones = new HashSet<Vector2Int>(); private static readonly HashSet<Vector2Int> Stripped = new HashSet<Vector2Int>(); private static readonly HashSet<Vector2Int> Scratch = new HashSet<Vector2Int>(); private static float _lastZoneSize; private static bool _visible = true; public static void Register(Heightmap distantHeightmap) { if (!LodMaps.Contains(distantHeightmap)) { LodMaps.Add(distantHeightmap); } } public static void OnRenderMeshRebuilt(Heightmap distantHeightmap) { Register(distantHeightmap); Mesh renderMesh = distantHeightmap.m_renderMesh; if (!((Object)(object)renderMesh == (Object)null)) { if (!PristineTriangles.TryGetValue(distantHeightmap, out List<int> value)) { value = (PristineTriangles[distantHeightmap] = new List<int>()); } renderMesh.GetTriangles(value, 0); if ((Object)(object)distantHeightmap.m_meshRenderer != (Object)null) { ((Renderer)distantHeightmap.m_meshRenderer).enabled = _visible; } StripUnderActiveZones(distantHeightmap, renderMesh); } } public static void Unregister(Heightmap distantHeightmap) { LodMaps.Remove(distantHeightmap); Pending.Remove(distantHeightmap); PristineTriangles.Remove(distantHeightmap); } public static void SetVisible(bool visible) { _visible = visible; for (int num = LodMaps.Count - 1; num >= 0; num--) { Heightmap val = LodMaps[num]; if ((Object)(object)val == (Object)null) { LodMaps.RemoveAt(num); } else if ((Object)(object)val.m_meshRenderer != (Object)null) { ((Renderer)val.m_meshRenderer).enabled = visible; } } } public static void RefreshAt(Heightmap zoneHeightmap) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)zoneHeightmap == (Object)null)) { QueueOverlapping(((Component)zoneHeightmap).transform.position, (float)zoneHeightmap.m_width * zoneHeightmap.m_scale * 0.5f); } } private static void QueueOverlapping(Vector3 centre, float half) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) for (int num = LodMaps.Count - 1; num >= 0; num--) { Heightmap val = LodMaps[num]; if ((Object)(object)val == (Object)null) { LodMaps.RemoveAt(num); } else { float num2 = (float)val.m_width * val.m_scale * 0.5f; Vector3 position = ((Component)val).transform.position; if (!(Mathf.Abs(centre.x - position.x) > num2 + half) && !(Mathf.Abs(centre.z - position.z) > num2 + half)) { Pending.Add(val); } } } } public static void Tick() { if (_lastTickFrame != Time.frameCount) { _lastTickFrame = Time.frameCount; RefreshEligibility(); FlushPending(); } } private static void RefreshEligibility() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { foreach (Vector2Int item in Stripped) { Vector2Int current = item; QueueOverlapping(new Vector3((float)((Vector2Int)(ref current)).x * _lastZoneSize, 0f, (float)((Vector2Int)(ref current)).y * _lastZoneSize), _lastZoneSize * 0.5f); } Stripped.Clear(); return; } float num = CollectStrippable(Scratch); if (num <= 0f) { num = _lastZoneSize; } if (num <= 0f || Scratch.SetEquals(Stripped)) { return; } foreach (Vector2Int item2 in Scratch) { Vector2Int current2 = item2; if (!Stripped.Contains(current2)) { QueueOverlapping(new Vector3((float)((Vector2Int)(ref current2)).x * num, 0f, (float)((Vector2Int)(ref current2)).y * num), num * 0.5f); } } foreach (Vector2Int item3 in Stripped) { Vector2Int current3 = item3; if (!Scratch.Contains(current3)) { QueueOverlapping(new Vector3((float)((Vector2Int)(ref current3)).x * num, 0f, (float)((Vector2Int)(ref current3)).y * num), num * 0.5f); } } Stripped.Clear(); Stripped.UnionWith(Scratch); } private static float CollectStrippable(HashSet<Vector2Int> into) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) into.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 0f; } Vector3 position = ((Component)localPlayer).transform.position; float result = 0f; foreach (KeyValuePair<Heightmap, VoxelZone> zone in VoxelWorld.Zones) { Heightmap key = zone.Key; if ((Object)(object)key == (Object)null) { continue; } VoxelZone value = zone.Value; if (value == null || !value.IsActive || (!value.HasCarvedGeometry && !value.SurfaceIsModified)) { continue; } float num = (float)key.m_width * key.m_scale; if (!(num <= 0f)) { result = (_lastZoneSize = num); Vector3 position2 = ((Component)key).transform.position; float num2 = num * 0.5f; if (!(Mathf.Abs(position.x - position2.x) > num2 + 192f) && !(Mathf.Abs(position.z - position2.z) > num2 + 192f)) { into.Add(ZoneKey(position2.x, position2.z, num)); } } } return result; } private static void FlushPending() { if (Pending.Count == 0) { return; } foreach (Heightmap item in Pending) { if ((Object)(object)item != (Object)null) { StripUnderActiveZones(item, item.m_renderMesh); } } Pending.Clear(); } public static bool StripUnderActiveZones(Heightmap distantHeightmap, Mesh? mesh) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)distantHeightmap == (Object)null || (Object)(object)mesh == (Object)null) { return false; } if (!PristineTriangles.TryGetValue(distantHeightmap, out List<int> value)) { value = (PristineTriangles[distantHeightmap] = new List<int>()); mesh.GetTriangles(value, 0); } if (value.Count == 0) { return false; } float num = CollectStrippable(ActiveZones); if (ActiveZones.Count == 0 || num <= 0f) { if (mesh.GetIndexCount(0) == (uint)value.Count) { return false; } mesh.SetTriangles(value, 0); return true; } StripVertices.Clear(); mesh.GetVertices(StripVertices); Transform transform = ((Component)distantHeightmap).transform; KeptTriangles.Clear(); for (int i = 0; i + 2 < value.Count; i += 3) { Vector3 val = (StripVertices[value[i]] + StripVertices[value[i + 1]] + StripVertices[value[i + 2]]) / 3f; Vector3 val2 = transform.TransformPoint(val); if (!ActiveZones.Contains(ZoneKey(val2.x, val2.z, num))) { KeptTriangles.Add(value[i]); KeptTriangles.Add(value[i + 1]); KeptTriangles.Add(value[i + 2]); } } if (KeptTriangles.Count == value.Count && mesh.GetIndexCount(0) == (uint)value.Count) { return false; } mesh.SetTriangles(KeptTriangles, 0); return true; } private static Vector2Int ZoneKey(float worldX, float worldZ, float zoneSize) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) return new Vector2Int(Mathf.FloorToInt(worldX / zoneSize + 0.5f), Mathf.FloorToInt(worldZ / zoneSize + 0.5f)); } } public static class MeshRectClipper { private struct ClipVertex { public Vector3 Position; public Vector3 Normal; public Vector2 TextureCoordinates; public Color32 Color; } private readonly struct VertexKey : IEquatable<VertexKey> { private readonly Vector3 _position; private readonly Vector3 _normal; private readonly Vector2 _textureCoordinates; public VertexKey(ClipVertex vertex) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) _position = vertex.Position; _normal = vertex.Normal; _textureCoordinates = vertex.TextureCoordinates; } public bool Equals(VertexKey other) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Vector3 val = _position; if (((Vector3)(ref val)).Equals(other._position)) { val = _normal; if (((Vector3)(ref val)).Equals(other._normal)) { Vector2 textureCoordinates = _textureCoordinates; return ((Vector2)(ref textureCoordinates)).Equals(other._textureCoordinates); } } return false; } public override bool Equals(object? obj) { if (obj is VertexKey other) { return Equals(other); } return false; } public override int GetHashCode() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) return (((((object)_position/*cast due to .constrained prefix*/).GetHashCode() * 397) ^ ((object)_normal/*cast due to .constrained prefix*/).GetHashCode()) * 397) ^ ((object)_textureCoordinates/*cast due to .constrained prefix*/).GetHashCode(); } } private const int MaxPolygonVertices = 12; private static readonly ClipVertex[] PrimaryPolygonBuffer = new ClipVertex[12]; private static readonly ClipVertex[] SecondaryPolygonBuffer = new ClipVertex[12]; private static readonly List<Vector3> OutputVertices = new List<Vector3>(); private static readonly List<Vector3> OutputNormals = new List<Vector3>(); private static readonly List<Vector2> OutputTextureCoordinates = new List<Vector2>(); private static readonly List<Color32> OutputColors = new List<Color32>(); private static readonly List<int> OutputTriangles = new List<int>(); private static readonly Dictionary<VertexKey, int> VertexIndices = new Dictionary<VertexKey, int>(); public static void Clip(List<Vector3> vertices, List<Vector3> normals, List<Vector2> textureCoordinates, List<Color32> colors, List<int> triangles, float minX, float maxX, float minZ, float maxZ) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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) OutputVertices.Clear(); OutputNormals.Clear(); OutputTextureCoordinates.Clear(); OutputColors.Clear(); OutputTriangles.Clear(); VertexIndices.Clear(); for (int i = 0; i + 2 < triangles.Count; i += 3) { ClipVertex[] first = PrimaryPolygonBuffer; ClipVertex[] second = SecondaryPolygonBuffer; int count = 3; for (int j = 0; j < 3; j++) { int index = triangles[i + j]; first[j] = new ClipVertex { Position = vertices[index], Normal = normals[index], TextureCoordinates = textureCoordinates[index], Color = colors[index] }; } count = ClipPlane(first, count, second, axisX: true, minX, keepGreater: true); Swap(ref first, ref second); count = ClipPlane(first, count, second, axisX: true, maxX, keepGreater: false); Swap(ref first, ref second); count = ClipPlane(first, count, second, axisX: false, minZ, keepGreater: true); Swap(ref first, ref second); count = ClipPlane(first, count, second, axisX: false, maxZ, keepGreater: false); Swap(ref first, ref second); if (count >= 3 && !CoplanarWithMin(first, count, minX, minZ)) { for (int k = 1; k + 1 < count; k++) { Emit(first[0], first[k], first[k + 1]); } } } vertices.Clear(); vertices.AddRange(OutputVertices); normals.Clear(); normals.AddRange(OutputNormals); textureCoordinates.Clear(); textureCoordinates.AddRange(OutputTextureCoordinates); colors.Clear(); colors.AddRange(OutputColors); triangles.Clear(); triangles.AddRange(OutputTriangles); } private static int ClipPlane(ClipVertex[] input, int count, ClipVertex[] output, bool axisX, float bound, bool keepGreater) { if (count == 0) { return 0; } int num = 0; ClipVertex clipVertex = input[count - 1]; bool flag = Inside(clipVertex, axisX, bound, keepGreater); for (int i = 0; i < count; i++) { ClipVertex clipVertex2 = input[i]; bool num2 = Inside(clipVertex2, axisX, bound, keepGreater); if (num2 != flag && num < 12) { output[num++] = Intersect(clipVertex, clipVertex2, axisX, bound); } if (num2 && num < 12) { output[num++] = clipVertex2; } clipVertex = clipVertex2; flag = num2; } return num; } private static bool Inside(ClipVertex vertex, bool axisX, float bound, bool keepGreater) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) float num = (axisX ? vertex.Position.x : vertex.Position.z); if (!keepGreater) { return num <= bound; } return num >= bound; } private static ClipVertex Intersect(ClipVertex firstVertex, ClipVertex secondVertex, bool axisX, float bound) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) float num = (axisX ? firstVertex.Position.x : firstVertex.Position.z); float num2 = (axisX ? secondVertex.Position.x : secondVertex.Position.z); ClipVertex clipVertex = ((num <= num2) ? firstVertex : secondVertex); ClipVertex clipVertex2 = ((num <= num2) ? secondVertex : firstVertex); float num3 = Mathf.Min(num, num2); float num4 = Mathf.Max(num, num2); float num5 = ((num4 - num3 > 1E-09f) ? ((bound - num3) / (num4 - num3)) : 0f); Vector3 position = Vector3.Lerp(clipVertex.Position, clipVertex2.Position, num5); if (axisX) { position.x = bound; } else { position.z = bound; } return new ClipVertex { Position = position, Normal = Vector3.Slerp(clipVertex.Normal, clipVertex2.Normal, num5), TextureCoordinates = Vector2.Lerp(clipVertex.TextureCoordinates, clipVertex2.TextureCoordinates, num5), Color = Color32.Lerp(clipVertex.Color, clipVertex2.Color, num5) }; } private static bool CoplanarWithMin(ClipVertex[] polygon, int count, float minX, float minZ) { bool flag = true; bool flag2 = true; for (int i = 0; i < count; i++) { flag &= polygon[i].Position.x == minX; flag2 &= polygon[i].Position.z == minZ; } return flag || flag2; } private static void Emit(ClipVertex firstVertex, ClipVertex secondVertex, ClipVertex thirdVertex) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Cross(secondVertex.Position - firstVertex.Position, thirdVertex.Position - firstVertex.Position); if (!(((Vector3)(ref val)).sqrMagnitude < 1E-10f)) { OutputTriangles.Add(Add(firstVertex)); OutputTriangles.Add(Add(secondVertex)); OutputTriangles.Add(Add(thirdVertex)); } } private static int Add(ClipVertex vertex) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) VertexKey key = new VertexKey(vertex); if (VertexIndices.TryGetValue(key, out var value)) { return value; } int count = OutputVertices.Count; OutputVertices.Add(vertex.Position); OutputNormals.Add(vertex.Normal); OutputTextureCoordinates.Add(vertex.TextureCoordinates); OutputColors.Add(vertex.Color); VertexIndices.Add(key, count); return count; } private static void Swap(ref ClipVertex[] first, ref ClipVertex[] second) { ClipVertex[] array = second; ClipVertex[] array2 = first; first = array; second = array2; } } public static class MineRockSupport { private const float Margin = 4f; private static readonly Collider[] Hits = (Collider[])(object)new Collider[128]; private static readonly HashSet<MineRock5> Seen = new HashSet<MineRock5>(); private static int _mask; private static Vector3 _lastPoint; private static int _lastFrame = -1; internal static int RockMask => Mask; private static int Mask { get { if (_mask == 0) { return _mask = LayerMask.GetMask(new string[4] { "piece", "Default", "static_solid", "Default_small" }); } return _mask; } } public static void ShakeLoose(Vector3 point, float radius) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (_lastFrame == Time.frameCount) { Vector3 val = point - _lastPoint; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return; } } _lastFrame = Time.frameCount; _lastPoint = point; int num = Physics.OverlapSphereNonAlloc(point, radius + 4f, Hits, Mask, (QueryTriggerInteraction)1); if (num <= 0) { return; } Seen.Clear(); for (int i = 0; i < num; i++) { Collider val2 = Hits[i]; if (!((Object)(object)val2 == (Object)null)) { MineRock5 componentInParent = ((Component)val2).GetComponentInParent<MineRock5>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.m_supportCheck && Seen.Add(componentInParent)) { componentInParent.CheckSupport(); } } } Seen.Clear(); } } public static class Rescue { public const float CharacterProbeUp = 1f; public const float CharacterHeadroom = 1.5f; public const float ItemProbeUp = 0.3f; public const float ItemHeadroom = 0.5f; public static bool IsNoClipping(Character? character) { if ((Object)(object)character != (Object)null && character.IsPlayer() && character.IsDebugFlying() && (Object)(object)character.m_collider != (Object)null) { return !((Collider)character.m_collider).enabled; } return false; } public static void PlaceAt(Transform transform, Rigidbody? body, Vector3 target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) transform.position = target; if (!((Object)(object)body == (Object)null)) { body.position = target; body.linearVelocity = Vector3.zero; } } public static void PlaceAt(Character character, Vector3 target) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) PlaceAt(((Component)character).transform, character.m_body, target); character.m_maxAirAltitude = target.y; } public static bool TryUnbury(ZNetView? networkView, Transform transform, Rigidbody? body, float probeUp, float headroom) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)networkView == (Object)null || !networkView.IsValid() || !networkView.IsOwner()) { return false; } if (!VoxelWorld.TryRelocateOutOfSolid(transform.position, probeUp, headroom, out var target)) { return false; } PlaceAt(transform, body, target); return true; } public static bool HandleTerrainCheck(Transform transform, Rigidbody? body, float probeUp, float headroom) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) Vector3 position = transform.position; float num = default(float); if (!Heightmap.GetHeight(position, ref num) || position.y >= num - 0.35f) { return false; } if (VoxelWorld.IsGroundPendingAt(position)) { return true; } if (!VoxelWorld.TrySampleSolid(position + Vector3.up * probeUp, out var solid)) { return false; } if (!solid) { return true; } if (!VoxelWorld.TryRelocateOutOfSolid(position, probeUp, headroom, out var target)) { return false; } PlaceAt(transform, body, target); return true; } public static void EjectBuried(Vector3 point, float range) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter.m_nview == (Object)null || !allCharacter.m_nview.IsValid() || !allCharacter.m_nview.IsOwner() || IsNoClipping(allCharacter)) { continue; } Vector3 position = ((Component)allCharacter).transform.position; if (!(Utils.DistanceXZ(position, point) > range)) { VoxelZone activeZoneAt = VoxelWorld.GetActiveZoneAt(position); if (activeZoneAt != null && activeZoneAt.TryLiftOutOfSolid(position, 1f, 1.5f, out var target)) { PlaceAt(allCharacter, target); } } } } } public static class SurfaceNets { private const float PristineBorderSink = 0.03f; private const float CarvedBorderSink = 0.05f; private const float CeilingNormalY = -0.55f; private static readonly float CeilingNormalXZ = Mathf.Sqrt(0.6975f); private static readonly List<Vector3> Vertices = new List<Vector3>(); private static readonly List<Vector3> Normals = new List<Vector3>(); private static readonly List<Color32> Colors = new List<Color32>(); private static readonly List<Vector2> TextureCoordinates = new List<Vector2>(); private static readonly List<int> Triangles = new List<int>(); private static int[] _cellVertices = Array.Empty<int>(); private static Vector3Int _cellMinimum; private static Vector3Int _cellMaximum; private static int _sizeX; private static int _sizeZ; private static readonly float[] CornerDensities = new float[8]; private static readonly int[,] CornerOffset = new int[8, 3] { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 1, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 0, 1, 1 }, { 1, 1, 1 } }; private static readonly int[,] CellEdges = new int[12, 2] { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 0, 2 }, { 1, 3 }, { 4, 6 }, { 5, 7 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } }; private static bool _allPristine; public static bool Build(VoxelZone zone, Vector3Int sampleMin, Vector3Int sampleMax, bool allPristine, out List<Vector3> vertices, out List<Vector3> normals, out List<Color32> colors, out List<Vector2> uvs, out List<int> triangles) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) _allPristine = allPristine; vertices = Vertices; normals = Normals; colors = Colors; uvs = TextureCoordinates; triangles = Triangles; Vertices.Clear(); Normals.Clear(); Colors.Clear(); TextureCoordinates.Clear(); Triangles.Clear(); if (((Vector3Int)(ref sampleMin)).x >= ((Vector3Int)(ref sampleMax)).x || ((Vector3Int)(ref sampleMin)).y >= ((Vector3Int)(ref sampleMax)).y || ((Vector3Int)(ref sampleMin)).z >= ((Vector3Int)(ref sampleMax)).z) { return false; } _cellMinimum = new Vector3Int(Mathf.Max(0, ((Vector3Int)(ref sampleMin)).x - 1), Mathf.Max(0, ((Vector3Int)(ref sampleMin)).y - 1), Mathf.Max(0, ((Vector3Int)(ref sampleMin)).z - 1)); _cellMaximum = new Vector3Int(Mathf.Min(zone.NX - 2, ((Vector3Int)(ref sampleMax)).x - 1), Mathf.Min(zone.NY - 2, ((Vector3Int)(ref sampleMax)).y - 1), Mathf.Min(zone.NZ - 2, ((Vector3Int)(ref sampleMax)).z - 1)); _sizeX = ((Vector3Int)(ref _cellMaximum)).x - ((Vector3Int)(ref _cellMinimum)).x + 1; _sizeZ = ((Vector3Int)(ref _cellMaximum)).z - ((Vector3Int)(ref _cellMinimum)).z + 1; int num = _sizeX * (((Vector3Int)(ref _cellMaximum)).y - ((Vector3Int)(ref _cellMinimum)).y + 1) * _sizeZ; if (_cellVertices.Length < num) { _cellVertices = new int[num]; } for (int i = 0; i < num; i++) { _cellVertices[i] = -1; } PlaceVertices(zone); if (Vertices.Count == 0) { return false; } EmitQuads(zone, sampleMin, sampleMax); return Triangles.Count > 0; } private static void PlaceVertices(VoxelZone zone) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01db: 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_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = default(Vector3); for (int i = ((Vector3Int)(ref _cellMinimum)).y; i <= ((Vector3Int)(ref _cellMaximum)).y; i++) { for (int j = ((Vector3Int)(ref _cellMinimum)).z; j <= ((Vector3Int)(ref _cellMaximum)).z; j++) { for (int k = ((Vector3Int)(ref _cellMinimum)).x; k <= ((Vector3Int)(ref _cellMaximum)).x; k++) { float[] cornerDensities = CornerDensities; int num = 0; for (int l = 0; l < 8; l++) { cornerDensities[l] = zone.D(k + CornerOffset[l, 0], i + CornerOffset[l, 1], j + CornerOffset[l, 2]); if (cornerDensities[l] > 0f) { num |= 1 << l; } } if (num != 0 && num != 255) { Vector3 val = AverageEdgeCrossing(cornerDensities) + new Vector3((float)k, (float)i, (float)j); ((Vector3)(ref val2))..ctor(val.x * zone.HorizontalSpacing, val.y * 1f, val.z * zone.HorizontalSpacing); bool flag = _allPristine || zone.IsPristineCell(k, i, j); if (flag && zone.TryVanillaSurfaceHeight(zone.Origin.x + val2.x, zone.Origin.z + val2.z, out var height)) { val2.y = height - zone.Origin.y; } if ((k == 0 && !zone.HasNeighborNX) || (k == zone.NX - 2 && !zone.HasNeighborPX) || (j == 0 && !zone.HasNeighborNZ) || (j == zone.NZ - 2 && !zone.HasNeighborPZ)) { val2.y -= (flag ? 0.03f : 0.05f); } zone.GetSurfaceAttributes(zone.Origin + val2, out var textureCoordinates, out var surfaceColor); _cellVertices[CellIndex(k, i, j)] = Vertices.Count; Vertices.Add(val2); Normals.Add(CellNormal(zone, cornerDensities)); Colors.Add(surfaceColor); TextureCoordinates.Add(textureCoordinates); } } } } } private static Vector3 AverageEdgeCrossing(float[] cornerDensities) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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) Vector3 val = Vector3.zero; int num = 0; for (int i = 0; i < 12; i++) { int num2 = CellEdges[i, 0]; int num3 = CellEdges[i, 1]; if (cornerDensities[num2] > 0f != cornerDensities[num3] > 0f) { float num4 = cornerDensities[num2] / (cornerDensities[num2] - cornerDensities[num3]); val += new Vector3((float)CornerOffset[num2, 0] + num4 * (float)(CornerOffset[num3, 0] - CornerOffset[num2, 0]), (float)CornerOffset[num2, 1] + num4 * (float)(CornerOffset[num3, 1] - CornerOffset[num2, 1]), (float)CornerOffset[num2, 2] + num4 * (float)(CornerOffset[num3, 2] - CornerOffset[num2, 2])); num++; } } return val / (float)num; } private static Vector3 CellNormal(VoxelZone zone, float[] cornerDensities) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_009e: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) float num = (cornerDensities[1] + cornerDensities[3] + cornerDensities[5] + cornerDensities[7] - cornerDensities[0] - cornerDensiti