Please disclose if your mod was created primarily 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 TorvaldsAffordablePainters v1.3.0
plugins/torvalds-painters.dll
Decompiled 6 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("torvalds-painters")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("torvalds-painters")] [assembly: AssemblyCopyright("Copyright \ufffd 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [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")] public static class MaterialManExtensions { public static PropertyContainer GetPropertyContainer(this MaterialMan materialManager, GameObject gameObject) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown int instanceID = ((Object)gameObject).GetInstanceID(); if (!materialManager.m_blocks.TryGetValue(instanceID, out var value)) { gameObject.AddComponent<MaterialManNotifier>(); value = new PropertyContainer(gameObject, materialManager.m_propertyBlock); PropertyContainer obj = value; obj.MarkDirty = (Action<PropertyContainer>)Delegate.Combine(obj.MarkDirty, new Action<PropertyContainer>(materialManager.QueuePropertyUpdate)); materialManager.m_blocks.Add(instanceID, value); } return value; } public static PropertyContainer SetValue<T>(this PropertyContainer propertyContainer, int propertyId, T value) { propertyContainer.SetValue<T>(propertyId, value); return propertyContainer; } } namespace TorvaldsPainters; public class ConfigurationManagerAttributes { public bool? IsAdminOnly { get; set; } public bool? IsAdvanced { get; set; } public int? Order { get; set; } public bool? Browsable { get; set; } public string Category { get; set; } public Action<ConfigEntryBase> CustomDrawer { get; set; } } public class PickerCloser : MonoBehaviour { public Action OnClose; private void Update() { if (ZInput.GetKeyDown((KeyCode)27, true)) { Close(); } } public void Close() { OnClose?.Invoke(); GUIManager.BlockInput(false); Object.Destroy((Object)(object)((Component)this).gameObject); } } public enum LogLevel { None, Basic, Detailed, Debug } [Flags] public enum BuildCategory { None = 0, Building = 1, Furniture = 2, Crafting = 4, Misc = 8, All = 0xF } [Flags] public enum FunctionalBucket { None = 0, Stations = 1, Production = 2, Storage = 4, Beds = 8, PortalsWard = 0x10, Lighting = 0x20, SignsStands = 0x40, Transport = 0x80, Defenses = 0x100, All = -1 } [Flags] public enum MaterialBucket { Unknown = 0, Wood = 1, Stone = 2, Metal = 4, Marble = 8, All = -1 } [BepInPlugin("cebero.TorvaldsAffordablePainters", "Torvald's Affordable Painters", "1.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class TorvaldsPainters : BaseUnityPlugin { public struct PieceAttributes { public string Prefab; public BuildCategory Category; public FunctionalBucket Functional; public MaterialBucket Material; public bool HasRenderer; public bool HasValidZNV; public bool ComfortGiving; } public const string PluginGUID = "cebero.TorvaldsAffordablePainters"; public const string PluginName = "Torvald's Affordable Painters"; public const string PluginVersion = "1.3.0"; private static ConfigEntry<string> RecipeConfig; private static ConfigEntry<bool> RequireWorkbenchConfig; private static ConfigEntry<string> DarkBrownRGBMultiplierConfig; private static ConfigEntry<string> MediumBrownRGBMultiplierConfig; private static ConfigEntry<string> NaturalWoodRGBMultiplierConfig; private static ConfigEntry<string> LightBrownRGBMultiplierConfig; private static ConfigEntry<string> PaleWoodRGBMultiplierConfig; private static ConfigEntry<string> BlackRGBMultiplierConfig; private static ConfigEntry<string> WhiteRGBMultiplierConfig; private static ConfigEntry<string> RedRGBMultiplierConfig; private static ConfigEntry<string> BlueRGBMultiplierConfig; private static ConfigEntry<string> GreenRGBMultiplierConfig; private static ConfigEntry<string> YellowRGBMultiplierConfig; private static ConfigEntry<string> OrangeRGBMultiplierConfig; private static ConfigEntry<string> PurpleRGBMultiplierConfig; private static ConfigEntry<LogLevel> LogLevelConfig; private static ConfigEntry<float> MaxPaintDistanceConfig; private static ConfigEntry<bool> RequireBuildPermissionConfig; private static ConfigEntry<BuildCategory> AllowedCategoriesConfig; private static ConfigEntry<FunctionalBucket> ExcludedFunctionalConfig; private static ConfigEntry<MaterialBucket> AllowedMaterialsConfig; private static ConfigEntry<string> WhitelistPrefabsConfig; private static ConfigEntry<string> BlacklistPrefabsConfig; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); private Harmony harmony; public static readonly Dictionary<string, Color> VikingColors = new Dictionary<string, Color>(); public static string currentSelectedColor = "Natural Wood"; public static int colorIndex = 2; internal static readonly Dictionary<int, (string color, float t)> _lastApply = new Dictionary<int, (string, float)>(); internal const float HighlightReapplyMinInterval = 0.25f; private static readonly int PaintPieceMask = LayerMask.GetMask(new string[5] { "piece", "piece_nonsolid", "Default", "Default_small", "static_solid" }); private static readonly RaycastHit[] _hitsBuf = (RaycastHit[])(object)new RaycastHit[16]; private static HashSet<string> _whitelist; private static HashSet<string> _blacklist; private static HashSet<int> _buildingCats; private static int _craftingCat; private static int _furnitureCat; private static int _miscCat; private static bool _categoriesInitialized = false; private static CustomPieceTable paintingPieceTable; public GameObject colorPickerPanel; public static TorvaldsPainters Instance { get; private set; } private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Instance = this; Logger.LogInfo((object)"\ud83c\udfa8 Torvald's Affordable Painters is loading..."); InitializeConfiguration(); InitializeColorsFromConfig(); harmony = new Harmony("cebero.TorvaldsAffordablePainters"); harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += AddCustomItems; PrefabManager.OnVanillaPrefabsAvailable += InitializeCategoryMapping; Logger.LogInfo((object)"\ud83c\udfa8 Torvald's Affordable Painters ready for business!"); } private void InitializeConfiguration() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Expected O, but got Unknown //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Expected O, but got Unknown //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Expected O, but got Unknown //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Expected O, but got Unknown //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Expected O, but got Unknown //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Expected O, but got Unknown //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Expected O, but got Unknown //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Expected O, but got Unknown //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Expected O, but got Unknown //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Expected O, but got Unknown //IL_055b: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Expected O, but got Unknown //IL_058a: Unknown result type (might be due to invalid IL or missing references) //IL_0594: Expected O, but got Unknown RecipeConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Recipe", "Materials", "Wood:10,LeatherScraps:5,Coal:1", new ConfigDescription("Recipe materials in format: Material1:Amount1,Material2:Amount2,etc.\nExamples:\n- Early game: \"Wood:10,LeatherScraps:5,Coal:1\"\n- Mid game: \"FineWood:8,Bronze:2,LeatherScraps:3\"\n- Late game: \"BlackMetal:1,Silver:2,LoxPelt:1\"\nUse exact Valheim item names (case sensitive)", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); RequireWorkbenchConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Recipe", "RequireWorkbench", true, new ConfigDescription("Whether the painting mallet requires a workbench to craft", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); DarkBrownRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.WoodTones", "DarkBrownRGBMultiplier", "0.45,0.25,0.15", new ConfigDescription("RGB multiplier values for Dark Brown wood effect (format: R,G,B with values 0.0-3.0)\nValues <1.0 darken, 1.0 = unchanged, >1.0 brighten. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); MediumBrownRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.WoodTones", "MediumBrownRGBMultiplier", "1.2,0.8,0.4", new ConfigDescription("RGB multiplier values for Medium Brown wood effect (format: R,G,B with values 0.0-3.0)\nValues <1.0 darken, 1.0 = unchanged, >1.0 brighten. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); NaturalWoodRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.WoodTones", "NaturalWoodRGBMultiplier", "1.0,1.0,1.0", new ConfigDescription("RGB multiplier values for Natural Wood - leaves texture unchanged (format: R,G,B)\n1.0,1.0,1.0 = original texture with no modifications.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); LightBrownRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.WoodTones", "LightBrownRGBMultiplier", "1.3,1.1,0.8", new ConfigDescription("RGB multiplier values for Light Brown wood effect (format: R,G,B with values 0.0-3.0)\nValues <1.0 darken, 1.0 = unchanged, >1.0 brighten. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); PaleWoodRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.WoodTones", "PaleWoodRGBMultiplier", "1.1,1.4,1.9", new ConfigDescription("RGB multiplier values for Pale Wood effect (format: R,G,B with values 0.0-3.0)\nValues <1.0 darken, 1.0 = unchanged, >1.0 brighten. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); BlackRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "BlackRGBMultiplier", "0.1,0.1,0.1", new ConfigDescription("RGB multiplier values for Black paint effect (format: R,G,B with values 0.0-3.0)\nLow values create dark colors. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); WhiteRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "WhiteRGBMultiplier", "1.55,1.75,1.95", new ConfigDescription("RGB multiplier values for White paint effect (format: R,G,B with values 0.0-3.0)\nHigh values create bright/white colors. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); RedRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "RedRGBMultiplier", "1.5,0.2,0.2", new ConfigDescription("RGB multiplier values for Red paint effect (format: R,G,B with values 0.0-3.0)\nBoost red channel, reduce green/blue for red tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); BlueRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "BlueRGBMultiplier", "0.2,0.3,1.5", new ConfigDescription("RGB multiplier values for Blue paint effect (format: R,G,B with values 0.0-3.0)\nBoost blue channel, reduce red/green for blue tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); GreenRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "GreenRGBMultiplier", "0.3,1.5,0.3", new ConfigDescription("RGB multiplier values for Green paint effect (format: R,G,B with values 0.0-3.0)\nBoost green channel, reduce red/blue for green tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); YellowRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "YellowRGBMultiplier", "1.8,1.6,0.2", new ConfigDescription("RGB multiplier values for Yellow paint effect (format: R,G,B with values 0.0-3.0)\nBoost red/green channels, reduce blue for yellow tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); OrangeRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "OrangeRGBMultiplier", "1.5,0.9,0.25", new ConfigDescription("RGB multiplier values for Orange paint effect (format: R,G,B with values 0.0-3.0)\nBoost red, moderate green, low blue for orange tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); PurpleRGBMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Colors.PaintColors", "PurpleRGBMultiplier", "1.2,0.5,1.4", new ConfigDescription("RGB multiplier values for Purple paint effect (format: R,G,B with values 0.0-3.0)\nBoost red/blue channels, reduce green for purple tint. Multiplies with base texture.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); LogLevelConfig = ((BaseUnityPlugin)this).Config.Bind<LogLevel>("Debug", "LogLevel", LogLevel.Basic, new ConfigDescription("Debug logging level: None (0), Basic (1), Detailed (2), Debug (3)\n- None: No debug logging\n- Basic: Basic operations and errors only\n- Detailed: Detailed operations and validation info\n- Debug: Everything including raycast details", (AcceptableValueBase)null, Array.Empty<object>())); MaxPaintDistanceConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Debug", "MaxPaintDistance", 8f, new ConfigDescription("Maximum distance for painting objects (meters)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); RequireBuildPermissionConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "RequireBuildPermission", true, new ConfigDescription("Require build permission to paint objects (recommended for multiplayer)", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { IsAdminOnly = true } })); AllowedCategoriesConfig = ((BaseUnityPlugin)this).Config.Bind<BuildCategory>("Filtering", "AllowedCategories", BuildCategory.Building | BuildCategory.Furniture, new ConfigDescription("Which vanilla hammer categories are paintable.\nValid flags: Building, Furniture, Crafting, Misc, All", (AcceptableValueBase)null, Array.Empty<object>())); ExcludedFunctionalConfig = ((BaseUnityPlugin)this).Config.Bind<FunctionalBucket>("Filtering", "ExcludedFunctional", FunctionalBucket.Stations | FunctionalBucket.Production | FunctionalBucket.Storage | FunctionalBucket.Beds | FunctionalBucket.PortalsWard | FunctionalBucket.Transport, new ConfigDescription("Functional groups to exclude even if their category is allowed.\nValid flags: Stations, Production, Storage, Beds, PortalsWard, Lighting, SignsStands, Transport, Defenses, All, None", (AcceptableValueBase)null, Array.Empty<object>())); AllowedMaterialsConfig = ((BaseUnityPlugin)this).Config.Bind<MaterialBucket>("Filtering", "AllowedMaterials", MaterialBucket.Wood | MaterialBucket.Stone | MaterialBucket.Marble, new ConfigDescription("Material families that are paintable.\nValid flags: Wood, Stone, Metal, Marble, All", (AcceptableValueBase)null, Array.Empty<object>())); WhitelistPrefabsConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Filtering", "WhitelistPrefabs", "", new ConfigDescription("Comma-separated prefab names to always allow painting.\nThese override all other filtering rules.\nExample: piece_chest,portal_wood", (AcceptableValueBase)null, Array.Empty<object>())); BlacklistPrefabsConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Filtering", "BlacklistPrefabs", "", new ConfigDescription("Comma-separated prefab names to always exclude from painting.\nThese override all other filtering rules (including whitelist).\nExample: piece_workbench,piece_forge", (AcceptableValueBase)null, Array.Empty<object>())); Logger.LogDebug((object)"⚙\ufe0f Configuration loaded successfully!"); RebuildNameSets(); WhitelistPrefabsConfig.SettingChanged += delegate { RebuildNameSets(); }; BlacklistPrefabsConfig.SettingChanged += delegate { RebuildNameSets(); }; DarkBrownRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; MediumBrownRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; NaturalWoodRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; LightBrownRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; PaleWoodRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; BlackRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; WhiteRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; RedRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; BlueRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; GreenRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; YellowRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; OrangeRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; PurpleRGBMultiplierConfig.SettingChanged += delegate { InitializeColorsFromConfig(); }; } private void InitializeColorsFromConfig() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00f5: 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_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) VikingColors["Dark Brown"] = ParseColorFromConfig(DarkBrownRGBMultiplierConfig.Value, new Color(0.45f, 0.25f, 0.15f)); VikingColors["Medium Brown"] = ParseColorFromConfig(MediumBrownRGBMultiplierConfig.Value, new Color(1.2f, 0.8f, 0.4f)); VikingColors["Natural Wood"] = ParseColorFromConfig(NaturalWoodRGBMultiplierConfig.Value, new Color(1f, 1f, 1f)); VikingColors["Light Brown"] = ParseColorFromConfig(LightBrownRGBMultiplierConfig.Value, new Color(1.3f, 1.1f, 0.8f)); VikingColors["Pale Wood"] = ParseColorFromConfig(PaleWoodRGBMultiplierConfig.Value, new Color(1.1f, 1.4f, 1.9f)); VikingColors["Black"] = ParseColorFromConfig(BlackRGBMultiplierConfig.Value, new Color(0.1f, 0.1f, 0.1f)); VikingColors["White"] = ParseColorFromConfig(WhiteRGBMultiplierConfig.Value, new Color(1.55f, 1.75f, 1.95f)); VikingColors["Red"] = ParseColorFromConfig(RedRGBMultiplierConfig.Value, new Color(1.5f, 0.2f, 0.2f)); VikingColors["Blue"] = ParseColorFromConfig(BlueRGBMultiplierConfig.Value, new Color(0.2f, 0.3f, 1.5f)); VikingColors["Green"] = ParseColorFromConfig(GreenRGBMultiplierConfig.Value, new Color(0.3f, 1.5f, 0.3f)); VikingColors["Yellow"] = ParseColorFromConfig(YellowRGBMultiplierConfig.Value, new Color(1.8f, 1.6f, 0.2f)); VikingColors["Orange"] = ParseColorFromConfig(OrangeRGBMultiplierConfig.Value, new Color(1.5f, 0.9f, 0.25f)); VikingColors["Purple"] = ParseColorFromConfig(PurpleRGBMultiplierConfig.Value, new Color(1.2f, 0.5f, 1.4f)); Logger.LogDebug((object)"\ud83c\udfa8 RGB multiplier values loaded from configuration!"); } private Color ParseColorFromConfig(string colorString, Color defaultColor) { //IL_009d: 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) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) try { string[] array = colorString.Split(new char[1] { ',' }); if (array.Length == 3 && float.TryParse(array[0], out var result) && float.TryParse(array[1], out var result2) && float.TryParse(array[2], out var result3)) { result = Mathf.Clamp(result, 0f, 3f); result2 = Mathf.Clamp(result2, 0f, 3f); result3 = Mathf.Clamp(result3, 0f, 3f); return new Color(result, result2, result3); } } catch (Exception ex) { Logger.LogWarning((object)("⚠\ufe0f Invalid RGB multiplier format '" + colorString + "', using default: " + ex.Message)); } return defaultColor; } private static void RebuildNameSets() { _whitelist = BuildNameSet(WhitelistPrefabsConfig.Value); _blacklist = BuildNameSet(BlacklistPrefabsConfig.Value); Logger.LogDebug((object)$"Rebuilt name sets: {_whitelist.Count} whitelist, {_blacklist.Count} blacklist"); } private static void InitializeCategoryMapping() { //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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected I4, but got Unknown if (_categoriesInitialized) { return; } try { List<PieceCategory> list = Enum.GetValues(typeof(PieceCategory)).Cast<PieceCategory>().ToList(); Logger.LogDebug((object)("Available piece categories: " + string.Join(", ", list))); _miscCat = GetCategoryByName(list, "Misc"); _craftingCat = GetCategoryByName(list, "Crafting"); _furnitureCat = GetCategoryByName(list, "Furniture"); _buildingCats = new HashSet<int>(); foreach (PieceCategory item in list) { PieceCategory current = item; string text = ((object)(PieceCategory)(ref current)).ToString(); if (text.IndexOf("Building", StringComparison.OrdinalIgnoreCase) >= 0 || text.Equals("Building", StringComparison.OrdinalIgnoreCase)) { _buildingCats.Add((int)current); } } if (_buildingCats.Count == 0) { _buildingCats.Add(0); } Logger.LogDebug((object)string.Format("Category mapping: Misc={0}, Crafting={1}, Furniture={2}, Building=[{3}]", _miscCat, _craftingCat, _furnitureCat, string.Join(",", _buildingCats))); _categoriesInitialized = true; } catch (Exception ex) { Logger.LogError((object)("Failed to initialize category mapping: " + ex.Message)); _miscCat = 0; _craftingCat = 1; _furnitureCat = 2; _buildingCats = new HashSet<int> { 3 }; _categoriesInitialized = true; } } private static int GetCategoryByName(List<PieceCategory> categories, string targetName) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected I4, but got Unknown foreach (PieceCategory category in categories) { PieceCategory current = category; if (((object)(PieceCategory)(ref current)).ToString().Equals(targetName, StringComparison.OrdinalIgnoreCase)) { return (int)current; } } return 0; } private static HashSet<string> BuildNameSet(string csv) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(csv)) { return hashSet; } string[] array = csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { hashSet.Add(text.Trim()); } return hashSet; } private static string GetPrefabNameStable(Piece piece) { ZNetView component = ((Component)piece).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { try { return component.GetPrefabName(); } catch { } } return Utils.GetPrefabName(((Component)piece).gameObject); } private static BuildCategory MapCategory(Piece piece) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown if (!_categoriesInitialized) { Logger.LogError((object)"Category mapping not initialized - using fallback"); return BuildCategory.None; } int num = (int)piece.m_category; if (_buildingCats.Contains(num)) { return BuildCategory.Building; } if (num == _craftingCat) { return BuildCategory.Crafting; } if (num == _furnitureCat) { return BuildCategory.Furniture; } if (num == _miscCat) { return BuildCategory.Misc; } Logger.LogDebug((object)$"Unknown piece category ID {num} for piece '{((Object)piece).name}'"); return BuildCategory.None; } private static FunctionalBucket DetectFunctionalBuckets(Piece piece) { GameObject gameObject = ((Component)piece).gameObject; FunctionalBucket functionalBucket = FunctionalBucket.None; if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<CraftingStation>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<StationExtension>())) { functionalBucket |= FunctionalBucket.Stations; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Smelter>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Fermenter>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<CookingStation>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Windmill>())) { functionalBucket |= FunctionalBucket.Production; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Container>())) { functionalBucket |= FunctionalBucket.Storage; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Bed>())) { functionalBucket |= FunctionalBucket.Beds; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<TeleportWorld>()) || HasWardComponent(gameObject)) { functionalBucket |= FunctionalBucket.PortalsWard; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Fireplace>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Light>())) { functionalBucket |= FunctionalBucket.Lighting; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Sign>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<ItemStand>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<ArmorStand>())) { functionalBucket |= FunctionalBucket.SignsStands; } if (Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Ship>()) || Object.op_Implicit((Object)(object)gameObject.GetComponentInChildren<Vagon>())) { functionalBucket |= FunctionalBucket.Transport; } if (MightBeDefense(piece)) { functionalBucket |= FunctionalBucket.Defenses; } return functionalBucket; static bool HasWardComponent(GameObject g) { return (Object)(object)g.GetComponentInChildren<PrivateArea>() != (Object)null; } static bool MightBeDefense(Piece p) { string prefabNameStable = GetPrefabNameStable(p); if (prefabNameStable.IndexOf("stake", StringComparison.OrdinalIgnoreCase) < 0 && prefabNameStable.IndexOf("spike", StringComparison.OrdinalIgnoreCase) < 0) { return prefabNameStable.IndexOf("ballista", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } } private static bool HasComponentNamed(GameObject go, string typeName) { MonoBehaviour[] components = go.GetComponents<MonoBehaviour>(); foreach (MonoBehaviour val in components) { if ((Object)(object)val != (Object)null) { Type type = ((object)val).GetType(); if (type != null && type.Name.Equals(typeName, StringComparison.Ordinal)) { return true; } } } return false; } private static MaterialBucket MapMaterialBucket(Piece piece) { WearNTear component = ((Component)piece).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { return ((object)(MaterialType)(ref component.m_materialType)).ToString() switch { "Wood" => MaterialBucket.Wood, "Stone" => MaterialBucket.Stone, "Iron" => MaterialBucket.Metal, "Marble" => MaterialBucket.Marble, "BlackMarble" => MaterialBucket.Marble, _ => MaterialBucket.Unknown, }; } return MaterialBucket.Unknown; } private static PieceAttributes Classify(Piece piece) { PieceAttributes result = default(PieceAttributes); result.Prefab = GetPrefabNameStable(piece); result.Category = MapCategory(piece); result.Functional = DetectFunctionalBuckets(piece); result.Material = MapMaterialBucket(piece); result.HasRenderer = (Object)(object)((Component)piece).GetComponentInChildren<MeshRenderer>() != (Object)null || (Object)(object)((Component)piece).GetComponentInChildren<SkinnedMeshRenderer>() != (Object)null; ZNetView component = ((Component)piece).GetComponent<ZNetView>(); result.HasValidZNV = component != null && component.IsValid(); result.ComfortGiving = piece.m_comfort > 0; return result; } public static bool IsPaintableByPolicy(Piece piece, Vector3 hitPos, out string reason) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) reason = ""; if ((Object)(object)piece == (Object)null) { reason = "Not a building piece"; return false; } PieceAttributes attrs = Classify(piece); BuildCategory value = AllowedCategoriesConfig.Value; FunctionalBucket value2 = ExcludedFunctionalConfig.Value; MaterialBucket value3 = AllowedMaterialsConfig.Value; Logger.LogDebug((object)$"Policy check: '{attrs.Prefab}' Category={attrs.Category} Functional={attrs.Functional} Material={attrs.Material}"); if (_blacklist.Contains(attrs.Prefab)) { reason = "Excluded by blacklist configuration"; Logger.LogDebug((object)("Policy: '" + attrs.Prefab + "' blacklisted")); return false; } if (_whitelist.Contains(attrs.Prefab)) { Logger.LogDebug((object)("Policy: '" + attrs.Prefab + "' whitelisted - allowing")); return FinalChecks(piece, attrs, hitPos, ref reason); } if ((value & attrs.Category) == 0) { reason = $"Category '{attrs.Category}' not allowed"; Logger.LogDebug((object)$"Policy: '{attrs.Prefab}' category '{attrs.Category}' not in allowed categories '{value}'"); return false; } if ((attrs.Functional & value2) != 0) { FunctionalBucket functionalBucket = attrs.Functional & value2; reason = $"Functional group excluded: {functionalBucket}"; Logger.LogDebug((object)$"Policy: '{attrs.Prefab}' has excluded functional components: {functionalBucket}"); return false; } if (attrs.Material != 0 && (value3 & attrs.Material) == 0) { reason = $"Material '{attrs.Material}' not allowed"; Logger.LogDebug((object)$"Policy: '{attrs.Prefab}' material '{attrs.Material}' not in allowed materials '{value3}'"); return false; } Logger.LogDebug((object)("Policy: '" + attrs.Prefab + "' passed all policy checks")); return FinalChecks(piece, attrs, hitPos, ref reason); } private static bool FinalChecks(Piece piece, PieceAttributes attrs, Vector3 hitPos, ref string reason) { //IL_0062: 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) if (!attrs.HasRenderer) { reason = "Object has no renderers to paint"; Logger.LogDebug((object)("FinalChecks: '" + attrs.Prefab + "' has no renderers")); return false; } if (!attrs.HasValidZNV) { reason = "Object cannot sync in multiplayer"; Logger.LogDebug((object)("FinalChecks: '" + attrs.Prefab + "' missing/invalid ZNetView")); return false; } if (RequireBuildPermissionConfig.Value && !PrivateArea.CheckAccess(hitPos, 0f, true, false)) { reason = "No build permission for this area"; Logger.LogDebug((object)$"FinalChecks: '{attrs.Prefab}' denied by PrivateArea at {hitPos}"); return false; } Logger.LogDebug((object)("FinalChecks: '" + attrs.Prefab + "' passed all final checks")); return true; } private static GameObject GetPaintableObjectAtLook(out string errorMessage, out float distance) { //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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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) errorMessage = ""; distance = 0f; if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { errorMessage = "No local player found"; Logger.LogError((object)"GetPaintableObjectAtLook: No local player found"); return null; } Camera mainCamera = Utils.GetMainCamera(); if (!Object.op_Implicit((Object)(object)mainCamera)) { errorMessage = "No main camera found"; Logger.LogError((object)"GetPaintableObjectAtLook: No main camera found"); return null; } Ray val = mainCamera.ScreenPointToRay(Input.mousePosition); Logger.LogDebug((object)$"GetPaintableObjectAtLook: Ray origin={((Ray)(ref val)).origin}, direction={((Ray)(ref val)).direction}"); float value = MaxPaintDistanceConfig.Value; Logger.LogDebug((object)"GetPaintableObjectAtLook: Using PaintPieceMask for layers: piece, piece_nonsolid, Default, Default_small, static_solid"); int num = Physics.RaycastNonAlloc(val, _hitsBuf, value, PaintPieceMask, (QueryTriggerInteraction)1); if (num <= 0) { errorMessage = "No objects found in range"; Logger.LogDebug((object)$"GetPaintableObjectAtLook: No raycast hits found (maxDistance={value})"); return null; } Logger.LogDebug((object)$"GetPaintableObjectAtLook: Found {num} raycast hits"); Array.Sort(_hitsBuf, 0, num, Comparer<RaycastHit>.Create((RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance))); for (int i = 0; i < num; i++) { RaycastHit val2 = _hitsBuf[i]; distance = ((RaycastHit)(ref val2)).distance; Logger.LogDebug((object)$"GetPaintableObjectAtLook: Hit {i}: object='{((Object)((RaycastHit)(ref val2)).collider).name}', distance={((RaycastHit)(ref val2)).distance:F2}m, layer={((Component)((RaycastHit)(ref val2)).collider).gameObject.layer} ({LayerMask.LayerToName(((Component)((RaycastHit)(ref val2)).collider).gameObject.layer)})"); Piece componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)componentInParent)) { Logger.LogDebug((object)$"GetPaintableObjectAtLook: Hit {i} '{((Object)((RaycastHit)(ref val2)).collider).name}' has no Piece component in parent"); continue; } Logger.LogDebug((object)("GetPaintableObjectAtLook: Found Piece component on '" + ((Object)componentInParent).name + "'")); if (IsPaintableByPolicy(componentInParent, ((RaycastHit)(ref val2)).point, out var reason)) { Logger.LogDebug((object)$"GetPaintableObjectAtLook: Found paintable piece '{((Object)componentInParent).name}' at {((RaycastHit)(ref val2)).distance:F2}m"); return ((Component)componentInParent).gameObject; } Logger.LogDebug((object)("GetPaintableObjectAtLook: Piece '" + ((Object)componentInParent).name + "' rejected by policy: " + reason)); errorMessage = reason; return null; } errorMessage = ((num == 1) ? "Object cannot be painted" : $"None of the {num} objects found can be painted"); Logger.LogDebug((object)("GetPaintableObjectAtLook: " + errorMessage)); return null; } private static string GetUserFriendlyErrorMessage(string technicalError) { if (string.IsNullOrEmpty(technicalError)) { return "$paint_cannot_paint"; } if (technicalError.Contains("No objects found in range")) { return "❌ No objects in range to paint"; } if (technicalError.Contains("Not a building piece")) { return "❌ Can only paint building pieces"; } if (technicalError.Contains("too far")) { return "❌ Too far away to paint"; } if (technicalError.Contains("No build permission")) { return "❌ No permission to paint here"; } if (technicalError.Contains("exclusion list")) { return "❌ This object is excluded from painting"; } if (technicalError.Contains("Functional pieces")) { return "❌ Cannot paint functional objects"; } if (technicalError.Contains("This type of object cannot be painted")) { return "❌ This object type cannot be painted"; } if (technicalError.Contains("Object has no renderers")) { return "❌ Object cannot be painted"; } if (technicalError.Contains("cannot sync in multiplayer")) { return "❌ Object not compatible with multiplayer painting"; } if (technicalError.Contains("None of the") && technicalError.Contains("objects found can be painted")) { return "❌ No paintable objects found"; } if (technicalError.StartsWith("Object '") && technicalError.Contains("cannot be painted")) { return "❌ Selected object cannot be painted"; } return "$paint_cannot_paint"; } private void ApplyRecipeFromConfig(ItemConfig itemConfig) { //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown try { string value = RecipeConfig.Value; Logger.LogDebug((object)("\ud83d\udccb Parsing recipe: " + value)); if (string.IsNullOrWhiteSpace(value)) { Logger.LogWarning((object)"⚠\ufe0f Recipe config is empty, using default recipe"); ApplyDefaultRecipe(itemConfig); return; } string[] array = value.Split(new char[1] { ',' }); int num = 0; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i].Trim(); if (string.IsNullOrWhiteSpace(text)) { continue; } string[] array3 = text.Split(new char[1] { ':' }); if (array3.Length != 2) { Logger.LogWarning((object)("⚠\ufe0f Invalid recipe format: '" + text + "' (expected Material:Amount)")); continue; } string text2 = array3[0].Trim(); if (!int.TryParse(array3[1].Trim(), out var result) || result <= 0) { Logger.LogWarning((object)("⚠\ufe0f Invalid amount for material '" + text2 + "': '" + array3[1] + "'")); } else if (ValidateMaterialName(text2)) { itemConfig.AddRequirement(new RequirementConfig(text2, result, 0, true)); num++; Logger.LogDebug((object)$"✅ Added recipe requirement: {text2} x{result}"); } else { Logger.LogWarning((object)("⚠\ufe0f Potentially invalid material name: '" + text2 + "' (added anyway - check spelling!)")); itemConfig.AddRequirement(new RequirementConfig(text2, result, 0, true)); num++; } } if (num == 0) { Logger.LogWarning((object)"⚠\ufe0f No valid materials found in recipe config, using default recipe"); ApplyDefaultRecipe(itemConfig); } else { Logger.LogDebug((object)$"\ud83c\udfa8 Successfully applied recipe with {num} materials"); } } catch (Exception ex) { Logger.LogError((object)("❌ Error parsing recipe config: " + ex.Message)); Logger.LogWarning((object)"\ud83d\udd27 Falling back to default recipe"); ApplyDefaultRecipe(itemConfig); } } private bool ValidateMaterialName(string materialName) { if (string.IsNullOrWhiteSpace(materialName)) { return false; } string[] array = new string[50] { "Wood", "Stone", "Flint", "Coal", "Resin", "LeatherScraps", "DeerHide", "BoarHide", "WolfHide", "LoxPelt", "FineWood", "CoreWood", "ElderBark", "YggdrasilWood", "Copper", "Tin", "Bronze", "Iron", "Silver", "BlackMetal", "CopperOre", "TinOre", "IronOre", "SilverOre", "BlackMetalOre", "Chitin", "Carapace", "Scale_Hide", "Crystal", "Obsidian", "Amber", "AmberPearl", "GreydwarfEye", "SurtlingCore", "AncientSeed", "WitheredBone", "TrophyDeer", "TrophyBoar", "TrophyNeck", "TrophyGreydwarf", "Feathers", "Guck", "Bloodbag", "Ooze", "Chain", "Nails", "IronNails", "LinenThread", "JuteRed", "JuteBlue" }; foreach (string b in array) { if (string.Equals(materialName, b, StringComparison.OrdinalIgnoreCase)) { return true; } } if (materialName.Length >= 2 && materialName.Length <= 50 && !materialName.Contains(":")) { return !materialName.Contains(","); } return false; } private void ApplyDefaultRecipe(ItemConfig itemConfig) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown itemConfig.AddRequirement(new RequirementConfig("Wood", 10, 0, true)); itemConfig.AddRequirement(new RequirementConfig("LeatherScraps", 5, 0, true)); itemConfig.AddRequirement(new RequirementConfig("Coal", 1, 0, true)); Logger.LogDebug((object)"\ud83d\udd27 Applied default recipe: Wood x10, LeatherScraps x5, Coal x1"); } private void AddCustomItems() { try { CreatePaintingMalletTable(); CreatePaintingMallet(); RegisterInputs(); Logger.LogInfo((object)"✅ Custom painting mallet created successfully!"); } catch (Exception ex) { Logger.LogError((object)("❌ Error creating custom items: " + ex.Message)); } } private void CreatePaintingMalletTable() { //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_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) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown PieceTableConfig val = new PieceTableConfig { UseCategories = false, UseCustomCategories = false, CustomCategories = Array.Empty<string>(), CanRemovePieces = false }; paintingPieceTable = new CustomPieceTable("_PaintTable", val); PieceConfig val2 = new PieceConfig { Name = "$item_painting_mallet", Description = "$item_painting_mallet_desc", PieceTable = "_PaintTable", Category = "Misc" }; CustomPiece val3 = new CustomPiece("PaintMode", "piece_repair", val2); PieceManager.Instance.AddPiece(val3); PieceManager.Instance.AddPieceTable(paintingPieceTable); Logger.LogDebug((object)"\ud83c\udfa8 Created piece table with default Paint Mode piece"); } private void CreatePaintingMallet() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00d4: 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) GameObject val = PrefabManager.Instance.CreateClonedPrefab("TorvaldsMallet", "Hammer"); if (!Object.op_Implicit((Object)(object)val)) { Logger.LogError((object)"Could not clone hammer for painting mallet"); return; } ItemConfig val2 = new ItemConfig { Name = "$item_painting_mallet", Description = "$item_painting_mallet_desc" }; ApplyRecipeFromConfig(val2); if (RequireWorkbenchConfig.Value) { val2.CraftingStation = "piece_workbench"; Logger.LogDebug((object)"\ud83d\udd28 Workbench requirement enabled for painting mallet"); } else { Logger.LogDebug((object)"\ud83d\udeab No crafting station required for painting mallet"); } CustomItem val3 = new CustomItem(val, true, val2); ItemManager.Instance.AddItem(val3); Logger.LogDebug((object)("\ud83c\udfaf Added mallet to ItemManager - ID: " + val3.ItemDrop.m_itemData.m_shared.m_name)); SharedData shared = val3.ItemDrop.m_itemData.m_shared; shared.m_buildPieces = paintingPieceTable.PieceTable; shared.m_itemType = (ItemType)19; shared.m_useDurability = true; shared.m_maxDurability = 200f; shared.m_durabilityPerLevel = 50f; shared.m_canBeReparied = true; shared.m_toolTier = 2; shared.m_damages = default(DamageTypes); shared.m_blockPower = 0f; shared.m_timedBlockBonus = 0f; shared.m_deflectionForce = 0f; shared.m_attack.m_attackAnimation = ""; shared.m_attack.m_attackStamina = 0f; shared.m_attack.m_attackRange = 0f; shared.m_secondaryAttack.m_attackAnimation = ""; Logger.LogDebug((object)"\ud83c\udfa8 Created proper painting mallet tool with empty piece table"); CustomizePaintingMalletAppearance(val3.ItemPrefab); AddLocalization(); } private void AddLocalization() { CustomLocalization localization = Localization; string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "item_painting_mallet", "Torvald's Painting Mallet" }, { "item_painting_mallet_desc", "A fine mallet from Torvald's Affordable Painters! Left-click to paint building pieces, right-click to select colors." }, { "paint_apply_hint", "Apply Paint" }, { "paint_select_color_hint", "Select Color" }, { "paint_applied", "\ud83c\udfa8 Painted with" }, { "paint_cannot_paint", "❌ Cannot paint this object" }, { "paint_color_picker_title", "Select Paint Color" }, { "paint_wood_stains_section", "Wood Stains" }, { "paint_colors_section", "Paint Colors" }, { "paint_close_button", "Close" } }); } internal static void OnRpcSetColor(long sender, ZDOID id, string colorName) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } GameObject val = null; if ((Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.FindInstance(id); } if ((Object)(object)val == (Object)null) { Logger.LogDebug((object)$"TP_SetColor: Instance not found for ZDOID {id}"); return; } Piece componentInParent = val.GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null) { Logger.LogDebug((object)("TP_SetColor: No Piece component found on " + ((Object)val).name)); return; } ApplyColorToPiece(componentInParent, colorName, persistToZdo: false, logOnApply: false); Logger.LogDebug((object)("TP_SetColor: Applied " + colorName + " to " + ((Object)componentInParent).name + " from RPC")); } private static Sprite LoadPngSpriteFromFile(string fileName, float ppu = 100f) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) Logger.LogDebug((object)("\ud83d\udd0d Attempting to load icon from path: " + fileName)); Sprite val = AssetUtils.LoadSpriteFromFile(fileName, new Vector2(0.5f, 0.5f)); if ((Object)(object)val != (Object)null) { string name = ((Object)val).name; Rect rect = val.rect; object arg = ((Rect)(ref rect)).width; rect = val.rect; Logger.LogDebug((object)$"✅ Successfully loaded sprite: {name} ({arg}x{((Rect)(ref rect)).height})"); } else { Logger.LogWarning((object)("❌ Failed to load sprite from: " + fileName)); } return val; } private void CustomizePaintingMalletAppearance(GameObject malletPrefab) { ItemDrop component = malletPrefab.GetComponent<ItemDrop>(); if (!((Object)(object)component != (Object)null)) { return; } SharedData shared = component.m_itemData.m_shared; string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); Logger.LogDebug((object)("Available embedded resources: " + string.Join(", ", manifestResourceNames))); Logger.LogDebug((object)$"Number of resources found: {manifestResourceNames.Length}"); Sprite val = null; string[] array = new string[4] { "mallet.png", "cebero-TorvaldsAffordablePainters/mallet.png", "torvalds-painters/mallet.png", "../mallet.png" }; foreach (string text in array) { val = LoadPngSpriteFromFile(text); if ((Object)(object)val != (Object)null) { Logger.LogInfo((object)("\ud83c\udfa8 Successfully loaded custom icon from: " + text)); break; } } if ((Object)(object)val != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val }; Logger.LogInfo((object)"\ud83c\udfa8 Applied custom icon for painting mallet"); } else { Logger.LogWarning((object)"⚠\ufe0f Custom icon not found; leaving default hammer icon."); } } public static void ApplyColorToPiece(Piece piece, string colorName, bool persistToZdo = true, bool logOnApply = true) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (!VikingColors.TryGetValue(colorName, out var value)) { return; } WearNTear component = ((Component)piece).GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component) && ((int)component.m_materialType == 1 || ((object)(MaterialType)(ref component.m_materialType)).ToString().Contains("Marble"))) { value *= 0.9f; } if ((Object)(object)MaterialMan.instance != (Object)null) { MaterialMan.instance.GetPropertyContainer(((Component)piece).gameObject).SetValue<Color>(ShaderProps._Color, value); } else { MeshRenderer[] componentsInChildren = ((Component)piece).GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer obj in componentsInChildren) { MaterialPropertyBlock val = new MaterialPropertyBlock(); val.SetColor("_Color", value); ((Renderer)obj).SetPropertyBlock(val); } } if (persistToZdo) { ZNetView component2 = ((Component)piece).GetComponent<ZNetView>(); ZDO val2 = ((component2 != null) ? component2.GetZDO() : null); if (val2 != null && !string.Equals(val2.GetString("TorvaldsPainters.Color", ""), colorName, StringComparison.Ordinal)) { val2.Set("TorvaldsPainters.Color", colorName); } } if (logOnApply) { Logger.LogDebug((object)("Applied " + colorName + " to piece " + ((Object)piece).name)); } } private void RegisterInputs() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown KeyHintManager instance = KeyHintManager.Instance; KeyHintConfig val = new KeyHintConfig(); val.Item = "TorvaldsMallet"; val.ButtonConfigs = (ButtonConfig[])(object)new ButtonConfig[2] { new ButtonConfig { Name = "Attack", HintToken = "$paint_apply_hint" }, new ButtonConfig { Name = "Block", HintToken = "$paint_select_color_hint" } }; instance.AddKeyHint(val); Logger.LogDebug((object)"\ud83c\udfa8 Registered painting mallet key hints"); } public void PaintAtLook() { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Logger.LogDebug((object)"PaintAtLook: Paint attempt started"); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Logger.LogError((object)"PaintAtLook: No local player found"); return; } string errorMessage; float distance; GameObject paintableObjectAtLook = GetPaintableObjectAtLook(out errorMessage, out distance); if ((Object)(object)paintableObjectAtLook == (Object)null) { string userFriendlyErrorMessage = GetUserFriendlyErrorMessage(errorMessage); ((Character)localPlayer).Message((MessageType)1, userFriendlyErrorMessage, 0, (Sprite)null); Logger.LogDebug((object)("PaintAtLook: Failed - " + errorMessage)); return; } Piece componentInParent = paintableObjectAtLook.GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null) { Logger.LogError((object)"PaintAtLook: Object passed validation but has no Piece component - this should not happen"); ((Character)localPlayer).Message((MessageType)1, "$paint_cannot_paint", 0, (Sprite)null); return; } try { ApplyColorToPiece(componentInParent, currentSelectedColor); ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TP_SetColor", new object[2] { component.GetZDO().m_uid, currentSelectedColor }); Logger.LogDebug((object)("Broadcasted color change for " + ((Object)componentInParent).name + " to all clients")); } string text = "\ud83c\udfa8 Painted " + ((Object)componentInParent).name + " with " + currentSelectedColor + "!"; ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null); Logger.LogInfo((object)("\ud83c\udfa8 Painted '" + ((Object)componentInParent).name + "' with '" + currentSelectedColor + "'")); } catch (Exception ex) { Logger.LogError((object)("PaintAtLook: Failed to apply color to '" + ((Object)componentInParent).name + "': " + ex.Message)); ((Character)localPlayer).Message((MessageType)1, "Failed to paint object", 0, (Sprite)null); } } public void ShowColorPicker() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Expected O, but got Unknown if ((Object)(object)colorPickerPanel != (Object)null) { CloseColorPicker(); return; } colorPickerPanel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 650f, 400f, false); GUIManager.Instance.CreateText(Localization.TryTranslate("$paint_color_picker_title"), colorPickerPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -30f), GUIManager.Instance.Norse, 28, GUIManager.Instance.ValheimOrange, true, Color.black, 550f, 40f, false); CreateSimpleSection(Localization.TryTranslate("$paint_wood_stains_section"), new string[5] { "Dark Brown", "Medium Brown", "Natural Wood", "Light Brown", "Pale Wood" }, -180f); CreatePaintColorSection(Localization.TryTranslate("$paint_colors_section"), new string[8] { "Black", "White", "Red", "Blue", "Green", "Yellow", "Orange", "Purple" }, 80f); ((UnityEvent)GUIManager.Instance.CreateButton(Localization.TryTranslate("$paint_close_button"), colorPickerPanel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 30f), 100f, 30f).GetComponent<Button>().onClick).AddListener(new UnityAction(CloseColorPicker)); colorPickerPanel.AddComponent<PickerCloser>().OnClose = CloseColorPicker; GUIManager.BlockInput(true); } private void CreateSimpleSection(string sectionTitle, string[] colorNames, float xOffset) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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) //IL_00a7: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown GUIManager.Instance.CreateText(sectionTitle, colorPickerPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(xOffset, 120f), GUIManager.Instance.AveriaSerifBold, 18, GUIManager.Instance.ValheimOrange, true, Color.black, 200f, 25f, false); for (int i = 0; i < colorNames.Length; i++) { GameObject obj = GUIManager.Instance.CreateButton(colorNames[i], colorPickerPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(xOffset, 80f - (float)i * 35f), 160f, 30f); string colorName = colorNames[i]; ((UnityEvent)obj.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { SelectColor(colorName); }); } } private void CreatePaintColorSection(string sectionTitle, string[] colorNames, float xOffset) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown GUIManager.Instance.CreateText(sectionTitle, colorPickerPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(xOffset + 80f, 120f), GUIManager.Instance.AveriaSerifBold, 18, GUIManager.Instance.ValheimOrange, true, Color.black, 200f, 25f, false); int num = 4; for (int i = 0; i < colorNames.Length; i++) { int num2 = i / num; int num3 = i % num; float num4 = xOffset - 40f + (float)num2 * 160f; float num5 = 80f - (float)num3 * 35f; GameObject obj = GUIManager.Instance.CreateButton(colorNames[i], colorPickerPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(num4, num5), 150f, 30f); string colorName = colorNames[i]; ((UnityEvent)obj.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { SelectColor(colorName); }); } } private void SelectColor(string colorName) { currentSelectedColor = colorName; colorIndex = VikingColors.Keys.ToList().IndexOf(colorName); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, "\ud83c\udfa8 Selected: " + colorName, 0, (Sprite)null); } Logger.LogDebug((object)("\ud83c\udfa8 Color selected from GUI: " + colorName)); CloseColorPicker(); } public void CloseColorPicker() { if ((Object)(object)colorPickerPanel != (Object)null) { Object.Destroy((Object)(object)colorPickerPanel); colorPickerPanel = null; } GUIManager.BlockInput(false); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } PrefabManager.OnVanillaPrefabsAvailable -= AddCustomItems; if ((Object)(object)colorPickerPanel != (Object)null) { CloseColorPicker(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } [HarmonyPatch(typeof(Player), "PlayerAttackInput")] public static class PlayerAttackInputPatch { private static bool Prefix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !((Character)__instance).TakeInput()) { return true; } if (((Humanoid)__instance).GetRightItem()?.m_shared.m_name != "$item_painting_mallet") { return true; } if ((Object)(object)TorvaldsPainters.Instance == (Object)null) { return false; } if ((Object)(object)TorvaldsPainters.Instance.colorPickerPanel != (Object)null) { if (ZInput.GetButtonDown("Block") || ZInput.GetButtonDown("JoyButtonB")) { TorvaldsPainters.Instance.CloseColorPicker(); } return false; } if (ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyButtonX")) { TorvaldsPainters.Instance.PaintAtLook(); } else if (ZInput.GetButtonDown("Block") || ZInput.GetButtonDown("JoyButtonB")) { TorvaldsPainters.Instance.ShowColorPicker(); } return false; } } [HarmonyPatch(typeof(Player), "UpdateBuildGuiInput")] public static class PlayerUpdateBuildGuiInputPatch { private static bool Prefix(Player __instance) { if (((Humanoid)__instance).GetRightItem()?.m_shared.m_name == "$item_painting_mallet") { return false; } return true; } } [HarmonyPatch(typeof(Player), "Repair")] public static class PlayerRepairPatch { private static bool Prefix(Player __instance) { if (((Humanoid)__instance).GetRightItem()?.m_shared.m_name == "$item_painting_mallet") { return false; } return true; } } [HarmonyPatch(typeof(Game), "Start")] public static class GameStartPatch { private static void Postfix() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<ZDOID, string>("TP_SetColor", (Action<long, ZDOID, string>)TorvaldsPainters.OnRpcSetColor); Logger.LogDebug((object)"\ud83d\udd17 Multiplayer color sync ready"); } } } [HarmonyPatch(typeof(Piece), "Awake")] public static class PieceAwakePatch { private static void Postfix(Piece __instance) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { string @string = component.GetZDO().GetString("TorvaldsPainters.Color", ""); if (!string.IsNullOrEmpty(@string)) { TorvaldsPainters.ApplyColorToPiece(__instance, @string, persistToZdo: false, logOnApply: false); } } } } [HarmonyPatch(typeof(WearNTear), "ResetHighlight")] public static class WearNTearResetHighlightPatch { private static void Postfix(WearNTear __instance) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } Piece component = ((Component)__instance).GetComponent<Piece>(); ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || component2 == null || !component2.IsValid()) { return; } string @string = component2.GetZDO().GetString("TorvaldsPainters.Color", ""); if (!string.IsNullOrEmpty(@string)) { int instanceID = ((Object)((Component)component).gameObject).GetInstanceID(); float time = Time.time; if (!TorvaldsPainters._lastApply.TryGetValue(instanceID, out (string, float) value) || !(value.Item1 == @string) || !(time - value.Item2 < 0.25f)) { TorvaldsPainters.ApplyColorToPiece(component, @string, persistToZdo: false, logOnApply: false); TorvaldsPainters._lastApply[instanceID] = (@string, time); } } } }