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 BuildPiecesCustomized v1.3.0
BuildPiecesCustomized.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using ConditionalConfigSync; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using YamlDotNet.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Build Pieces Customized")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Build Pieces Customized")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("448a53ac-6a9d-47e7-b934-d6ee2b13e7b2")] [assembly: AssemblyFileVersion("1.3.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace BuildPiecesCustomized { [BepInPlugin("shudnal.BuildPiecesCustomized", "Build Pieces Customized", "1.3.0")] [BepInDependency("_shudnal.ConditionalConfigSync", "1.0.5")] [BepInIncompatibility("aedenthorn.BuildPieceTweaks")] [BepInIncompatibility("TheSxW_EditMaterialProperties")] [BepInIncompatibility("lime.plugins.foreverbuild")] [BepInIncompatibility("bonesbro.val.floorsareroofs")] public class BuildPiecesCustomized : BaseUnityPlugin { internal class MaterialPropertiesConfig { public ConfigEntry<float> maxSupport; public ConfigEntry<float> minSupport; public ConfigEntry<float> verticalLoss; public ConfigEntry<float> horizontalLoss; } [HarmonyPatch(typeof(ZoneSystem), "OnDestroy")] private static class ZoneSystem_OnDestroy_PiecesWntCache { private static void Postfix() { if (modEnabled.Value) { piecesWntComponent.Clear(); } } } [HarmonyPatch(typeof(Piece), "Awake")] private static class Piece_Awake_PiecesWntCache { private static void Prefix(Piece __instance) { if (modEnabled.Value) { piecesWntComponent[__instance] = ((Component)__instance).GetComponent<WearNTear>(); } } } [HarmonyPatch(typeof(Piece), "OnDestroy")] private static class Piece_OnDestroy_PiecesWntCache { private static void Prefix(Piece __instance) { if (modEnabled.Value) { piecesWntComponent.Remove(__instance); } } } [HarmonyPatch(typeof(ZoneSystem), "Start")] private static class ZoneSystem_Start_PiecesConfigWatcher { [HarmonyPriority(0)] private static void Postfix() { if (modEnabled.Value) { SetupConfigWatcher(); } } } [HarmonyPatch(typeof(WearNTear), "GetMaterialProperties")] private static class WearNTear_GetMaterialProperties_MaterialProperties { private static void Postfix(WearNTear __instance, ref float maxSupport, ref float minSupport, ref float horizontalLoss, ref float verticalLoss) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (modEnabled.Value && materialConfigs.ContainsKey(__instance.m_materialType)) { maxSupport *= materialConfigs[__instance.m_materialType].maxSupport.Value; minSupport *= materialConfigs[__instance.m_materialType].minSupport.Value; horizontalLoss /= materialConfigs[__instance.m_materialType].horizontalLoss.Value; verticalLoss /= materialConfigs[__instance.m_materialType].verticalLoss.Value; } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static EventHandler <>9__39_0; public static EventHandler <>9__39_1; public static EventHandler <>9__39_2; public static EventHandler <>9__39_3; public static EventHandler <>9__39_4; public static EventHandler <>9__39_5; public static EventHandler <>9__39_6; public static EventHandler <>9__39_7; public static EventHandler <>9__39_8; public static EventHandler <>9__39_9; public static EventHandler <>9__39_10; public static EventHandler <>9__39_11; public static ConsoleEvent <>9__42_0; public static Func<GameObject, string> <>9__42_6; public static ConsoleOptionsFetcher <>9__42_1; public static ConsoleEvent <>9__42_2; public static Func<GameObject, string> <>9__42_7; public static ConsoleOptionsFetcher <>9__42_3; public static ConsoleEvent <>9__42_4; public static Func<FileInfo, string> <>9__45_0; internal void <ConfigInit>b__39_0(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_1(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_2(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_3(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_4(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_5(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_6(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_7(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_8(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_9(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_10(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <ConfigInit>b__39_11(object s, EventArgs e) { PiecePatches.UpdatePiecesProperties(); } internal void <InitCommands>b__42_0(ConsoleEventArgs args) { bool flag = args.Length >= 2; string value = (flag ? args.FullLine.Substring(args[0].Length + 1) : ""); foreach (GameObject buildPiece in CustomPieceData.GetBuildPieces()) { CustomPieceData byPieceName = CustomPieceData.GetByPieceName(((Object)buildPiece).name); if (byPieceName != null && (!flag || byPieceName.prefabName.IndexOf(value) != -1 || Regex.IsMatch(byPieceName.prefabName, <InitCommands>g__WildCardToRegular|42_5(value)))) { byPieceName.SaveToDirectory(configDirectory.FullName); Terminal context = args.Context; if (context != null) { context.AddString("Saved " + byPieceName.prefabName + " file to config directory"); } } } } internal List<string> <InitCommands>b__42_1() { return (from piece in CustomPieceData.GetBuildPieces() select ((Object)piece).name).ToList(); } internal string <InitCommands>b__42_6(GameObject piece) { return ((Object)piece).name; } internal void <InitCommands>b__42_2(ConsoleEventArgs args) { if (args.Length < 2) { return; } string text = args.FullLine.Substring(args[0].Length + 1); CustomPieceData byPieceName = CustomPieceData.GetByPieceName(text); if (byPieceName == null) { Terminal context = args.Context; if (context != null) { context.AddString("Piece with name " + text + " was not found"); } return; } byPieceName.SaveToDirectory(configDirectory.FullName); Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Saved " + text + " file to config directory"); } } internal List<string> <InitCommands>b__42_3() { return (from piece in CustomPieceData.GetBuildPieces() select ((Object)piece).name).ToList(); } internal string <InitCommands>b__42_7(GameObject piece) { return ((Object)piece).name; } internal void <InitCommands>b__42_4(ConsoleEventArgs args) { DocGen.GenerateDocumentationFile(); } internal string <GetConfigFiles>b__45_0(FileInfo file) { return file.FullName; } } public const string pluginID = "shudnal.BuildPiecesCustomized"; public const string pluginName = "Build Pieces Customized"; public const string pluginVersion = "1.3.0"; private readonly Harmony harmony = new Harmony("shudnal.BuildPiecesCustomized"); internal static readonly ConfigSync configSync = new ConfigSync("shudnal.BuildPiecesCustomized") { DisplayName = "Build Pieces Customized", CurrentVersion = "1.3.0", MinimumRequiredVersion = "1.3.0" }; internal static ConfigEntry<bool> modEnabled; internal static ConfigEntry<bool> configLocked; internal static ConfigEntry<bool> loggingEnabled; internal static ConfigEntry<bool> saveAsYAML; internal static ConfigEntry<string> toolsToPatchPieces; internal static ConfigEntry<string> prefabListClipEverything; internal static ConfigEntry<string> prefabListAllowedInDungeons; internal static ConfigEntry<string> prefabListRepairPiece; internal static ConfigEntry<string> prefabListCanBeRemoved; internal static ConfigEntry<string> prefabListIsRoof; internal static ConfigEntry<string> prefabListIsLeaky; internal static ConfigEntry<string> prefabListDisabled; internal static ConfigEntry<string> prefabListAshDamageImmune; internal static ConfigEntry<string> prefabListSnowDamageImmune; internal static ConfigEntry<string> prefabListNoRoofWear; internal static ConfigEntry<string> prefabListNoSupportWear; internal static readonly Dictionary<MaterialType, MaterialPropertiesConfig> materialConfigs = new Dictionary<MaterialType, MaterialPropertiesConfig>(); internal static BuildPiecesCustomized instance; internal static readonly CustomSyncedValue<Dictionary<string, string>> configsJSON = new CustomSyncedValue<Dictionary<string, string>>((ConditionalConfigSync)(object)configSync, "JSON configs", new Dictionary<string, string>(), 0, (IEqualityComparer<Dictionary<string, string>>)null); internal static readonly Dictionary<string, CustomPieceData> pieceData = new Dictionary<string, CustomPieceData>(); internal static readonly Dictionary<string, CraftingStation> craftingStations = new Dictionary<string, CraftingStation>(); internal static readonly Dictionary<string, CustomPieceData> defaultPieceData = new Dictionary<string, CustomPieceData>(); internal static DirectoryInfo pluginDirectory; internal static DirectoryInfo configDirectory; private static FileSystemWatcher fileSystemWatcherPlugin; private static FileSystemWatcher fileSystemWatcherConfig; internal static readonly IDeserializer YamlDeserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().Build(); internal static readonly ISerializer YamlSerializer = new SerializerBuilder().Build(); internal static readonly Dictionary<Piece, WearNTear> piecesWntComponent = new Dictionary<Piece, WearNTear>(); private void Awake() { instance = this; pluginDirectory = new DirectoryInfo(Assembly.GetExecutingAssembly().Location).Parent; configDirectory = new DirectoryInfo(Path.Combine(Paths.ConfigPath, "shudnal.BuildPiecesCustomized")); ConfigInit(); PiecePatches.GlobalPatches.UpdateProperties(); ((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(configLocked); ((CustomSyncedValueBase)configsJSON).ValueChanged += LoadConfigs; harmony.PatchAll(); Game.isModded = true; } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } instance = null; } public static void LogInfo(object data) { if (loggingEnabled.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo(data); } } public static void LogWarning(object data) { ((BaseUnityPlugin)instance).Logger.LogWarning(data); } private ConfigDescription GetDescriptionSeparatedStrings(string description) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown return Chainloader.PluginInfos.ContainsKey("_shudnal.ConfigurationManager") ? new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()) : new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new CustomConfigs.ConfigurationManagerAttributes { CustomDrawer = CustomConfigs.DrawSeparatedStrings(",") } }); } public void ConfigInit() { //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) modEnabled = config("General", "Enabled", defaultValue: true, "Enable the mod."); configLocked = config("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only."); loggingEnabled = config("General", "Logging enabled", defaultValue: false, "Enable logging. [Not Synced with Server]", synchronizedSetting: false); saveAsYAML = config("General", "Save piece data as YAML", defaultValue: false, "Save piece data in YAML format. [Not Synced with Server]", synchronizedSetting: false); toolsToPatchPieces = config("General", "Tools list", "Hammer,Hoe,Cultivator", "Comma-separated list of tool prefab name to get build pieces from"); toolsToPatchPieces.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListClipEverything = config("List - Global setting", "Clip everything", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will clip through each other. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListAllowedInDungeons = config("List - Global setting", "Allow in dungeons", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be allowed to build in dungeons. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListRepairPiece = config("List - Global setting", "Can be repaired", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be repairable. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListCanBeRemoved = config("List - Global setting", "Can be removed", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be removeable. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListDisabled = config("List - Global setting", "Disabled pieces", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be disabled.")); prefabListIsRoof = config("List - Global setting", "Is Roof", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will work as a roof. Set \"AllPieces\" identifier to apply for all pieces.\nLeaky -> Roof transition will be applied immediately. \nRestart the game if you need Roof -> Leaky transition of updated pieces.")); prefabListIsLeaky = config("List - Global setting", "Is Leaky", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will not work as a roof. Set \"AllPieces\" identifier to apply for all pieces.\nRoof -> Leaky transition will be applied immediately. \nRestart the game if you need Leaky -> Roof transition of updated pieces.")); prefabListClipEverything.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListAllowedInDungeons.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListRepairPiece.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListCanBeRemoved.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListDisabled.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListIsRoof.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListIsLeaky.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListAshDamageImmune = config("List - Immune to", "Ash and lava", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be immune to ash and lava damage. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListSnowDamageImmune = config("List - Immune to", "Heavy snow", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be immune to heavy snow damage. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListNoRoofWear = config("List - Immune to", "Water damage", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will be immune to water damage. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListNoSupportWear = config("List - Immune to", "Structural integrity", "", GetDescriptionSeparatedStrings("Comma-separated list of pieces that will not be needed support. Set \"AllPieces\" identifier to apply for all pieces.")); prefabListAshDamageImmune.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListSnowDamageImmune.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListNoRoofWear.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; prefabListNoSupportWear.SettingChanged += delegate { PiecePatches.UpdatePiecesProperties(); }; foreach (MaterialType value in Enum.GetValues(typeof(MaterialType))) { materialConfigs.Add(value, new MaterialPropertiesConfig { maxSupport = config($"Material - {(object)value}", "Max support multiplier", 1f, "Multiplier of maximum support value material can provide."), minSupport = config($"Material - {(object)value}", "Min support multiplier", 1f, "Multiplier of minimum support value material can provide."), verticalLoss = config($"Material - {(object)value}", "Vertical stability multiplier", 1f, "Multiplier of vertical support value. Increase to be able to build higher."), horizontalLoss = config($"Material - {(object)value}", "Horizontal stability multiplier", 1f, "Multiplier of horizontal support value. Increase to be able to build longer hanging beams.") }); } InitCommands(); } private ConfigEntry<T> config<T>(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultValue, description); ((ConditionalConfigSync)configSync).AddConfigEntry<T>(val, (ConfigSyncMode)1, synchronizedSetting); return val; } private ConfigEntry<T> config<T>(string group, string name, T defaultValue, 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, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } public static void InitCommands() { //IL_002e: 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_0039: Expected O, but got Unknown //IL_0061: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00c7: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown string text = "[Prefab partial name or wildcard *] - save data of ALL pieces into JSON files to config directory " + configDirectory.Name; object obj = <>c.<>9__42_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { bool flag = args.Length >= 2; string value = (flag ? args.FullLine.Substring(args[0].Length + 1) : ""); foreach (GameObject buildPiece in CustomPieceData.GetBuildPieces()) { CustomPieceData byPieceName = CustomPieceData.GetByPieceName(((Object)buildPiece).name); if (byPieceName != null && (!flag || byPieceName.prefabName.IndexOf(value) != -1 || Regex.IsMatch(byPieceName.prefabName, WildCardToRegular(value)))) { byPieceName.SaveToDirectory(configDirectory.FullName); Terminal context = args.Context; if (context != null) { context.AddString("Saved " + byPieceName.prefabName + " file to config directory"); } } } }; <>c.<>9__42_0 = val; obj = (object)val; } object obj2 = <>c.<>9__42_1; if (obj2 == null) { ConsoleOptionsFetcher val2 = () => (from piece in CustomPieceData.GetBuildPieces() select ((Object)piece).name).ToList(); <>c.<>9__42_1 = val2; obj2 = (object)val2; } new ConsoleCommand("bpcsaveall", text, (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false); string text2 = "[Prefab name] - save piece data into JSON file to config directory " + configDirectory.Name; object obj3 = <>c.<>9__42_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { if (args.Length >= 2) { string text3 = args.FullLine.Substring(args[0].Length + 1); CustomPieceData byPieceName = CustomPieceData.GetByPieceName(text3); if (byPieceName == null) { Terminal context = args.Context; if (context != null) { context.AddString("Piece with name " + text3 + " was not found"); } } else { byPieceName.SaveToDirectory(configDirectory.FullName); Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Saved " + text3 + " file to config directory"); } } } }; <>c.<>9__42_2 = val3; obj3 = (object)val3; } object obj4 = <>c.<>9__42_3; if (obj4 == null) { ConsoleOptionsFetcher val4 = () => (from piece in CustomPieceData.GetBuildPieces() select ((Object)piece).name).ToList(); <>c.<>9__42_3 = val4; obj4 = (object)val4; } new ConsoleCommand("bpcsave", text2, (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)obj4, false, false, false); object obj5 = <>c.<>9__42_4; if (obj5 == null) { ConsoleEvent val5 = delegate { DocGen.GenerateDocumentationFile(); }; <>c.<>9__42_4 = val5; obj5 = (object)val5; } new ConsoleCommand("bpcdocs", "Save documentation file Pieces and properties.md to config directory", (ConsoleEvent)obj5, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); static string WildCardToRegular(string value) { return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$"; } } public static void SetupConfigWatcher() { if (fileSystemWatcherPlugin == null) { fileSystemWatcherPlugin = new FileSystemWatcher(pluginDirectory.FullName, "*.*"); fileSystemWatcherPlugin.Changed += ReadConfigs; fileSystemWatcherPlugin.Created += ReadConfigs; fileSystemWatcherPlugin.Renamed += ReadConfigs; fileSystemWatcherPlugin.Deleted += ReadConfigs; fileSystemWatcherPlugin.IncludeSubdirectories = true; fileSystemWatcherPlugin.SynchronizingObject = ThreadingHelper.SynchronizingObject; } fileSystemWatcherPlugin.EnableRaisingEvents = modEnabled.Value; if (fileSystemWatcherConfig == null && configDirectory.Exists) { fileSystemWatcherConfig = new FileSystemWatcher(configDirectory.FullName, "*.*"); fileSystemWatcherConfig.Changed += ReadConfigs; fileSystemWatcherConfig.Created += ReadConfigs; fileSystemWatcherConfig.Renamed += ReadConfigs; fileSystemWatcherConfig.Deleted += ReadConfigs; fileSystemWatcherConfig.IncludeSubdirectories = true; fileSystemWatcherConfig.SynchronizingObject = ThreadingHelper.SynchronizingObject; } if (fileSystemWatcherConfig != null) { fileSystemWatcherConfig.EnableRaisingEvents = modEnabled.Value; } ReadConfigs(null, null); } private static void ReadConfigs(object sender, FileSystemEventArgs eargs) { Dictionary<string, CustomPieceData> dictionary = new Dictionary<string, CustomPieceData>(StringComparer.OrdinalIgnoreCase); PieceUsageTags.ConfigFile configFile = null; List<FileInfo> list = new List<FileInfo>(); if (pluginDirectory.Exists) { list.AddRange(GetConfigFiles(pluginDirectory)); } if (configDirectory.Exists) { list.AddRange(GetConfigFiles(configDirectory)); } foreach (FileInfo item in list) { if (string.Equals(item.Name, "manifest.json", StringComparison.OrdinalIgnoreCase)) { continue; } LogInfo("Found " + item.FullName); try { string text; using (FileStream stream = new FileStream(item.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using StreamReader streamReader = new StreamReader(stream); text = streamReader.ReadToEnd(); } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item.Name); bool flag = string.Equals(item.Extension, ".json", StringComparison.OrdinalIgnoreCase); if (string.Equals(fileNameWithoutExtension, "Piece categories", StringComparison.OrdinalIgnoreCase)) { LogWarning("Ignoring obsolete piece category configuration file '" + item.FullName + "'. Use 'Piece usage tags.yaml' or JSON instead."); } else if (string.Equals(fileNameWithoutExtension, "Piece usage tags", StringComparison.OrdinalIgnoreCase)) { if (configFile != null) { LogWarning("Multiple 'Piece usage tags' files found. Using the last file by configuration search priority: '" + item.FullName + "'."); } configFile = null; configFile = (flag ? JsonConvert.DeserializeObject<PieceUsageTags.ConfigFile>(text) : YamlDeserializer.Deserialize<PieceUsageTags.ConfigFile>(text)); } else { CustomPieceData customPieceData = (flag ? JsonConvert.DeserializeObject<CustomPieceData>(text) : YamlDeserializer.Deserialize<CustomPieceData>(text)); if (customPieceData != null) { dictionary[fileNameWithoutExtension] = customPieceData; } } } catch (Exception ex) { LogWarning("Error reading file (" + item.FullName + ")! Error: " + ex.Message); } } ApplyBulkUsageTagReplacements(dictionary, configFile); ApplyBulkUsageTagAdditions(dictionary, configFile); Dictionary<string, string> dictionary2 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, CustomPieceData> item2 in dictionary) { dictionary2[item2.Key] = JsonConvert.SerializeObject((object)item2.Value); } configsJSON.AssignLocalValue(dictionary2); } private static IEnumerable<FileInfo> GetConfigFiles(DirectoryInfo directory) { return directory.GetFiles("*.json", SearchOption.AllDirectories).Concat(directory.GetFiles("*.yaml", SearchOption.AllDirectories)).Concat(directory.GetFiles("*.yml", SearchOption.AllDirectories)) .OrderBy<FileInfo, string>((FileInfo file) => file.FullName, StringComparer.OrdinalIgnoreCase); } private static CustomPieceData GetOrCreatePieceConfig(Dictionary<string, CustomPieceData> configs, string pieceName) { if (!configs.TryGetValue(pieceName, out var value)) { value = (configs[pieceName] = new CustomPieceData { prefabName = pieceName }); } return value; } private static void ApplyBulkUsageTagReplacements(Dictionary<string, CustomPieceData> configs, PieceUsageTags.ConfigFile usageTagConfig) { if (usageTagConfig?.Pieces == null) { return; } foreach (KeyValuePair<string, List<string>> piece in usageTagConfig.Pieces) { string text = piece.Key?.Trim(); if (!string.IsNullOrWhiteSpace(text)) { UsageTagFlags result; List<string> canonicalNames; string invalidValue; if (piece.Value == null) { LogWarning("Ignoring null usage tag list for piece '" + text + "'. Use an empty list to clear all usage tags."); } else if (!PieceUsageTags.TryParseTags(piece.Value, out result, out canonicalNames, out invalidValue)) { LogWarning("Ignoring usage tag override for piece '" + text + "' because '" + invalidValue + "' is not a supported built-in usage tag."); } else { GetOrCreatePieceConfig(configs, text).usageTags = canonicalNames; } } } } private static void ApplyBulkUsageTagAdditions(Dictionary<string, CustomPieceData> configs, PieceUsageTags.ConfigFile usageTagConfig) { if (usageTagConfig?.Tags == null) { return; } foreach (KeyValuePair<string, List<string>> tag2 in usageTagConfig.Tags) { if (!PieceUsageTags.TryParseTag(tag2.Key, out var _, out var canonicalName)) { LogWarning("Ignoring unsupported built-in usage tag '" + tag2.Key + "' in 'Piece usage tags'."); continue; } if (tag2.Value == null) { LogWarning("Ignoring null piece list for usage tag '" + canonicalName + "'."); continue; } foreach (string item in tag2.Value) { string text = item?.Trim(); if (!string.IsNullOrWhiteSpace(text)) { CustomPieceData orCreatePieceConfig = GetOrCreatePieceConfig(configs, text); if (orCreatePieceConfig.usageTagsAdditions == null) { orCreatePieceConfig.usageTagsAdditions = new List<string>(); } if (!orCreatePieceConfig.usageTagsAdditions.Any((string a) => string.Equals(a, canonicalName, StringComparison.OrdinalIgnoreCase))) { orCreatePieceConfig.usageTagsAdditions.Add(canonicalName); } } } } } private static void LoadConfigs() { pieceData.Clear(); foreach (KeyValuePair<string, string> item in configsJSON.Value) { try { CustomPieceData customPieceData = JsonConvert.DeserializeObject<CustomPieceData>(item.Value); if (customPieceData != null) { customPieceData.PrepareUsageTags(item.Key); pieceData[item.Key] = customPieceData; } } catch (Exception ex) { LogWarning("Error parsing item (" + item.Key + ")! Error: " + ex.Message); } } PiecePatches.UpdatePiecesProperties(); } internal static WearNTear GetWearNTearComponent(Piece piece) { if (piecesWntComponent.TryGetValue(piece, out var value)) { return value; } WearNTear component = ((Component)piece).GetComponent<WearNTear>(); piecesWntComponent[piece] = component; return component; } [CompilerGenerated] internal static string <InitCommands>g__WildCardToRegular|42_5(string value) { return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$"; } } internal class CustomConfigs { internal class ConfigurationManagerAttributes { [UsedImplicitly] public Action<ConfigEntryBase>? CustomDrawer; } internal static object? configManager; internal static Type? configManagerStyles; internal static GUIStyle GetStyle(GUIStyle other) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if (configManagerStyles == null) { return other; } FieldInfo fieldInfo = AccessTools.Field(configManagerStyles, "fontSize"); if (fieldInfo == null) { return other; } return new GUIStyle(other) { fontSize = (int)fieldInfo.GetValue(configManagerStyles) }; } internal static void Awake() { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ConfigurationManager"); Type type = assembly?.GetType("ConfigurationManager.ConfigurationManager"); configManager = ((type == null) ? null : Chainloader.ManagerObject.GetComponent(type)); configManagerStyles = assembly?.GetType("ConfigurationManager.ConfigurationManagerStyles"); } internal static Action<ConfigEntryBase> DrawSeparatedStrings(string splitString) { return delegate(ConfigEntryBase cfg) { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true; bool flag = false; GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); List<string> list = new List<string>(); List<string> list2 = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToList(); for (int num = 0; num < list2.Count; num++) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = list2[num]; string text2 = GUILayout.TextField(text, GetStyle(GUI.skin.textArea), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (text2 != text && !valueOrDefault) { flag = true; } if (GUILayout.Button("x", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault) { flag = true; } else { list.Add(text2); } if (GUILayout.Button("+", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault) { flag = true; list.Add(""); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = string.Join(splitString, list); } }; } internal static Action<ConfigEntryBase> DrawOrderedFixedStrings(string splitString) { return delegate(ConfigEntryBase cfg) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown bool valueOrDefault = cfg.Description.Tags.Select((object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : ((bool?)null)).FirstOrDefault((bool? v) => v.HasValue) == true; bool flag = false; GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); string[] array = ((string)cfg.BoxedValue).Split(new string[1] { splitString }, StringSplitOptions.None).ToArray(); for (int num = 0; num < array.Length; num++) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string text = array[num]; GUILayout.Label(text, GetStyle(GUI.skin.textArea), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("ʌ", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num > 0)) { ref string reference = ref array[num]; ref string reference2 = ref array[num - 1]; string text2 = array[num - 1]; string text3 = array[num]; reference = text2; reference2 = text3; } if (GUILayout.Button("v", new GUIStyle(GetStyle(GUI.skin.button)) { fixedWidth = 21f }, Array.Empty<GUILayoutOption>()) && !valueOrDefault && (flag = num < array.Length - 1)) { ref string reference = ref array[num]; ref string reference3 = ref array[num + 1]; string text3 = array[num + 1]; string text2 = array[num]; reference = text3; reference3 = text2; } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = string.Join(splitString, array); } }; } } [Serializable] internal class CustomPieceData { private readonly struct ResourceSpec { internal readonly string Name; internal readonly int Amount; internal readonly bool Recover; internal ResourceSpec(string name, int amount, bool recover) { Name = name; Amount = amount; Recover = recover; } } public string? prefabName; public string? name; public string? description; public bool? enabled; public List<string>? usageTags; public ComfortGroup? comfortGroup; public int? comfort; public bool? groundOnly; public bool? cultivatedGroundOnly; public bool? waterPiece; public bool? clipGround; public bool? clipEverything; public bool? noInWater; public bool? notOnWood; public bool? notOnTiltingSurface; public bool? inCeilingOnly; public bool? notOnFloor; public bool? noClipping; public bool? onlyInTeleportArea; public bool? allowedInDungeons; public bool? allowedInDeepSnow; public bool? requireDeepSnow; public float? spaceRequirement; public bool? repairPiece; public bool? canBeRemoved; public bool? allowRotatedOverlap; public bool? vegetationGroundOnly; public float? blockRadius; public int? extraPlacementDistance; public string? station; public Biome? onlyInBiome; public bool? targetNonPlayerBuilt; public bool? primaryTarget; public bool? randomTarget; public float? health; public bool? noRoofWear; public float? roofCheckOffset; public bool? noSupportWear; public bool? snowDamageImmune; public MaterialType? materialType; public bool? supports; public float? hitNoise; public float? destroyNoise; public bool? autoCreateFragments; public List<string>? damageModifiers; public bool? ashDamageImmune; public bool? ashDamageResist; public bool? burnable; public int? minToolTier; public bool? triggerPrivateArea; public string? requiredPersistentEvent; public bool? takeDamageIfInsideEvent; public float? eventDamage; public float? eventDamageDeviation; public Biome? requiredBiome; public float? outsideRequiredBiomeDamage; public List<string>? resources; [JsonProperty(/*Could not decode attribute arguments.*/)] [YamlIgnore] internal List<string>? usageTagsAdditions; [NonSerialized] [JsonIgnore] [YamlIgnore] private UsageTagFlags? capturedUsageTags; [NonSerialized] [JsonIgnore] [YamlIgnore] private UsageTagFlags? parsedUsageTags; [NonSerialized] [JsonIgnore] [YamlIgnore] private UsageTagFlags parsedUsageTagAdditions; [NonSerialized] [JsonIgnore] private string[]? parsedResourceSource; [NonSerialized] [JsonIgnore] private ResourceSpec[] parsedResources = Array.Empty<ResourceSpec>(); [NonSerialized] [JsonIgnore] private string[]? parsedDamageSource; [NonSerialized] [JsonIgnore] private DamageModPair[] parsedDamageModifiers = Array.Empty<DamageModPair>(); private static bool Matches(List<string> source, string[]? cached) { if (cached == null || source.Count != cached.Length) { return false; } for (int i = 0; i < cached.Length; i++) { if (!string.Equals(source[i], cached[i], StringComparison.Ordinal)) { return false; } } return true; } private ResourceSpec[] GetResourceSpecs() { if (resources == null) { return Array.Empty<ResourceSpec>(); } if (Matches(resources, parsedResourceSource)) { return parsedResources; } List<ResourceSpec> list = new List<ResourceSpec>(resources.Count); foreach (string resource in resources) { string[] array = resource?.Split(new char[1] { ':' }) ?? Array.Empty<string>(); int result = 1; bool result2 = true; if (array.Length == 0 || string.IsNullOrWhiteSpace(array[0]) || (array.Length > 1 && (!int.TryParse(array[1], out result) || result < 0)) || (array.Length > 2 && !bool.TryParse(array[2], out result2))) { BuildPiecesCustomized.LogWarning("Invalid resource entry for " + prefabName + ": " + resource); } else { list.Add(new ResourceSpec(array[0], result, result2)); } } parsedResources = list.ToArray(); parsedResourceSource = resources.ToArray(); return parsedResources; } private DamageModPair[] GetDamageModifierSpecs() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (damageModifiers == null) { return Array.Empty<DamageModPair>(); } if (Matches(damageModifiers, parsedDamageSource)) { return parsedDamageModifiers; } List<DamageModPair> list = new List<DamageModPair>(damageModifiers.Count); foreach (string damageModifier in damageModifiers) { string[] array = damageModifier?.Split(new char[1] { ':' }) ?? Array.Empty<string>(); if (array.Length == 2 && Enum.TryParse<DamageType>(array[0], out DamageType result) && Enum.TryParse<DamageModifier>(array[1], out DamageModifier result2)) { list.Add(new DamageModPair { m_type = result, m_modifier = result2 }); } } parsedDamageModifiers = list.ToArray(); parsedDamageSource = damageModifiers.ToArray(); return parsedDamageModifiers; } internal void PatchPiece(Piece piece, bool skipResources = false) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Expected O, but got Unknown //IL_0805: Unknown result type (might be due to invalid IL or missing references) //IL_080a: Unknown result type (might be due to invalid IL or missing references) //IL_0849: Unknown result type (might be due to invalid IL or missing references) //IL_084e: Unknown result type (might be due to invalid IL or missing references) //IL_087b: Unknown result type (might be due to invalid IL or missing references) //IL_0880: Unknown result type (might be due to invalid IL or missing references) //IL_0883: Unknown result type (might be due to invalid IL or missing references) //IL_0885: Unknown result type (might be due to invalid IL or missing references) //IL_088a: Unknown result type (might be due to invalid IL or missing references) //IL_088c: Unknown result type (might be due to invalid IL or missing references) //IL_088e: Unknown result type (might be due to invalid IL or missing references) //IL_0893: Unknown result type (might be due to invalid IL or missing references) //IL_089d: Unknown result type (might be due to invalid IL or missing references) //IL_089f: Unknown result type (might be due to invalid IL or missing references) //IL_08a1: Unknown result type (might be due to invalid IL or missing references) //IL_08a3: Unknown result type (might be due to invalid IL or missing references) //IL_08a5: Unknown result type (might be due to invalid IL or missing references) //IL_08a9: Invalid comparison between Unknown and I4 //IL_08e8: Unknown result type (might be due to invalid IL or missing references) //IL_08ef: Invalid comparison between Unknown and I4 //IL_08ab: Unknown result type (might be due to invalid IL or missing references) //IL_08ae: Invalid comparison between Unknown and I4 //IL_0907: Unknown result type (might be due to invalid IL or missing references) //IL_090e: Invalid comparison between Unknown and I4 //IL_08f1: Unknown result type (might be due to invalid IL or missing references) //IL_08f5: Invalid comparison between Unknown and I4 //IL_08d5: Unknown result type (might be due to invalid IL or missing references) //IL_08d9: Invalid comparison between Unknown and I4 //IL_08b0: Unknown result type (might be due to invalid IL or missing references) //IL_08b3: Unknown result type (might be due to invalid IL or missing references) //IL_08c9: Expected I4, but got Unknown //IL_0977: Unknown result type (might be due to invalid IL or missing references) //IL_0979: Unknown result type (might be due to invalid IL or missing references) //IL_0961: Unknown result type (might be due to invalid IL or missing references) //IL_0963: Unknown result type (might be due to invalid IL or missing references) //IL_094b: Unknown result type (might be due to invalid IL or missing references) //IL_094d: Unknown result type (might be due to invalid IL or missing references) //IL_091f: Unknown result type (might be due to invalid IL or missing references) //IL_0921: Unknown result type (might be due to invalid IL or missing references) //IL_092a: Unknown result type (might be due to invalid IL or missing references) //IL_092c: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Unknown result type (might be due to invalid IL or missing references) //IL_0937: Unknown result type (might be due to invalid IL or missing references) //IL_0912: Unknown result type (might be due to invalid IL or missing references) //IL_0919: Invalid comparison between Unknown and I4 //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_0900: Invalid comparison between Unknown and I4 //IL_08dd: Unknown result type (might be due to invalid IL or missing references) //IL_08e1: Invalid comparison between Unknown and I4 //IL_08cb: Unknown result type (might be due to invalid IL or missing references) //IL_08ce: Invalid comparison between Unknown and I4 //IL_0982: Unknown result type (might be due to invalid IL or missing references) //IL_0984: Unknown result type (might be due to invalid IL or missing references) //IL_096c: Unknown result type (might be due to invalid IL or missing references) //IL_096e: Unknown result type (might be due to invalid IL or missing references) //IL_0956: Unknown result type (might be due to invalid IL or missing references) //IL_0958: Unknown result type (might be due to invalid IL or missing references) //IL_0940: Unknown result type (might be due to invalid IL or missing references) //IL_0942: Unknown result type (might be due to invalid IL or missing references) if (enabled.HasValue) { piece.m_enabled = enabled.Value; } if (name != null) { piece.m_name = name; } if (description != null) { piece.m_description = description; } if (capturedUsageTags.HasValue) { piece.m_usage = capturedUsageTags.Value; } else if (parsedUsageTags.HasValue) { piece.m_usage = parsedUsageTags.Value; } if ((int)parsedUsageTagAdditions > 0) { piece.m_usage |= parsedUsageTagAdditions; } if (comfort.HasValue) { piece.m_comfort = comfort.Value; } if (comfortGroup.HasValue) { piece.m_comfortGroup = comfortGroup.Value; } if (groundOnly.HasValue) { piece.m_groundOnly = groundOnly.Value; } if (cultivatedGroundOnly.HasValue) { piece.m_cultivatedGroundOnly = cultivatedGroundOnly.Value; } if (waterPiece.HasValue) { piece.m_waterPiece = waterPiece.Value; } if (clipGround.HasValue) { piece.m_clipGround = clipGround.Value; } if (clipEverything.HasValue) { piece.m_clipEverything = clipEverything.Value; } if (noInWater.HasValue) { piece.m_noInWater = noInWater.Value; } if (notOnWood.HasValue) { piece.m_notOnWood = notOnWood.Value; } if (notOnTiltingSurface.HasValue) { piece.m_notOnTiltingSurface = notOnTiltingSurface.Value; } if (inCeilingOnly.HasValue) { piece.m_inCeilingOnly = inCeilingOnly.Value; } if (notOnFloor.HasValue) { piece.m_notOnFloor = notOnFloor.Value; } if (noClipping.HasValue) { piece.m_noClipping = noClipping.Value; } if (onlyInTeleportArea.HasValue) { piece.m_onlyInTeleportArea = onlyInTeleportArea.Value; } if (allowedInDungeons.HasValue) { piece.m_allowedInDungeons = allowedInDungeons.Value; } if (allowedInDeepSnow.HasValue) { piece.m_allowedInDeepSnow = allowedInDeepSnow.Value; } if (requireDeepSnow.HasValue) { piece.m_requireDeepSnow = requireDeepSnow.Value; } if (spaceRequirement.HasValue) { piece.m_spaceRequirement = spaceRequirement.Value; } if (repairPiece.HasValue) { piece.m_repairPiece = repairPiece.Value; } if (canBeRemoved.HasValue) { piece.m_canBeRemoved = canBeRemoved.Value; } if (allowRotatedOverlap.HasValue) { piece.m_allowRotatedOverlap = allowRotatedOverlap.Value; } if (vegetationGroundOnly.HasValue) { piece.m_vegetationGroundOnly = vegetationGroundOnly.Value; } if (blockRadius.HasValue) { piece.m_blockRadius = blockRadius.Value; } if (extraPlacementDistance.HasValue) { piece.m_extraPlacementDistance = extraPlacementDistance.Value; } if (station != null) { piece.m_craftingStation = GeneralExtensions.GetValueSafe<string, CraftingStation>(BuildPiecesCustomized.craftingStations, station); } if (onlyInBiome.HasValue) { piece.m_onlyInBiome = onlyInBiome.Value; } if (targetNonPlayerBuilt.HasValue) { piece.m_targetNonPlayerBuilt = targetNonPlayerBuilt.Value; } if (primaryTarget.HasValue) { ((StaticTarget)piece).m_primaryTarget = primaryTarget.Value; } if (randomTarget.HasValue) { ((StaticTarget)piece).m_randomTarget = randomTarget.Value; } if (resources != null && !skipResources) { ResourceSpec[] resourceSpecs = GetResourceSpecs(); Requirement[] array = (Requirement[])(object)new Requirement[resourceSpecs.Length]; int num = 0; for (int i = 0; i < resourceSpecs.Length; i++) { ResourceSpec resourceSpec = resourceSpecs[i]; ObjectDB instance = ObjectDB.instance; object obj; if (instance == null) { obj = null; } else { GameObject itemPrefab = instance.GetItemPrefab(resourceSpec.Name); obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); } ItemDrop val = (ItemDrop)obj; if (!((Object)(object)val == (Object)null)) { array[num++] = new Requirement { m_resItem = val, m_amount = resourceSpec.Amount, m_recover = resourceSpec.Recover }; } } if (num != array.Length) { Array.Resize(ref array, num); } piece.m_resources = array; } WearNTear wearNTearComponent = BuildPiecesCustomized.GetWearNTearComponent(piece); if (wearNTearComponent == null) { return; } if (health.HasValue) { wearNTearComponent.m_health = health.Value; } if (noRoofWear.HasValue) { wearNTearComponent.m_noRoofWear = noRoofWear.Value; } if (roofCheckOffset.HasValue) { wearNTearComponent.m_roofCheckOffset = roofCheckOffset.Value; } if (noSupportWear.HasValue) { wearNTearComponent.m_noSupportWear = noSupportWear.Value; } if (snowDamageImmune.HasValue) { wearNTearComponent.m_snowDamageImmune = snowDamageImmune.Value; } if (supports.HasValue) { wearNTearComponent.m_supports = supports.Value; } if (hitNoise.HasValue) { wearNTearComponent.m_hitNoise = hitNoise.Value; } if (destroyNoise.HasValue) { wearNTearComponent.m_destroyNoise = destroyNoise.Value; } if (autoCreateFragments.HasValue) { wearNTearComponent.m_autoCreateFragments = autoCreateFragments.Value; } if (ashDamageImmune.HasValue) { wearNTearComponent.m_ashDamageImmune = ashDamageImmune.Value; } if (ashDamageResist.HasValue) { wearNTearComponent.m_ashDamageResist = ashDamageResist.Value; } if (burnable.HasValue) { wearNTearComponent.m_burnable = burnable.Value; } if (minToolTier.HasValue) { wearNTearComponent.m_minToolTier = minToolTier.Value; } if (triggerPrivateArea.HasValue) { wearNTearComponent.m_triggerPrivateArea = triggerPrivateArea.Value; } if (requiredPersistentEvent != null) { wearNTearComponent.m_requiredPersistentEvent = requiredPersistentEvent; } if (takeDamageIfInsideEvent.HasValue) { wearNTearComponent.m_takeDamageIfInsideEvent = takeDamageIfInsideEvent.Value; } if (eventDamage.HasValue) { wearNTearComponent.m_eventDamage = eventDamage.Value; } if (eventDamageDeviation.HasValue) { wearNTearComponent.m_eventDamageDeviation = eventDamageDeviation.Value; } if (requiredBiome.HasValue) { wearNTearComponent.m_requiredBiome = requiredBiome.Value; } if (outsideRequiredBiomeDamage.HasValue) { wearNTearComponent.m_outsideRequiredBiomeDamage = outsideRequiredBiomeDamage.Value; } if (materialType.HasValue) { wearNTearComponent.m_materialType = materialType.Value; } if (damageModifiers == null) { return; } DamageModPair[] damageModifierSpecs = GetDamageModifierSpecs(); foreach (DamageModPair val2 in damageModifierSpecs) { DamageType type = val2.m_type; DamageModifier modifier = val2.m_modifier; ref DamageModifiers damages = ref wearNTearComponent.m_damages; DamageType val3 = type; DamageType val4 = val3; if ((int)val4 <= 32) { if ((int)val4 <= 8) { switch (val4 - 1) { case 0: damages.m_blunt = modifier; continue; case 1: damages.m_slash = modifier; continue; case 3: damages.m_pierce = modifier; continue; case 2: continue; } if ((int)val4 == 8) { damages.m_chop = modifier; } } else if ((int)val4 != 16) { if ((int)val4 == 32) { damages.m_fire = modifier; } } else { damages.m_pickaxe = modifier; } } else if ((int)val4 <= 128) { if ((int)val4 != 64) { if ((int)val4 == 128) { damages.m_lightning = modifier; } } else { damages.m_frost = modifier; } } else if ((int)val4 != 256) { if ((int)val4 == 512) { damages.m_spirit = modifier; } } else { damages.m_poison = modifier; } } } internal void PrepareUsageTags(string sourceName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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) parsedUsageTags = null; parsedUsageTagAdditions = (UsageTagFlags)0; if (usageTags != null) { if (PieceUsageTags.TryParseTags(usageTags, out var result, out var canonicalNames, out var invalidValue)) { usageTags = canonicalNames; parsedUsageTags = result; } else { BuildPiecesCustomized.LogWarning("Invalid usage tag '" + invalidValue + "' in '" + sourceName + "'. The configured usageTags value will be ignored."); usageTags = null; } } if (usageTagsAdditions != null) { if (PieceUsageTags.TryParseTags(usageTagsAdditions, out var result2, out var canonicalNames2, out var invalidValue2)) { usageTagsAdditions = canonicalNames2; parsedUsageTagAdditions = result2; return; } BuildPiecesCustomized.LogWarning("Invalid usage tag '" + invalidValue2 + "' in the bulk usage tag override for '" + sourceName + "'. The tag additions will be ignored."); usageTagsAdditions = null; } } internal void SaveToDirectory(string directory) { Directory.CreateDirectory(directory); string path = Path.Combine(directory, prefabName + "." + (BuildPiecesCustomized.saveAsYAML.Value ? "yaml" : "json")); File.WriteAllText(path, BuildPiecesCustomized.saveAsYAML.Value ? BuildPiecesCustomized.YamlSerializer.Serialize((object)this) : JsonConvert.SerializeObject((object)this, (Formatting)1)); } internal CustomPieceData() { } internal CustomPieceData(Piece piece) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_0615: Unknown result type (might be due to invalid IL or missing references) //IL_065e: Unknown result type (might be due to invalid IL or missing references) //IL_06a7: Unknown result type (might be due to invalid IL or missing references) //IL_06f0: Unknown result type (might be due to invalid IL or missing references) prefabName = ((Object)((Component)piece).gameObject).name; enabled = piece.m_enabled; name = piece.m_name; description = piece.m_description; capturedUsageTags = piece.m_usage; usageTags = (PieceUsageTags.HasUnsupportedBits(piece.m_usage) ? null : PieceUsageTags.GetNames(piece.m_usage)); comfortGroup = piece.m_comfortGroup; comfort = piece.m_comfort; groundOnly = piece.m_groundOnly; cultivatedGroundOnly = piece.m_cultivatedGroundOnly; waterPiece = piece.m_waterPiece; clipGround = piece.m_clipGround; clipEverything = piece.m_clipEverything; noInWater = piece.m_noInWater; notOnWood = piece.m_notOnWood; notOnTiltingSurface = piece.m_notOnTiltingSurface; inCeilingOnly = piece.m_inCeilingOnly; notOnFloor = piece.m_notOnFloor; noClipping = piece.m_noClipping; onlyInTeleportArea = piece.m_onlyInTeleportArea; allowedInDungeons = piece.m_allowedInDungeons; allowedInDeepSnow = piece.m_allowedInDeepSnow; requireDeepSnow = piece.m_requireDeepSnow; spaceRequirement = piece.m_spaceRequirement; repairPiece = piece.m_repairPiece; canBeRemoved = piece.m_canBeRemoved; station = (Object.op_Implicit((Object)(object)piece.m_craftingStation) ? piece.m_craftingStation.m_name : ""); onlyInBiome = piece.m_onlyInBiome; allowRotatedOverlap = piece.m_allowRotatedOverlap; vegetationGroundOnly = piece.m_vegetationGroundOnly; blockRadius = piece.m_blockRadius; extraPlacementDistance = piece.m_extraPlacementDistance; targetNonPlayerBuilt = piece.m_targetNonPlayerBuilt; primaryTarget = ((StaticTarget)piece).m_primaryTarget; randomTarget = ((StaticTarget)piece).m_randomTarget; resources = new List<string>(); resources.AddRange(piece.m_resources.Select((Requirement req) => $"{((Object)req.m_resItem).name}:{req.m_amount}:{req.m_recover}")); WearNTear wearNTearComponent = BuildPiecesCustomized.GetWearNTearComponent(piece); if ((Object)(object)wearNTearComponent != (Object)null) { health = wearNTearComponent.m_health; noRoofWear = wearNTearComponent.m_noRoofWear; roofCheckOffset = wearNTearComponent.m_roofCheckOffset; noSupportWear = wearNTearComponent.m_noSupportWear; snowDamageImmune = wearNTearComponent.m_snowDamageImmune; materialType = wearNTearComponent.m_materialType; supports = wearNTearComponent.m_supports; hitNoise = wearNTearComponent.m_hitNoise; destroyNoise = wearNTearComponent.m_destroyNoise; autoCreateFragments = wearNTearComponent.m_autoCreateFragments; ashDamageImmune = wearNTearComponent.m_ashDamageImmune; ashDamageResist = wearNTearComponent.m_ashDamageResist; burnable = wearNTearComponent.m_burnable; minToolTier = wearNTearComponent.m_minToolTier; triggerPrivateArea = wearNTearComponent.m_triggerPrivateArea; requiredPersistentEvent = wearNTearComponent.m_requiredPersistentEvent; takeDamageIfInsideEvent = wearNTearComponent.m_takeDamageIfInsideEvent; eventDamage = wearNTearComponent.m_eventDamage; eventDamageDeviation = wearNTearComponent.m_eventDamageDeviation; requiredBiome = wearNTearComponent.m_requiredBiome; outsideRequiredBiomeDamage = wearNTearComponent.m_outsideRequiredBiomeDamage; damageModifiers = new List<string> { Enum.GetName(typeof(DamageType), (object)(DamageType)1) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_blunt), Enum.GetName(typeof(DamageType), (object)(DamageType)2) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_slash), Enum.GetName(typeof(DamageType), (object)(DamageType)4) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_pierce), Enum.GetName(typeof(DamageType), (object)(DamageType)8) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_chop), Enum.GetName(typeof(DamageType), (object)(DamageType)16) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_pickaxe), Enum.GetName(typeof(DamageType), (object)(DamageType)32) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_fire), Enum.GetName(typeof(DamageType), (object)(DamageType)64) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_frost), Enum.GetName(typeof(DamageType), (object)(DamageType)128) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_lightning), Enum.GetName(typeof(DamageType), (object)(DamageType)256) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_poison), Enum.GetName(typeof(DamageType), (object)(DamageType)512) + ":" + Enum.GetName(typeof(DamageModifier), wearNTearComponent.m_damages.m_spirit) }; } } internal static CustomPieceData? GetByPieceName(string pieceName) { if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return null; } GameObject val = ((IEnumerable<GameObject>)GetBuildPieces()).FirstOrDefault((Func<GameObject, bool>)((GameObject buildPiece) => ((Object)buildPiece).name == pieceName)); if ((Object)(object)val == (Object)null) { return null; } Piece piece = default(Piece); if (!val.TryGetComponent<Piece>(ref piece)) { return null; } return new CustomPieceData(piece); } internal static List<GameObject> GetBuildPieces() { List<GameObject> list = new List<GameObject>(); HashSet<string> hashSet = new HashSet<string>(from c in BuildPiecesCustomized.toolsToPatchPieces.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select c.Trim()); foreach (string item in hashSet) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null)) { list.AddRange(val.m_itemData.m_shared.m_buildPieces.m_pieces); } } return list; } } internal static class DocGen { [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPriority(0)] private static class ObjectDB_Awake_DocGen { private static void Postfix() { if (BuildPiecesCustomized.modEnabled.Value) { GenerateDocumentationFile(); } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPriority(0)] private static class ObjectDB_CopyOtherDB_DocGen { private static void Postfix() { if (BuildPiecesCustomized.modEnabled.Value) { GenerateDocumentationFile(); } } } [HarmonyPatch(typeof(ZoneSystem), "Start")] [HarmonyPriority(0)] private static class ZoneSystem_Start_DocGen { private static void Postfix() { if (BuildPiecesCustomized.modEnabled.Value) { GenerateDocumentationFile(); } } } private static readonly StringBuilder sb = new StringBuilder(); internal const string filename = "Pieces and properties.md"; internal static void GenerateDocumentationFile() { string text = Path.Combine(BuildPiecesCustomized.configDirectory.FullName, "Pieces and properties.md"); try { Directory.CreateDirectory(BuildPiecesCustomized.configDirectory.FullName); File.WriteAllText(text, GetFileText()); } catch (Exception ex) { BuildPiecesCustomized.LogWarning("Error when writing file (" + text + ")! Error: " + ex.Message); } } private static void LogUsageTags() { sb.AppendLine("`usageTags` is an optional list of built-in Valheim Hammer usage tags."); sb.AppendLine("If the property is omitted, the original usage tags are preserved."); sb.AppendLine("If the property is present, the list fully replaces the current usage tags. An empty list clears them."); sb.AppendLine("Tag names are case-insensitive when loading, but generated files use the canonical names below."); sb.AppendLine("Numeric values and custom runtime tags added by other mods are not supported."); sb.AppendLine("Unsupported custom tags are preserved when usageTags is omitted, but a usageTags replacement contains built-in tags only."); sb.AppendLine(); sb.AppendLine("| Value | In-game name |"); sb.AppendLine("|---|---|"); foreach (PieceUsageTags.Definition definition in PieceUsageTags.Definitions) { sb.AppendLine("| " + definition.Name + " | " + PieceUsageTags.GetLocalizedDisplayName(definition) + " |"); } } private static void LogBulkUsageTagFormat() { sb.AppendLine("Use a file named `Piece usage tags.yaml`, `Piece usage tags.yml`, or `Piece usage tags.json` for centralized usage tag overrides."); sb.AppendLine("The bulk file has higher priority than individual piece files."); sb.AppendLine("The `pieces` section replaces the full tag list for a piece. The `tags` section adds one tag to every listed piece."); sb.AppendLine("Within the bulk file, `pieces` is applied first and `tags` is applied afterwards, so both directions can be mixed safely."); sb.AppendLine(); sb.AppendLine("```yaml"); sb.AppendLine("pieces:"); sb.AppendLine(" wood_door:"); sb.AppendLine(" - Building"); sb.AppendLine(" - Doors"); sb.AppendLine(" custom_piece: []"); sb.AppendLine(); sb.AppendLine("tags:"); sb.AppendLine(" Defense:"); sb.AppendLine(" - h_drawbridge01"); sb.AppendLine(" - hayzestake_01"); sb.AppendLine("```"); sb.AppendLine(); sb.AppendLine("```json"); sb.AppendLine("{"); sb.AppendLine(" \"pieces\": {"); sb.AppendLine(" \"wood_door\": [\"Building\", \"Doors\"],"); sb.AppendLine(" \"custom_piece\": []"); sb.AppendLine(" },"); sb.AppendLine(" \"tags\": {"); sb.AppendLine(" \"Defense\": [\"h_drawbridge01\", \"hayzestake_01\"]"); sb.AppendLine(" }"); sb.AppendLine("}"); sb.AppendLine("```"); } private static string GetFileText() { //IL_0558: Unknown result type (might be due to invalid IL or missing references) sb.Clear(); sb.AppendLine("This documentation is generated automatically. It contains all available pieces and identifiers used to configure pieces."); sb.AppendLine(); sb.AppendLine("# Properties and available values"); sb.AppendLine(); sb.AppendLine("## usageTags - Hammer categories"); LogUsageTags(); sb.AppendLine(); sb.AppendLine("## Piece usage tags bulk file"); LogBulkUsageTagFormat(); sb.AppendLine(); sb.AppendLine("## Deep North and environment properties"); sb.AppendLine("| Property | Description |"); sb.AppendLine("|---|---|"); sb.AppendLine("| `allowedInDeepSnow` | Allows placement in Deep North deep-snow areas that normally reject the piece. |"); sb.AppendLine("| `requireDeepSnow` | Requires Deep North deep snow for placement. |"); sb.AppendLine("| `roofCheckOffset` | Offset used by WearNTear roof detection. |"); sb.AppendLine("| `snowDamageImmune` | Immunity to heavy-snow damage. |"); sb.AppendLine("| `requiredPersistentEvent` | Persistent-event identifier used by WearNTear event damage logic. |"); sb.AppendLine("| `takeDamageIfInsideEvent` | Enables the configured persistent-event damage condition. |"); sb.AppendLine("| `eventDamage`, `eventDamageDeviation` | Base persistent-event damage and random deviation. |"); sb.AppendLine("| `requiredBiome`, `outsideRequiredBiomeDamage` | Biome requirement and damage applied outside that biome. |"); sb.AppendLine(); sb.AppendLine("## comfortGroup"); EnumToList(typeof(ComfortGroup)); sb.AppendLine(); sb.AppendLine("## biome values (`onlyInBiome`, `requiredBiome`)"); EnumToList(typeof(Biome)); sb.AppendLine(); sb.AppendLine("## materialType"); EnumToList(typeof(MaterialType)); sb.AppendLine(); sb.AppendLine("## damageModifiers"); sb.AppendLine(); sb.AppendLine("### type"); EnumToList(typeof(DamageType), noID: true); sb.AppendLine(); sb.AppendLine("### modifier"); EnumToList(typeof(DamageModifier), noID: true); if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { sb.AppendLine(); sb.AppendLine("## station"); Dictionary<string, CraftingStation> dictionary = new Dictionary<string, CraftingStation>(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_craftingStation == (Object)null)) { dictionary[((Object)recipe.m_craftingStation).name] = recipe.m_craftingStation; } } sb.AppendLine("| Prefab | Localized name |"); sb.AppendLine("|---|---|"); foreach (KeyValuePair<string, CraftingStation> item in dictionary) { sb.AppendLine("| " + MarkdownCell(item.Key) + " | " + MarkdownCell(Localization.instance.Localize(item.Value.m_name)) + " |"); } sb.AppendLine(); sb.AppendLine("# Piece prefab names and usage tags"); sb.AppendLine("Pieces are listed in the same order as their build tool."); Piece val = default(Piece); foreach (ItemDrop allItem in ObjectDB.instance.GetAllItems((ItemType)19, "")) { if ((Object)(object)allItem == (Object)null || (Object)(object)allItem.m_itemData.m_shared.m_buildPieces == (Object)null || allItem.m_itemData.m_shared.m_buildPieces.m_pieces.Count == 0) { continue; } sb.AppendLine(); sb.AppendLine("## " + ((Object)allItem).name + " - " + allItem.m_itemData.m_shared.m_name + " - " + Localization.instance.Localize(allItem.m_itemData.m_shared.m_name)); sb.AppendLine("| Prefab | Token | Localized name | usageTags |"); sb.AppendLine("|---|---|---|---|"); foreach (GameObject piece in allItem.m_itemData.m_shared.m_buildPieces.m_pieces) { if (piece.TryGetComponent<Piece>(ref val)) { sb.AppendLine("| " + MarkdownCell(((Object)val).name) + " | " + MarkdownCell(val.m_name) + " | " + MarkdownCell(Localization.instance.Localize(val.m_name)) + " | " + MarkdownCell(PieceUsageTags.FormatForDocumentation(val.m_usage)) + " |"); } } } } return sb.ToString(); } private static void EnumToList(Type enumType, bool noID = false) { if (noID) { sb.AppendLine("| Value |"); sb.AppendLine("|---|"); } else { sb.AppendLine("| ID | Value |"); sb.AppendLine("|---:|---|"); } foreach (object value in Enum.GetValues(enumType)) { sb.AppendLine(noID ? $"| {value} |" : $"| {(int)value} | {value} |"); } } private static string MarkdownCell(string value) { return (value ?? string.Empty).Replace("|", "\\|").Replace("\r", " ").Replace("\n", " "); } } public static class PiecePatches { [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] private static class ZNetScene_OnDestroy_ClearFallbackPieces { private static void Postfix() { fallbackPieces.Clear(); fallbackScene = null; } } [HarmonyPatch(typeof(Piece), "Awake")] private static class Piece_Awake_PatchPiece { private static void Postfix(Piece __instance) { if (BuildPiecesCustomized.modEnabled.Value) { PatchPiece(__instance); } } } [HarmonyPatch(typeof(PieceTable), "IsPieceAvailable")] private static class PieceTable_IsPieceAvailable_PieceDisabled { private static void Postfix(PieceTable __instance, Piece piece, ref bool __result) { if (BuildPiecesCustomized.modEnabled.Value && __result && GlobalPatches.IsPieceForceDisabled(piece)) { __result = false; } } } [HarmonyPatch(typeof(PieceTable), "UpdateAvailable")] private static class PieceTable_UpdateAvailable_PieceDisabled { [HarmonyPriority(0)] private static void Postfix(PieceTable __instance) { if (!BuildPiecesCustomized.modEnabled.Value) { return; } int num = __instance.m_availablePieces.RemoveWhere(GlobalPatches.IsPieceForceDisabled); __instance.m_enabledPieces.RemoveWhere(GlobalPatches.IsPieceForceDisabled); foreach (List<Piece> item in __instance.m_availablePiecesByCategory) { item.RemoveAll(GlobalPatches.IsPieceForceDisabled); } if (num > 0) { BuildPiecesCustomized.LogInfo($"Hidden pieces {((Object)__instance).name}: {num}"); } } } public static class GlobalPatches { public const string allPiecesIdentifier = "AllPieces"; private static readonly string allPiecesListIdentifier = "AllPieces".ToLowerInvariant(); private static bool clipEverything; private static bool allowedInDungeons; private static bool repairPiece; private static bool canBeRemoved; private static bool isRoof; private static bool isLeaky; private static bool ashDamageImmune; private static bool snowDamageImmune; private static bool noRoofWear; private static bool noSupportWear; private static HashSet<string> listClipEverything; private static HashSet<string> listAllowedInDungeons; private static HashSet<string> listRepairPiece; private static HashSet<string> listCanBeRemoved; private static HashSet<string> listIsRoof; private static HashSet<string> listIsLeaky; private static HashSet<string> listAshDamageImmune; private static HashSet<string> listSnowDamageImmune; private static HashSet<string> listNoRoofWear; private static HashSet<string> listNoSupportWear; private static HashSet<string> listDisabled; private static HashSet<string> ConfigToHashSet(string configString) { return new HashSet<string>(from p in configString.Split(new char[1] { ',' }) select p.Trim() into p where !string.IsNullOrWhiteSpace(p) select p, StringComparer.OrdinalIgnoreCase); } public static void UpdateProperties() { listClipEverything = ConfigToHashSet(BuildPiecesCustomized.prefabListClipEverything.Value); listAllowedInDungeons = ConfigToHashSet(BuildPiecesCustomized.prefabListAllowedInDungeons.Value); listRepairPiece = ConfigToHashSet(BuildPiecesCustomized.prefabListRepairPiece.Value); listCanBeRemoved = ConfigToHashSet(BuildPiecesCustomized.prefabListCanBeRemoved.Value); listIsRoof = ConfigToHashSet(BuildPiecesCustomized.prefabListIsRoof.Value); listIsLeaky = ConfigToHashSet(BuildPiecesCustomized.prefabListIsLeaky.Value); listAshDamageImmune = ConfigToHashSet(BuildPiecesCustomized.prefabListAshDamageImmune.Value); listSnowDamageImmune = ConfigToHashSet(BuildPiecesCustomized.prefabListSnowDamageImmune.Value); listNoRoofWear = ConfigToHashSet(BuildPiecesCustomized.prefabListNoRoofWear.Value); listNoSupportWear = ConfigToHashSet(BuildPiecesCustomized.prefabListNoSupportWear.Value); listDisabled = ConfigToHashSet(BuildPiecesCustomized.prefabListDisabled.Value); clipEverything = listClipEverything.Contains(allPiecesListIdentifier); allowedInDungeons = listAllowedInDungeons.Contains(allPiecesListIdentifier); repairPiece = listRepairPiece.Contains(allPiecesListIdentifier); canBeRemoved = listCanBeRemoved.Contains(allPiecesListIdentifier); isRoof = listIsRoof.Contains(allPiecesListIdentifier); isLeaky = listIsLeaky.Contains(allPiecesListIdentifier); ashDamageImmune = listAshDamageImmune.Contains(allPiecesListIdentifier); snowDamageImmune = listSnowDamageImmune.Contains(allPiecesListIdentifier); noRoofWear = listNoRoofWear.Contains(allPiecesListIdentifier); noSupportWear = listNoSupportWear.Contains(allPiecesListIdentifier); } public static bool IsPieceForceDisabled(Piece piece) { return (Object)(object)piece != (Object)null && listDisabled != null && listDisabled.Count > 0 && listDisabled.Contains(Utils.GetPrefabName(((Component)piece).gameObject)); } public static bool IsPieceForceDisabled(GameObject gameObject) { Piece piece = default(Piece); return (Object)(object)gameObject != (Object)null && gameObject.TryGetComponent<Piece>(ref piece) && IsPieceForceDisabled(piece); } public static void PatchGlobalProperties(Piece piece, string pieceName) { if (clipEverything) { piece.m_clipEverything = true; } else if (listClipEverything.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " clip everything"); } piece.m_clipEverything = true; } if (allowedInDungeons) { piece.m_allowedInDungeons = true; } else if (listAllowedInDungeons.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " allowed in dungeons"); } piece.m_allowedInDungeons = true; } if (repairPiece) { piece.m_repairPiece = true; } else if (listRepairPiece.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " can be repaired"); } piece.m_repairPiece = true; } if (canBeRemoved) { piece.m_canBeRemoved = true; } else if (listCanBeRemoved.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " can be removed"); } piece.m_canBeRemoved = true; } if (listDisabled.Contains(pieceName)) { piece.m_enabled = false; } WearNTear wearNTearComponent = BuildPiecesCustomized.GetWearNTearComponent(piece); if (!((Object)(object)wearNTearComponent != (Object)null)) { return; } if (ashDamageImmune) { wearNTearComponent.m_ashDamageImmune = true; } else if (listAshDamageImmune.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " ash and lava immune"); } wearNTearComponent.m_ashDamageImmune = true; } if (snowDamageImmune) { wearNTearComponent.m_snowDamageImmune = true; } else if (listSnowDamageImmune.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " heavy snow immune"); } wearNTearComponent.m_snowDamageImmune = true; } if (noRoofWear) { wearNTearComponent.m_noRoofWear = false; } else if (listNoRoofWear.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " no water damage"); } wearNTearComponent.m_noRoofWear = false; } if (noSupportWear) { wearNTearComponent.m_noSupportWear = false; } else if (listNoSupportWear.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " no structural integrity"); } wearNTearComponent.m_noSupportWear = false; } if (isRoof) { CollectionExtensions.Do<Collider>(from col in ((Component)((Component)wearNTearComponent).transform.root).GetComponentsInChildren<Collider>(true) where ((Component)col).tag == "leaky" select col, (Action<Collider>)delegate(Collider col) { ((Component)col).tag = "roof"; }); } else if (listIsRoof.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " leaky -> roof"); } CollectionExtensions.Do<Collider>(from col in ((Component)((Component)wearNTearComponent).transform.root).GetComponentsInChildren<Collider>(true) where ((Component)col).tag == "leaky" select col, (Action<Collider>)delegate(Collider col) { ((Component)col).tag = "roof"; }); } if (isLeaky) { CollectionExtensions.Do<Collider>(from col in ((Component)((Component)wearNTearComponent).transform.root).GetComponentsInChildren<Collider>(true) where ((Component)col).tag == "roof" select col, (Action<Collider>)delegate(Collider col) { ((Component)col).tag = "leaky"; }); } else if (listIsLeaky.Contains(pieceName)) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + pieceName + " roof -> leaky"); } CollectionExtensions.Do<Collider>(from col in ((Component)((Component)wearNTearComponent).transform.root).GetComponentsInChildren<Collider>(true) where ((Component)col).tag == "roof" select col, (Action<Collider>)delegate(Collider col) { ((Component)col).tag = "leaky"; }); } } } private static ZNetScene fallbackScene; private static readonly Dictionary<string, Piece> fallbackPieces = new Dictionary<string, Piece>(StringComparer.Ordinal); public static void UpdatePiecesProperties() { GlobalPatches.UpdateProperties(); if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { ((MonoBehaviour)BuildPiecesCustomized.instance).StartCoroutine(PatchPieces()); } List<Piece> s_allPieces = Piece.s_allPieces; if (s_allPieces != null) { CollectionExtensions.Do<Piece>((IEnumerable<Piece>)s_allPieces, (Action<Piece>)delegate(Piece piece) { PatchPiece(piece); }); } RefreshBuildUi(); } private static void RefreshBuildUi() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { localPlayer.UpdateAvailablePiecesList(); BuildUi val = Hud.instance?.m_buildUi; if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf) { val.UpdateTagButtons(true); } } } private static void FillCraftingStations() { BuildPiecesCustomized.craftingStations.Clear(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!((Object)(object)recipe?.m_craftingStation == (Object)null) && !BuildPiecesCustomized.craftingStations.ContainsKey(((Object)recipe.m_craftingStation).name)) { BuildPiecesCustomized.craftingStations[((Object)recipe.m_craftingStation).name] = recipe.m_craftingStation; BuildPiecesCustomized.craftingStations[recipe.m_craftingStation.m_name] = recipe.m_craftingStation; BuildPiecesCustomized.craftingStations[recipe.m_craftingStation.m_name.Substring(1)] = recipe.m_craftingStation; } } } private static Piece FindDefaultPiece(string name) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)fallbackScene != (Object)(object)instance) { fallbackScene = instance; fallbackPieces.Clear(); } GameObject prefab = instance.GetPrefab(name); if (Object.op_Implicit((Object)(object)prefab)) { return prefab.GetComponent<Piece>(); } if (fallbackPieces.TryGetValue(name, out var value) && Object.op_Implicit((Object)(object)value)) { return value; } Piece result = null; Piece[] array = Resources.FindObjectsOfTypeAll<Piece>(); foreach (Piece val in array) { if (Object.op_Implicit((Object)(object)val)) { string name2 = ((Object)val).name; if (fallbackPieces.Count < 4096 && (!fallbackPieces.TryGetValue(name2, out var value2) || !Object.op_Implicit((Object)(object)value2))) { fallbackPieces[name2] = val; } if (name2 == name) { result = val; break; } } } return result; } private static void PatchPiece(Piece piece) { if ((Object)(object)piece == (Object)null || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return; } string prefabName = Utils.GetPrefabName(((Component)piece).gameObject); if (!BuildPiecesCustomized.defaultPieceData.TryGetValue(prefabName, out var value)) { Piece val = FindDefaultPiece(prefabName); if (!Object.op_Implicit((Object)(object)val)) { return; } value = new CustomPieceData(val); BuildPiecesCustomized.defaultPieceData[prefabName] = value; } BuildPiecesCustomized.pieceData.TryGetValue(prefabName, out var value2); value.PatchPiece(piece, value2?.resources != null); if (value2 != null) { if (BuildPiecesCustomized.loggingEnabled.Value) { BuildPiecesCustomized.LogInfo("Patching " + ((Object)piece).name); } value2.PatchPiece(piece); } GlobalPatches.PatchGlobalProperties(piece, prefabName); if ((Object)(object)piece.m_nview != (Object)null && piece.m_nview.IsValid()) { piece.m_nview.LoadFields(); } } private static IEnumerator PatchPieces() { yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)ObjectDB.instance != (Object)null)); FillCraftingStations(); yield return (object)new WaitForFixedUpdate(); if (!BuildPiecesCustomized.modEnabled.Value || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { yield break; } Piece piece = default(Piece); foreach (GameObject go in CustomPieceData.GetBuildPieces()) { if ((Object)(object)go != (Object)null && go.TryGetComponent<Piece>(ref piece)) { PatchPiece(piece); } piece = null; } RefreshBuildUi(); DocGen.GenerateDocumentationFile(); } } internal static class PieceUsageTags { internal sealed class Definition { internal string Name { get; } internal UsageTagFlags Value { get; } internal string DisplayNameToken { get; } internal Definition(string name, UsageTagFlags value, string displayNameToken) { //IL_0010: 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) Name = name; Value = value; DisplayNameToken = displayNameToken; } } internal sealed class ConfigFile { [JsonProperty("pieces")] [YamlMember(Alias = "pieces")] public Dictionary<string, List<string>> Pieces { get; set; } [JsonProperty("tags")] [YamlMember(Alias = "tags")] public Dictionary<string, List<string>> Tags { get; set; } } internal const string ConfigFileName = "Piece usage tags"; private static readonly List<Definition> definitions = (from field in typeof(UsageTagFlags).GetFields(BindingFlags.Static | BindingFlags.Public) orderby field.MetadataToken select field).Select(delegate(FieldInfo field) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) DisplayNameAttribute val = (DisplayNameAttribute)Attribute.GetCustomAttribute(field, typeof(DisplayNameAttribute)); return new Definition(field.Name, (UsageTagFlags)field.GetValue(null), val?.DisplayName); }).ToList(); private static readonly Dictionary<string, Definition> definitionsByName = definitions.ToDictionary<Definition, string>((Definition definition) => definition.Name, StringComparer.OrdinalIgnoreCase); private static readonly int knownMask = definitions.Aggregate(0, (int mask, Definition definition) => mask | definition.Value); internal static IReadOnlyList<Definition> Definitions => definitions; internal static bool TryParseTag(string value, out UsageTagFlags tag, out string canonicalName) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected I4, but got Unknown tag = (UsageTagFlags)0; canonicalName = null; if (string.IsNullOrWhiteSpace(value) || !definitionsByName.TryGetValue(value.Trim(), out var value2)) { return false; } tag = (UsageTagFlags)(int)value2.Value; canonicalName = value2.Name; return true; } internal static bool TryParseTags(IEnumerable<string> values, out UsageTagFlags result, out List<string> canonicalNames, out string invalidValue) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected I4, but got Unknown result = (UsageTagFlags)0; canonicalNames = new List<string>(); invalidValue = null; if (values == null) { return true; } HashSet<UsageTagFlags> hashSet = new HashSet<UsageTagFlags>(); foreach (string value in values) { if (!TryParseTag(value, out var tag, out var _)) { invalidValue = value ?? "<null>"; return false; } hashSet.Add(tag); } foreach (Definition definition in definitions) { if (hashSet.Contains(definition.Value)) { result |= definition.Value; canonicalNames.Add(definition.Name); } } return true; } internal static List<string> GetNames(UsageTagFlags value) { //IL_001d: 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_0024: 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) List<string> list = new List<string>(); foreach (Definition definition in definitions) { if ((UsageTagFlags)(value & definition.Value) == definition.Value) { list.Add(definition.Name); } } return list; } internal static bool HasUnsupportedBits(UsageTagFlags value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 return (value & ~knownMask) > 0; } internal static string GetLocalizedDisplayName(Definition definition) { if (string.IsNullOrWhiteSpace(definition.DisplayNameToken)) { return definition.Name; } return (Localization.instance != null) ? Localization.instance.Localize(definition.DisplayNameToken) : definition.DisplayNameToken; } internal static string FormatForDocumentation(UsageTagFlags value) { //IL_0006: 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) string text = string.Join(", ", GetNames(value)); if (!HasUnsupportedBits(value)) { return (text.Length == 0) ? "None" : text; } return (text.Length == 0) ? "Unsupported/custom tags" : (text + ", Unsupported/custom tags"); } } }