Decompiled source of DrakesRenameit v1.1.6

DrakesRenameit.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DrakeModsLibs.API;
using DrakeModsLibs.Input;
using DrakeModsLibs.Sync;
using DrakeModsLibs.Tags;
using DrakeModsLibs.UI;
using DrakeRenameit.API;
using DrakeRenameit.Ext.UI;
using DrakeRenameit.Integration;
using DrakeRenameit.ModText;
using DrakeRenameit.Permissions;
using DrakeRenameit.UI;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("DrakeRenameit")]
[assembly: AssemblyDescription("Manage your doors and chests better")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DrakesWorkshop")]
[assembly: AssemblyProduct("DrakeRenameit")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5DF97E86-BF46-46C5-894F-6B2D80EA6645")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DrakeRenameit
{
	public static class MenuKeyBinding
	{
		public static bool IsHeld(string? binding)
		{
			return MenuKeyBinding.IsHeld(binding);
		}

		public static string FormatForDisplay(string? binding)
		{
			return MenuKeyBinding.FormatForDisplay(binding, RenameItLocalization.T("menu_key_fallback"));
		}
	}
	public static class RenameitConfig
	{
		private const int ExpectedSyncedEntryCount = 49;

		private const string SectionAdmin = "01 Admin";

		private const string SectionFeatures = "02 Features";

		private const string SectionExclusions = "03 Exclusions";

		private const string SectionCraftedBy = "04 CraftedBy";

		private const string SectionGeneral = "05 General";

		private const string SectionStacks = "06 Stacks";

		private const string SectionUnlockCost = "07 UnlockCost";

		private const string SectionLimits = "08 Limits";

		private const string SectionModifiers = "09 Modifiers";

		private const string SectionPaper = "10 Paper";

		private const string SectionUI = "11 UI-NotSynced";

		private const string DisplayAdmin = "Admin";

		private const string DisplayFeatures = "Features";

		private const string DisplayExclusions = "Exclusions";

		private const string DisplayCraftedBy = "Crafted by";

		private const string DisplayGeneral = "General";

		private const string DisplayStacks = "Stacks";

		private const string DisplayUnlockCost = "Unlock cost";

		private const string DisplayLimits = "Limits";

		private const string DisplayModifiers = "Modifiers";

		private const string DisplayUI = "UI-NotSynced";

		private const string DisplayPaper = "Paper";

		private static readonly DrakeConfigSync _drakeConfigSync = DrakeConfigSync.Create("DrakesRenameit", "DrakesRenameit", "1.1.6", (string)null);

		private static ConfigEntry<bool> _lockToOwner = null;

		private static ConfigEntry<bool> _rewriteDescriptionsEnable = null;

		private static ConfigEntry<bool> _RenameEnable = null;

		private static ConfigEntry<bool> _nameClaimsOwner = null;

		private static ConfigEntry<bool> _allowAdminOverride = null;

		private static ConfigEntry<bool> _allowRenameUnownedItems = null;

		private static ConfigEntry<int> _nameCharLimit = null;

		private static ConfigEntry<int> _descCharLimit = null;

		private static ConfigEntry<int> _craftedByCharLimit = null;

		private static ConfigEntry<string> _vipList = null;

		private static ConfigEntry<bool> _configLock = null;

		private static ConfigEntry<string> _menuHintColor = null;

		private static ConfigEntry<string> _excludedNames = null;

		private static ConfigEntry<string> _excludedCategory = null;

		private static ConfigEntry<string> _renameAllowlist = null;

		private static ConfigEntry<bool> _excludeStacks = null;

		private static ConfigEntry<bool> _vipOnlyOverride = null;

		private static ConfigEntry<bool> _showDenialUi = null;

		private static ConfigEntry<bool> _showReason = null;

		private static ConfigEntry<bool> _separateStacks = null;

		private static ConfigEntry<bool> _separateStacksHardLock = null;

		private static ConfigEntry<bool> _craftedByLabelEnabled = null;

		private static ConfigEntry<bool> _craftedByLabelCustomizable = null;

		private static ConfigEntry<string> _craftedByAllowedLabels = null;

		private static ConfigEntry<string> _menuOpenModifier = null;

		private static ConfigEntry<bool> _logSpam = null;

		private static ConfigEntry<string> _serverDefaultMenuOpenModifier = null;

		private static ConfigEntry<bool> _unlockCostEnabled = null;

		private static ConfigEntry<string> _unlockCost = null;

		private static ConfigEntry<bool> _showItemStandItemNameWhenNoAccess = null;

		private static ConfigEntry<bool> _durabilityModifierEnabled = null;

		private static ConfigEntry<string> _durabilityUnbrokenLabel = null;

		private static ConfigEntry<string> _durabilityBrokenLabel = null;

		private static ConfigEntry<string> _durabilityTierModifiers = null;

		private static ConfigEntry<bool> _paperEnabled = null;

		private static ConfigEntry<string> _paperName = null;

		private static ConfigEntry<string> _paperDescription = null;

		private static ConfigEntry<string> _paperCost = null;

		private static ConfigEntry<string> _paperCraftingStation = null;

		private static ConfigEntry<float> _paperScale = null;

		private static ConfigEntry<string> _paperItemType = null;

		private static ConfigEntry<int> _blankPaperStackSize = null;

		private static ConfigEntry<string> _writtenPaperName = null;

		private static ConfigEntry<string> _writtenPaperDescription = null;

		private static ConfigEntry<bool> _writtenPaperIgnoresRestrictions = null;

		private static ConfigEntry<bool> _publicRewriteEnabled = null;

		private static ConfigEntry<bool> _paperPlaceEnabled = null;

		private static ConfigEntry<bool> _paperTakePublicEnabled = null;

		private static ConfigEntry<bool> _verticalPaperPlaceable = null;

		private static ConfigEntry<bool> _horizontalPaperPlaceable = null;

		private static ConfigEntry<bool> _stackPaperPlaceable = null;

		private static ConfigEntry<string> _blankPaperPlaceOrientation = null;

		internal const string BlankPlaceVerticalOnly = "Vertical Only";

		internal const string BlankPlaceHorizontalOnly = "Horizontal Only";

		internal const string BlankPlaceBoth = "Both";

		internal static ManualLogSource? Log { get; set; }

		public static bool LockToOwner => _lockToOwner.Value;

		public static int DescCharLimit => _descCharLimit.Value;

		public static bool NameClaimsOwner => _nameClaimsOwner.Value;

		public static bool RewriteDescriptionsEnabled => _rewriteDescriptionsEnable.Value;

		public static bool RenameEnabled => _RenameEnable.Value;

		public static bool CraftedByLabelEnabled => _craftedByLabelEnabled.Value;

		public static bool CraftedByLabelCustomizable => _craftedByLabelCustomizable.Value;

		public static string CraftedByAllowedLabels => _craftedByAllowedLabels.Value;

		public static bool AllowRenameUnownedItems => _allowRenameUnownedItems.Value;

		public static bool AllowAdminOverride => _allowAdminOverride.Value;

		public static int NameCharLimit => _nameCharLimit.Value;

		public static int CraftedByCharLimit => _craftedByCharLimit.Value;

		public static string VipList => _vipList.Value;

		public static bool LockSyncedConfig => _configLock.Value;

		public static string MenuHintColor => _menuHintColor.Value;

		public static string ExcludedNames => _excludedNames.Value;

		public static string ExcludedCategory => _excludedCategory.Value;

		public static string RenameAllowlist => _renameAllowlist.Value;

		public static bool ExcludeStacks => _excludeStacks.Value;

		public static bool VipOnlyOverride => _vipOnlyOverride.Value;

		public static bool ShowDenialUi => _showDenialUi.Value;

		public static bool ShowReason => _showReason.Value;

		public static bool SeparateStacks => _separateStacks.Value;

		public static bool SeparateStacksHardLock => _separateStacksHardLock.Value;

		public static string ServerDefaultMenuOpenModifier => _serverDefaultMenuOpenModifier.Value;

		public static string MenuOpenModifier
		{
			get
			{
				if (!string.IsNullOrWhiteSpace(_menuOpenModifier.Value))
				{
					return _menuOpenModifier.Value;
				}
				return _serverDefaultMenuOpenModifier.Value;
			}
		}

		public static bool LogSpam
		{
			get
			{
				if (_logSpam != null)
				{
					return _logSpam.Value;
				}
				return false;
			}
		}

		public static bool UnlockCostEnabled => _unlockCostEnabled.Value;

		public static string UnlockCost => _unlockCost.Value;

		public static bool ShowItemStandItemNameWhenNoAccess => _showItemStandItemNameWhenNoAccess.Value;

		public static bool DurabilityModifierEnabled => _durabilityModifierEnabled.Value;

		public static string DurabilityUnbrokenLabel => _durabilityUnbrokenLabel.Value;

		public static string DurabilityBrokenLabel => _durabilityBrokenLabel.Value;

		public static string DurabilityTierModifiers => _durabilityTierModifiers.Value;

		public static bool PaperEnabled => _paperEnabled.Value;

		public static string PaperName => _paperName.Value;

		public static string PaperDescription => _paperDescription.Value;

		public static string PaperCost => _paperCost.Value;

		public static string PaperCraftingStation => _paperCraftingStation.Value;

		public static float PaperScale => Math.Max(0.25f, Math.Min(5f, _paperScale.Value));

		public static string PaperItemType => _paperItemType.Value;

		public static int BlankPaperStackSize => Math.Max(1, _blankPaperStackSize.Value);

		public static string WrittenPaperName => _writtenPaperName.Value;

		public static string WrittenPaperDescription => _writtenPaperDescription.Value;

		public static bool WrittenPaperIgnoresRestrictions => _writtenPaperIgnoresRestrictions.Value;

		public static bool PublicRewriteEnabled => _publicRewriteEnabled.Value;

		public static bool PaperPlaceEnabled => _paperPlaceEnabled.Value;

		public static bool PaperTakePublicEnabled => _paperTakePublicEnabled.Value;

		public static bool VerticalPaperPlaceable => _verticalPaperPlaceable.Value;

		public static bool HorizontalPaperPlaceable => _horizontalPaperPlaceable.Value;

		public static bool StackPaperPlaceable => _stackPaperPlaceable.Value;

		public static string BlankPaperPlaceOrientation => NormalizeBlankPlaceOrientation(_blankPaperPlaceOrientation?.Value);

		public static bool BlankPaperPlaceVertical
		{
			get
			{
				string blankPaperPlaceOrientation = BlankPaperPlaceOrientation;
				if (blankPaperPlaceOrientation == "Vertical Only" || blankPaperPlaceOrientation == "Both")
				{
					return true;
				}
				return false;
			}
		}

		public static bool BlankPaperPlaceHorizontal
		{
			get
			{
				string blankPaperPlaceOrientation = BlankPaperPlaceOrientation;
				if (blankPaperPlaceOrientation == "Horizontal Only" || blankPaperPlaceOrientation == "Both")
				{
					return true;
				}
				return false;
			}
		}

		public static bool BlankPaperPlaceCanToggle => BlankPaperPlaceOrientation == "Both";

		internal static event Action? HammerPaperPlaceableChanged;

		internal static void SetSyncedVipList(string commaSeparatedEntries)
		{
			if (_vipList != null)
			{
				_vipList.Value = commaSeparatedEntries ?? "";
			}
		}

		internal static void VerboseDebug(string message)
		{
			if (LogSpam)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogDebug((object)message);
				}
			}
		}

		internal static void VerboseInfo(string message)
		{
			if (LogSpam)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogInfo((object)message);
				}
			}
		}

		internal static void VerboseWarning(string message)
		{
			if (LogSpam)
			{
				ManualLogSource? log = Log;
				if (log != null)
				{
					log.LogWarning((object)message);
				}
			}
		}

		internal static string NormalizeBlankPlaceOrientation(string? raw)
		{
			if (string.IsNullOrWhiteSpace(raw))
			{
				return "Both";
			}
			string text = raw.Trim();
			if (text.Equals("Vertical Only", StringComparison.OrdinalIgnoreCase) || text.Equals("VerticalOnly", StringComparison.OrdinalIgnoreCase) || text.Equals("Vertical", StringComparison.OrdinalIgnoreCase))
			{
				return "Vertical Only";
			}
			if (text.Equals("Horizontal Only", StringComparison.OrdinalIgnoreCase) || text.Equals("HorizontalOnly", StringComparison.OrdinalIgnoreCase) || text.Equals("Horizontal", StringComparison.OrdinalIgnoreCase))
			{
				return "Horizontal Only";
			}
			return "Both";
		}

		public static List<string> GetCraftedByAllowedLabelsList()
		{
			string value = _craftedByAllowedLabels.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return new List<string> { "Crafted By", "Belongs To", "Return to" };
			}
			List<string> list = (from s in value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim() into s
				where s.Length > 0
				select s).ToList();
			if (list.Count == 0)
			{
				return new List<string> { "Crafted By", "Belongs To", "Return to" };
			}
			List<string> list2 = new List<string>();
			foreach (string p in list)
			{
				if (!list2.Exists((string x) => string.Equals(x, p, StringComparison.Ordinal)))
				{
					list2.Add(p);
				}
			}
			return list2;
		}

		public static void Bind(ConfigFile config)
		{
			_allowAdminOverride = _drakeConfigSync.BindSynced<bool>(config, "01 Admin", "Admin", "AllowAdminOverride", true, "If enabled, Valheim server admins and VIP list / API users may bypass ownership, exclusions, and most per-item blocks (still respects Features toggles unless elevated logic applies). Does NOT grant Valheim admin commands.");
			_configLock = _drakeConfigSync.BindSynced<bool>(config, "01 Admin", "Admin", "LockSyncedConfig", true, "When true, only Valheim server admins can change synced gameplay settings (sections 01–09 and 11 Paper). Clients cannot push config edits to the server. UI section (10) stays per-client. Strongly recommended for public servers.");
			_drakeConfigSync.AddLockingConfigEntry(_configLock);
			_vipList = _drakeConfigSync.BindSynced<string>(config, "01 Admin", "Admin", "VipList", "", "Comma- or semicolon-separated character names and/or platform user IDs (Steam ID / GetPlayerID — same as adminlist.txt IDs). Server-synced cfg only. VIP list API results are kept in memory separately and are not written here. Grants mod bypass only, not Valheim admin.");
			_vipOnlyOverride = _drakeConfigSync.BindSynced<bool>(config, "01 Admin", "Admin", "VipOnlyOverride", false, "If true (and AdminOverride is on), only VIP list / AddVIP API users are treated as elevated for bypassing rules—Valheim server admin is NOT. Useful for testing VIP behavior locally. If false, Valheim admin OR VIP is elevated.");
			_RenameEnable = _drakeConfigSync.BindSynced<bool>(config, "02 Features", "Features", "RenameEnabled", true, "If enabled, players may edit item display names (subject to all other rules). Turn off to freeze names on new edits while leaving descriptions/crafted-by alone.");
			_rewriteDescriptionsEnable = _drakeConfigSync.BindSynced<bool>(config, "02 Features", "Features", "RewriteDescriptionsEnabled", true, "If enabled, players may edit item descriptions. Turn off to pre-place lore text and block further description changes.");
			_craftedByLabelEnabled = _drakeConfigSync.BindSynced<bool>(config, "02 Features", "Features", "CraftedByLabelEnabled", true, "If true, players may set a display-only override for the crafted-by line (real crafter id/name unchanged).");
			_publicRewriteEnabled = _drakeConfigSync.BindSynced<bool>(config, "02 Features", "Features", "PublicRewriteEnabled", true, "If true, items flagged Public (Drake_PublicRewrite) allow non-owners to edit name and description. Crafted-by is never opened by this flag. Default on.");
			_excludedNames = _drakeConfigSync.BindSynced<string>(config, "03 Exclusions", "Exclusions", "ExcludedNames", "", "Comma-separated entries: Jotunn Token ($item_...) OR Item spawn name (AxeStone) OR English display name. Admins/VIP ignore when AdminOverride is on. See ExcludedCategory and RenameAllowlist.");
			_excludedCategory = _drakeConfigSync.BindSynced<string>(config, "03 Exclusions", "Exclusions", "ExcludedCategory", "", "Comma-separated category tokens (non-elevated players). Examples: Swords,Armor,Material,Bows. Reference file: BepInEx/config/<mod GUID>/ExcludedCategoryReference.txt on first run or version change.");
			_renameAllowlist = _drakeConfigSync.BindSynced<string>(config, "03 Exclusions", "Exclusions", "RenameAllowlist", "", "Comma-separated entries (same format as ExcludedNames). When RenameEnabled / RewriteDescriptionsEnabled are ON, these items bypass ExcludedNames, ExcludedCategory, ExcludeStacks, and the unowned (AllowRenameUnownedItems) rule. Does NOT bypass global Features toggles when those are off. Does not bypass LockToOwner.");
			_craftedByLabelCustomizable = _drakeConfigSync.BindSynced<bool>(config, "04 CraftedBy", "Crafted by", "LabelCustomizable", true, "If true, players who can edit crafted-by may choose a tooltip line label from AllowedLabels. If false, the label picker is greyed out for normal players (default line only) while admins/VIPs can still change it.");
			_craftedByAllowedLabels = _drakeConfigSync.BindSynced<string>(config, "04 CraftedBy", "Crafted by", "AllowedLabels", "Crafted By, Belongs To, Return to", "Comma- or semicolon-separated labels shown before the crafter name (e.g. “Belongs To: Name”). The first entry is the default (vanilla localized crafted-by line when that option is selected).");
			_lockToOwner = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "LockToOwner", true, "If true, only the crafter/owner can rename the item, edit its description, or crafted-by display. Items with no crafter (unowned stacks) are not locked until someone claims them (NameClaimsOwner) or the item is crafted.");
			_nameClaimsOwner = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "NameClaimsOwner", true, "If true, renaming an unowned item assigns ownership to the renamer. Used with LockToOwner: the first successful rename on an unclaimed stack makes you the owner.");
			_allowRenameUnownedItems = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "AllowRenameUnownedItems", true, "If true, unowned items may be renamed or given a description/crafted-by display. Unowned means no crafter id and no crafter name — e.g. picked up from the world, spawned (console/admin), loot drops, and uncrafted resource stacks. When false, those stacks are blocked unless on RenameAllowlist. Not the same as ExcludedCategory Material (that blocks by item type even when crafted). When false, NameClaimsOwner cannot claim those stacks.");
			_showDenialUi = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "ShowDenialUi", true, "If true, access denials (not your item, excluded, rename disabled, etc.) show a red strikethrough menu hint, denial lines in tooltips, and a center message when modifier+right-click cannot open the menu. If false, those access cues are hidden. Unlock-cost, not-in-inventory, and empty-field errors are unchanged. Server-synced.");
			_showReason = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "ShowReason", false, "If true, denial text (when ShowDenialUi is on) uses specific reasons (ownership, exclusion, unowned, etc.). If false, generic messages only. Has no effect when ShowDenialUi is off. Server-synced.");
			_showItemStandItemNameWhenNoAccess = _drakeConfigSync.BindSynced<bool>(config, "05 General", "General", "ShowItemStandItemNameWhenNoAccess", true, "If true, item stands inside warded/private areas still show 'no access' but also append the stand's current item name to the hover label (display only; permissions unchanged).");
			_serverDefaultMenuOpenModifier = _drakeConfigSync.BindSynced<string>(config, "05 General", "General", "ServerDefaultMenuOpenModifier", "Shift", "Default keys for opening the Renameit menu when a player's local MenuOpenModifier (section 11 UI-NotSynced) is empty. Set on the server/modpack for compatibility (e.g. None if another mod uses Shift). Non-empty local MenuOpenModifier always overrides on that client.");
			_separateStacks = _drakeConfigSync.BindSynced<bool>(config, "06 Stacks", "Stacks", "SeparateStacks", true, "If true, stacks only combine when Drake custom name, description, and crafted-by display match (same identity). Renamed or customized stacks no longer absorb mismatched pickups automatically.");
			_separateStacksHardLock = _drakeConfigSync.BindSynced<bool>(config, "06 Stacks", "Stacks", "SeparateStacksHardLock", false, "Only applies when SeparateStacks is on. If true, mismatched stacks never merge — including manual drags. If false, auto pickup still will not combine mismatched stacks, but you can drag one stack onto another to merge immediately (target stack keeps its custom data).");
			_excludeStacks = _drakeConfigSync.BindSynced<bool>(config, "06 Stacks", "Stacks", "ExcludeStacks", false, "When true, non-elevated players cannot rename, change descriptions, or edit crafted-by on stackable vanilla items (m_maxStackSize > 1). Admins/VIPs override when AllowAdminOverride is on. Items on RenameAllowlist bypass this. Does not change SeparateStacks merge behavior.");
			_unlockCostEnabled = _drakeConfigSync.BindSynced<bool>(config, "07 UnlockCost", "Unlock cost", "UnlockCostEnabled", false, "If true, each item stack must be unlocked once (pay UnlockCost from your inventory) before rename, description, or crafted-by edits apply. Invalid/empty UnlockCost is ignored. Elevated players skip the cost when AdminOverride applies.");
			_unlockCost = _drakeConfigSync.BindSynced<string>(config, "07 UnlockCost", "Unlock cost", "UnlockCost", "Coins:5", "Comma or semicolon separated: PrefabName:amount (e.g. Coins:4, Coal:10) or $item_token:amount. Uses player inventory. Paid once per stack via the Unlock button in the action menu.");
			_nameCharLimit = _drakeConfigSync.BindSynced<int>(config, "08 Limits", "Limits", "NameCharacterLimit", 50, "Max characters for rename text (count <color=> tag codes toward the limit).");
			_craftedByCharLimit = _drakeConfigSync.BindSynced<int>(config, "08 Limits", "Limits", "CraftedByCharLimit", 50, "Max characters for crafted-by display name (count rich-text tags toward the limit).");
			_descCharLimit = _drakeConfigSync.BindSynced<int>(config, "08 Limits", "Limits", "DescriptionCharacterLimit", 1000, "Max characters for item description (count rich-text tags toward the limit).");
			_durabilityModifierEnabled = _drakeConfigSync.BindSynced<bool>(config, "09 Modifiers", "Modifiers", "DurabilityModifierEnabled", false, "If true, prepends a durability wear label (Pristine / tiers / Broken) in front of the item name everywhere Drake builds display names — only for forge-repair gear and tools (m_useDurability), not spoilage timers. Does not change stored rename text.");
			_durabilityUnbrokenLabel = _drakeConfigSync.BindSynced<string>(config, "09 Modifiers", "Modifiers", "DurabilityUnbrokenLabel", "Pristine", "Prepended at full durability (100%). Empty = no label when pristine. Rich-text color tags allowed.");
			_durabilityBrokenLabel = _drakeConfigSync.BindSynced<string>(config, "09 Modifiers", "Modifiers", "DurabilityBrokenLabel", "<#f00>Broken</color>", "Prepended only when durability is 0 (item is broken in-game and must be repaired). Not used for worn but usable gear. Empty = no label when broken.");
			_durabilityTierModifiers = _drakeConfigSync.BindSynced<string>(config, "09 Modifiers", "Modifiers", "DurabilityTierModifiers", "{<#c50>Rusty</color>,0.4},{<#888>Worn</color>,0.6},{<#aaa>Tarnished</color>,0.8}", "Wear bands between broken and pristine: {Name,fraction} or {Name,percent}. Each applies when current/max is at or below that value; lowest matching band wins. Supports <color> tags; terminate with </color> unless you add a high threshold near 1.");
			_menuHintColor = _drakeConfigSync.BindClientOnly<string>(config, "11 UI-NotSynced", "UI-NotSynced", "MenuHintColor", "yellow", "Color for the inventory tooltip hint (Modifier + Right Click). Unity color names or hex (#fff / #ffffff). Per-client only.");
			_menuOpenModifier = _drakeConfigSync.BindClientOnly<string>(config, "11 UI-NotSynced", "UI-NotSynced", "MenuOpenModifier", "", "Optional per-client override for menu keys. Leave empty to use ServerDefaultMenuOpenModifier from the server. When set, always wins on this machine. Examples: Shift, Ctrl, Alt, Shift+Alt, F1, None. Combine with + , or &.");
			_logSpam = _drakeConfigSync.BindClientOnly<bool>(config, "11 UI-NotSynced", "UI-NotSynced", "LogSpam", false, "If true, writes verbose BepInEx logs on this client (permission allow/deny traces, localization load details, unlock-cost parse notes). Does not sync to the server. Leave off unless debugging.");
			_paperEnabled = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "PaperEnabled", true, "If true, players can craft the Piece of Paper item (blank rename vessel). The prefab is always registered so clients stay in sync; this only toggles craftability.");
			_paperName = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "PaperName", "Piece of Paper", "Default display name for newly crafted / unrenamed Piece of Paper. Server-synced. Updates the localization token used by the item.");
			_paperDescription = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "PaperDescription", "A blank piece of paper you can write on. Renaming or rewriting the description uses one sheet and creates a Written Page.", "Default description for blank Piece of Paper. Server-synced.");
			_paperCost = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "PaperCost", "Wood:1,Coal:1", "Comma or semicolon separated recipe ingredients: PrefabName:amount (e.g. Wood:1,Coal:1). Same format as UnlockCost. Applied when the item is registered (menu/world load).");
			_paperCraftingStation = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "PaperCraftingStation", "", "Crafting station prefab for Piece of Paper (e.g. piece_workbench). Leave empty to craft anywhere from the inventory craft list.");
			_paperScale = _drakeConfigSync.BindSynced<float>(config, "10 Paper", "Paper", "PaperScale", 1.5f, "World size multiplier for blank/written paper sheets and hammer décor (1 = US Letter ~8.5×11 inches in meters). Default 1.5 (50% larger). Applied when items/pieces register; restart world/menu to re-apply.");
			_paperItemType = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "PaperItemType", "Material", "Vanilla item category for Piece of Paper / Written Page: Material or Misc. Applied when the item is registered. ExcludedCategory can also use alias 'Paper' to target these items.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Material", "Misc" }));
			_blankPaperStackSize = _drakeConfigSync.BindSynced<int>(config, "10 Paper", "Paper", "BlankPaperStackSize", 50, "Max stack size for blank Piece of Paper. Written Page is always stack size 1. Applied when items are registered.");
			_writtenPaperName = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "WrittenPaperName", "Written Page", "Default display name for Written Page (before a custom name). Server-synced.");
			_writtenPaperDescription = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "WrittenPaperDescription", "A page with writing on it.", "Default description for Written Page when no custom description is set. Server-synced.");
			_writtenPaperIgnoresRestrictions = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "WrittenPaperIgnoresRestrictions", false, "If true, Written Page name/description ignore RenameEnabled/RewriteDescriptions off, exclusions, and ExcludeStacks for non-elevated players. Ownership and Public rewrite rules still apply. Owner always may edit written pages regardless.");
			_paperPlaceEnabled = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "PaperPlaceEnabled", true, "If true, Written Page in the hotbar can open place-mode to pin parchment in the world (vertical/horizontal). Blank paper Use opens rename instead.");
			_paperTakePublicEnabled = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "PaperTakePublicEnabled", true, "If true, the page's creator or an admin override (inside a ward that already allows them) can press Shift+Use to let anyone take it off the wall. Shift+Use again makes it private. Other players cannot flip this. Visitors still cannot place a new page or hammer-remove it. Default on.");
			_verticalPaperPlaceable = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "VerticalPaperPlaceable", true, "If true, the hammer furniture piece Blank Paper (wall) can be placed. Default on.");
			_horizontalPaperPlaceable = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "HorizontalPaperPlaceable", true, "If true, the hammer furniture piece Blank Paper (flat / table) can be placed. Default on.");
			_stackPaperPlaceable = _drakeConfigSync.BindSynced<bool>(config, "10 Paper", "Paper", "StackPaperPlaceable", true, "If true, the hammer furniture piece Paper Stack can be placed. Default on.");
			_blankPaperPlaceOrientation = _drakeConfigSync.BindSynced<string>(config, "10 Paper", "Paper", "BlankPaperPlaceOrientation", "Both", "How Written Page places from the hotbar (Use). Vertical Only or Horizontal Only: tooltip is just Use to place, and Use does not switch orientation. Both (default): Use again switches wall / flat, and the tooltip says so. Blank paper is not placeable from Use.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Vertical Only", "Horizontal Only", "Both" }));
			_verticalPaperPlaceable.SettingChanged += RaiseHammerPlaceableChanged;
			_horizontalPaperPlaceable.SettingChanged += RaiseHammerPlaceableChanged;
			_stackPaperPlaceable.SettingChanged += RaiseHammerPlaceableChanged;
			_paperName.SettingChanged += delegate
			{
				PaperItem.ApplyLocalizationFromConfig();
			};
			_paperDescription.SettingChanged += delegate
			{
				PaperItem.ApplyLocalizationFromConfig();
			};
			_writtenPaperName.SettingChanged += delegate
			{
				PaperItem.ApplyLocalizationFromConfig();
			};
			_writtenPaperDescription.SettingChanged += delegate
			{
				PaperItem.ApplyLocalizationFromConfig();
			};
			_durabilityModifierEnabled.SettingChanged += RefreshStandLabelsOnDurabilityConfigChange;
			_durabilityUnbrokenLabel.SettingChanged += RefreshStandLabelsOnDurabilityConfigChange;
			_durabilityBrokenLabel.SettingChanged += RefreshStandLabelsOnDurabilityConfigChange;
			_durabilityTierModifiers.SettingChanged += RefreshStandLabelsOnDurabilityConfigChange;
			MigrateLegacyConfigSections(config);
			RenameitPermission.WireVipListSync(_vipList, _drakeConfigSync);
			_drakeConfigSync.FinalizeBinding(Log, 49, (Func<bool>)(() => LockSyncedConfig));
			static void RaiseHammerPlaceableChanged(object sender, EventArgs e)
			{
				RenameitConfig.HammerPaperPlaceableChanged?.Invoke();
			}
			static void RefreshStandLabelsOnDurabilityConfigChange(object sender, EventArgs e)
			{
				CustomizeLibsAPI.RefreshItemStandDisplayNames();
			}
		}

		private static void MigrateLegacyConfigSections(ConfigFile config)
		{
			MigrateSectionKeys(config, "Admin", "01 Admin", "AllowAdminOverride", "LockSyncedConfig", "VipList", "VipOnlyOverride");
			MigrateSectionKeys(config, "Features", "02 Features", "RenameEnabled", "RewriteDescriptionsEnabled", "CraftedByLabelEnabled", "PublicRewriteEnabled");
			MigrateSectionKeys(config, "Exclusions", "03 Exclusions", "ExcludedNames", "ExcludedCategory", "RenameAllowlist");
			MigrateSectionKeys(config, "CraftedBy", "04 CraftedBy", "LabelCustomizable", "AllowedLabels");
			MigrateSectionKeys(config, "General", "05 General", "LockToOwner", "NameClaimsOwner", "AllowRenameUnownedItems", "ShowDenialUi", "ShowReason", "ShowItemStandItemNameWhenNoAccess", "ServerDefaultMenuOpenModifier");
			MigrateHideDisabledDenialUiToShowDenialUi(config);
			MigrateSectionKeys(config, "Stacks", "06 Stacks", "SeparateStacks", "SeparateStacksHardLock", "ExcludeStacks");
			MigrateSectionKeys(config, "UnlockCost", "07 UnlockCost", "UnlockCostEnabled", "UnlockCost");
			MigrateSectionKeys(config, "Limits", "08 Limits", "NameCharacterLimit", "CraftedByCharLimit", "DescriptionCharacterLimit");
			MigrateSectionKeys(config, "Modifiers", "09 Modifiers", "DurabilityModifierEnabled", "DurabilityUnbrokenLabel", "DurabilityBrokenLabel", "DurabilityTierModifiers");
			MigrateSectionKeys(config, "UI-NotSynced", "11 UI-NotSynced", "MenuHintColor", "MenuOpenModifier", "LogSpam");
			MigrateSectionKeys(config, "11 Paper", "10 Paper", "PaperEnabled", "PaperName", "PaperDescription", "PaperCost", "PaperCraftingStation", "PaperScale", "PaperItemType", "BlankPaperStackSize", "WrittenPaperName", "WrittenPaperDescription", "WrittenPaperIgnoresRestrictions", "PaperPlaceEnabled", "PaperTakePublicEnabled", "VerticalPaperPlaceable", "HorizontalPaperPlaceable", "StackPaperPlaceable", "BlankPaperPlaceOrientation");
			MigrateSectionKeys(config, "10 UI-NotSynced", "11 UI-NotSynced", "MenuHintColor", "MenuOpenModifier", "LogSpam");
			MigrateSectionKeys(config, "Stacks", "07 UnlockCost", "UnlockCostEnabled", "UnlockCost");
		}

		private static void MigrateSectionKeys(ConfigFile config, string legacySection, string newSection, params string[] keys)
		{
			foreach (string key in keys)
			{
				if (!TryMigrate<bool>(config, legacySection, key, newSection) && !TryMigrate<int>(config, legacySection, key, newSection))
				{
					TryMigrate<string>(config, legacySection, key, newSection);
				}
			}
		}

		private static bool TryMigrate<T>(ConfigFile config, string legacySection, string key, string newSection)
		{
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (!config.TryGetEntry<T>(legacySection, key, ref val))
			{
				return false;
			}
			ConfigEntry<T> val2 = default(ConfigEntry<T>);
			if (!config.TryGetEntry<T>(newSection, key, ref val2))
			{
				return false;
			}
			val2.Value = val.Value;
			return true;
		}

		private static void MigrateHideDisabledDenialUiToShowDenialUi(ConfigFile config)
		{
			string[] array = new string[2] { "05 General", "General" };
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			ConfigEntry<bool> val2 = default(ConfigEntry<bool>);
			foreach (string text in array)
			{
				if (config.TryGetEntry<bool>(text, "HideDisabledDenialUi", ref val))
				{
					if (config.TryGetEntry<bool>("05 General", "ShowDenialUi", ref val2))
					{
						val2.Value = !val.Value;
					}
					break;
				}
			}
		}
	}
	internal static class RenameUnlockCost
	{
		private static string? _cachedUnlockCostRaw;

		private static bool _cacheValid;

		private static bool _cacheOk;

		private static List<(string SharedName, int Amount, string ConfigKey)>? _cachedLines;

		private static string? _cachedError;

		internal static bool HasValidCostConfigured()
		{
			List<(string, int, string)> lines;
			string error;
			return TryBuildResolvedCost(out lines, out error);
		}

		internal static bool UnlockCostApplies()
		{
			if (RenameitConfig.UnlockCostEnabled)
			{
				return HasValidCostConfigured();
			}
			return false;
		}

		internal static bool CanPlayerAfford(Player? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!TryBuildResolvedCost(out List<(string, int, string)> lines, out string _))
			{
				return true;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return false;
			}
			foreach (var (text, num, _) in lines)
			{
				if (inventory.CountItems(text, -1, true) < num)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool TryConsumeUnlockCost(Player? player, out string errorMessage)
		{
			errorMessage = "";
			if ((Object)(object)player == (Object)null)
			{
				errorMessage = RenameItLocalization.T("unlock_err_no_player");
				return false;
			}
			if (!TryBuildResolvedCost(out List<(string, int, string)> lines, out string error))
			{
				errorMessage = error ?? RenameItLocalization.T("unlock_err_not_configured");
				return false;
			}
			if (lines.Count == 0)
			{
				errorMessage = RenameItLocalization.T("unlock_err_empty");
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				errorMessage = RenameItLocalization.T("unlock_err_no_inventory");
				return false;
			}
			foreach (var (text, num, _) in lines)
			{
				if (inventory.CountItems(text, -1, true) < num)
				{
					errorMessage = RenameItLocalization.T("unlock_err_not_enough");
					return false;
				}
			}
			foreach (var (text2, num2, _) in lines)
			{
				inventory.RemoveItem(text2, num2, -1, true);
			}
			return true;
		}

		internal static string GetCostDisplayShort()
		{
			if (!TryBuildResolvedCost(out List<(string, int, string)> lines, out string _) || lines.Count == 0)
			{
				return "";
			}
			List<string> list = new List<string>();
			foreach (var item3 in lines)
			{
				string item = item3.Item1;
				int item2 = item3.Item2;
				string arg = item;
				if (Localization.instance != null)
				{
					arg = Localization.instance.Localize(item);
				}
				list.Add($"{item2}x {arg}");
			}
			return string.Join(", ", list);
		}

		internal static List<(string LocalizedName, int Amount, string PrefabName)> GetCostDisplayEntries()
		{
			List<(string, int, string)> list = new List<(string, int, string)>();
			if (!TryBuildResolvedCost(out List<(string, int, string)> lines, out string _) || lines.Count == 0)
			{
				return list;
			}
			foreach (var item5 in lines)
			{
				string item = item5.Item1;
				int item2 = item5.Item2;
				string item3 = item5.Item3;
				string item4 = item;
				if (Localization.instance != null)
				{
					item4 = Localization.instance.Localize(item);
				}
				list.Add((item4, item2, item3));
			}
			return list;
		}

		internal static string GetItemTokenPublic(string prefabName)
		{
			return ResolveItemSharedName(prefabName);
		}

		internal static Sprite? GetItemIconSprite(string configPrefabName)
		{
			if (string.IsNullOrWhiteSpace(configPrefabName) || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(configPrefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return null;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if (component == null)
			{
				return null;
			}
			ItemData itemData = component.m_itemData;
			if (itemData == null)
			{
				return null;
			}
			return itemData.GetIcon();
		}

		private static bool TryBuildResolvedCost(out List<(string SharedName, int Amount, string ConfigKey)> lines, out string? error)
		{
			string text = RenameitConfig.UnlockCost?.Trim() ?? "";
			if (_cacheValid && string.Equals(_cachedUnlockCostRaw, text, StringComparison.Ordinal))
			{
				lines = _cachedLines ?? new List<(string, int, string)>();
				error = _cachedError;
				return _cacheOk;
			}
			lines = new List<(string, int, string)>();
			error = null;
			if (string.IsNullOrEmpty(text))
			{
				error = "UnlockCost is empty.";
				StoreParseCache(text, ok: false, lines, error);
				return false;
			}
			string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (string.IsNullOrEmpty(text2))
				{
					continue;
				}
				int num = text2.LastIndexOf(':');
				if (num <= 0 || num >= text2.Length - 1)
				{
					RenameitConfig.VerboseWarning("[UnlockCost] Ignoring invalid segment (need Name:Amount): \"" + text2 + "\"");
					continue;
				}
				string text3 = text2.Substring(0, num).Trim();
				if (!int.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result <= 0)
				{
					RenameitConfig.VerboseWarning("[UnlockCost] Ignoring invalid amount in: \"" + text2 + "\"");
					continue;
				}
				string text4 = ResolveItemSharedName(text3);
				if (string.IsNullOrEmpty(text4))
				{
					RenameitConfig.VerboseWarning("[UnlockCost] Unknown item or token: \"" + text3 + "\"");
				}
				else
				{
					lines.Add((text4, result, text3));
				}
			}
			if (lines.Count == 0)
			{
				error = "No valid UnlockCost entries (use Item prefab name or $item_ token, e.g. Coins:4).";
				StoreParseCache(text, ok: false, lines, error);
				return false;
			}
			StoreParseCache(text, ok: true, lines, null);
			return true;
		}

		private static void StoreParseCache(string raw, bool ok, List<(string SharedName, int Amount, string ConfigKey)> lines, string? error)
		{
			_cachedUnlockCostRaw = raw;
			_cacheValid = true;
			_cacheOk = ok;
			_cachedLines = lines;
			_cachedError = error;
		}

		private static string ResolveItemSharedName(string tokenOrPrefab)
		{
			if (string.IsNullOrWhiteSpace(tokenOrPrefab))
			{
				return "";
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				if (!tokenOrPrefab.StartsWith("$", StringComparison.Ordinal))
				{
					return "";
				}
				return tokenOrPrefab;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(tokenOrPrefab);
			if ((Object)(object)itemPrefab != (Object)null)
			{
				string text = itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name ?? "";
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			if (tokenOrPrefab.StartsWith("$", StringComparison.Ordinal))
			{
				return tokenOrPrefab;
			}
			return "";
		}
	}
	internal static class PaperAssets
	{
		internal const string ArtAssetName = "art";

		private static ManualLogSource? _log;

		private static string _pluginDir = "";

		private static AssetBundle? _pieceBundle;

		private static AssetBundle? _itemBundle;

		internal static void Init(ManualLogSource log, string pluginDirectory)
		{
			_log = log;
			_pluginDir = pluginDirectory ?? "";
		}

		internal static GameObject? AttachForgeArt(Transform parent, bool forItem, bool written, Material? material = null)
		{
			//IL_0041: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			GameObject val = LoadArtPrefab(forItem);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, parent, false);
			((Object)val2).name = (written ? "art_written" : "art");
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = Vector3.one;
			ZNetView[] componentsInChildren = val2.GetComponentsInChildren<ZNetView>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			WearNTear[] componentsInChildren2 = val2.GetComponentsInChildren<WearNTear>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Piece[] componentsInChildren3 = val2.GetComponentsInChildren<Piece>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			ItemDrop[] componentsInChildren4 = val2.GetComponentsInChildren<ItemDrop>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[i]);
			}
			Collider[] componentsInChildren5 = val2.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren5[i]);
			}
			if ((Object)(object)material != (Object)null)
			{
				Renderer[] componentsInChildren6 = val2.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val3 in componentsInChildren6)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						val3.sharedMaterial = material;
					}
				}
			}
			else
			{
				ApplyDonorMaterials(val2, ((Component)parent).gameObject);
			}
			if (written)
			{
				TryTintWritten(val2);
			}
			FitToPaperSize(val2);
			return val2;
		}

		private static void FitToPaperSize(GameObject visual)
		{
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: 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_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)visual == (Object)null)
			{
				return;
			}
			MeshFilter[] componentsInChildren = visual.GetComponentsInChildren<MeshFilter>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
			bool flag = false;
			MeshFilter[] array = componentsInChildren;
			foreach (MeshFilter val3 in array)
			{
				Mesh val4 = (((Object)(object)val3 != (Object)null) ? val3.sharedMesh : null);
				if (!((Object)(object)val4 == (Object)null))
				{
					Bounds bounds = val4.bounds;
					Vector3[] array2 = (Vector3[])(object)new Vector3[8]
					{
						new Vector3(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).min.z),
						new Vector3(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).max.z),
						new Vector3(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).min.z),
						new Vector3(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).max.z),
						new Vector3(((Bounds)(ref bounds)).max.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).min.z),
						new Vector3(((Bounds)(ref bounds)).max.x, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).max.z),
						new Vector3(((Bounds)(ref bounds)).max.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).min.z),
						new Vector3(((Bounds)(ref bounds)).max.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).max.z)
					};
					foreach (Vector3 val5 in array2)
					{
						Vector3 val6 = ((Component)val3).transform.TransformPoint(val5);
						Vector3 val7 = visual.transform.InverseTransformPoint(val6);
						val = Vector3.Min(val, val7);
						val2 = Vector3.Max(val2, val7);
						flag = true;
					}
				}
			}
			if (flag)
			{
				Vector3 val8 = val2 - val;
				float x = val8.x;
				float y = val8.y;
				float z = val8.z;
				float num;
				float num2;
				if (x >= y && x >= z)
				{
					num = x;
					num2 = ((y >= z) ? y : z);
				}
				else if (y >= x && y >= z)
				{
					num = y;
					num2 = ((x >= z) ? x : z);
				}
				else
				{
					num = z;
					num2 = ((x >= y) ? x : y);
				}
				num = Mathf.Max(num, 0.0001f);
				num2 = Mathf.Max(num2, 0.0001f);
				Vector2 paperSize = PaperItem.PaperSize;
				float num3 = Mathf.Min(paperSize.x / num, paperSize.y / num2);
				float num4 = Mathf.Min(paperSize.x / num2, paperSize.y / num);
				if (num4 > num3 && num4 * num <= paperSize.y * 1.05f && num4 * num2 <= paperSize.x * 1.05f)
				{
					num3 = num4;
				}
				visual.transform.localScale = Vector3.one * num3;
				Vector3 val9 = (val + val2) * 0.5f;
				visual.transform.localPosition = -val9 * num3;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)($"[Paper] Forge art fitted to letter {paperSize.x:0.###}x{paperSize.y:0.###}m " + $"(mesh footprint {num:0.###}x{num2:0.###} → scale {num3:0.###})."));
				}
			}
		}

		private static GameObject? LoadArtPrefab(bool forItem)
		{
			AssetBundle val = EnsureArtBundle();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = val.LoadAsset<GameObject>("art");
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			string[] allAssetNames = val.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				if (!string.IsNullOrEmpty(text) && Path.GetFileNameWithoutExtension(text).Equals("art", StringComparison.OrdinalIgnoreCase))
				{
					return val.LoadAsset<GameObject>(text);
				}
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogError((object)"[Paper] Forge art.bundle has no prefab named 'art'.");
			}
			return null;
		}

		private static AssetBundle? EnsureArtBundle()
		{
			if ((Object)(object)_itemBundle != (Object)null)
			{
				return _itemBundle;
			}
			if ((Object)(object)_pieceBundle != (Object)null)
			{
				return _pieceBundle;
			}
			string path = Path.Combine(_pluginDir, "Assets", "Items", "paper_item", "art.bundle");
			string path2 = Path.Combine(_pluginDir, "Assets", "Items", "paper_piece", "art.bundle");
			string path3 = Path.Combine(_pluginDir, "art.bundle");
			_itemBundle = LoadBundle(path);
			if ((Object)(object)_itemBundle != (Object)null)
			{
				_pieceBundle = _itemBundle;
				return _itemBundle;
			}
			_pieceBundle = LoadBundle(path2);
			if ((Object)(object)_pieceBundle != (Object)null)
			{
				_itemBundle = _pieceBundle;
				return _pieceBundle;
			}
			AssetBundle val = LoadBundle(path3);
			if ((Object)(object)val != (Object)null)
			{
				_itemBundle = val;
				_pieceBundle = val;
				return val;
			}
			return null;
		}

		private static AssetBundle? EnsurePieceBundle()
		{
			return EnsureArtBundle();
		}

		private static AssetBundle? EnsureItemBundle()
		{
			return EnsureArtBundle();
		}

		private static AssetBundle? LoadBundle(string path)
		{
			if (string.IsNullOrEmpty(path) || !File.Exists(path))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[Paper] Forge bundle missing: " + path));
				}
				return null;
			}
			try
			{
				AssetBundle obj = AssetBundle.LoadFromFile(path);
				if ((Object)(object)obj == (Object)null)
				{
					ManualLogSource? log2 = _log;
					if (log2 != null)
					{
						log2.LogError((object)("[Paper] Failed to load forge bundle: " + path + " (identical bundle may already be loaded)."));
					}
				}
				else
				{
					ManualLogSource? log3 = _log;
					if (log3 != null)
					{
						log3.LogInfo((object)("[Paper] Loaded forge art '" + path + "'."));
					}
				}
				return obj;
			}
			catch (Exception ex)
			{
				ManualLogSource? log4 = _log;
				if (log4 != null)
				{
					log4.LogError((object)("[Paper] Forge bundle load error: " + ex.Message));
				}
				return null;
			}
		}

		private static void ApplyDonorMaterials(GameObject visual, GameObject donorRoot)
		{
			Material val = null;
			MeshRenderer[] componentsInChildren = donorRoot.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Component)val2).transform.IsChildOf(visual.transform) && (Object)(object)((Renderer)val2).sharedMaterial != (Object)null)
				{
					val = ((Renderer)val2).sharedMaterial;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren2 = visual.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren2)
			{
				if (!((Object)(object)val3 == (Object)null))
				{
					val3.sharedMaterial = val;
				}
			}
		}

		private static void TryTintWritten(GameObject visual)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_005d: 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)
			Renderer[] componentsInChildren = visual.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMaterial == (Object)null))
				{
					Material val2 = new Material(val.sharedMaterial);
					if (val2.HasProperty("_Color"))
					{
						val2.SetColor("_Color", new Color(0.92f, 0.88f, 0.78f, 1f));
					}
					if (val2.HasProperty("_Color"))
					{
						val2.color = new Color(0.92f, 0.88f, 0.78f, 1f);
					}
					val.sharedMaterial = val2;
				}
			}
		}

		internal static void EnsurePersistentZNetView(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			if (!root.activeSelf)
			{
				root.SetActive(true);
			}
			ZNetView[] componentsInChildren = root.GetComponentsInChildren<ZNetView>(true);
			ZNetView val = null;
			foreach (ZNetView val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if ((Object)(object)((Component)val2).gameObject == (Object)(object)root)
					{
						val = val2;
					}
					else
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = root.AddComponent<ZNetView>();
			}
			val.m_persistent = true;
			val.m_distant = false;
			if (!((Behaviour)val).enabled)
			{
				((Behaviour)val).enabled = true;
			}
		}
	}
	internal static class PaperItem
	{
		internal enum PaperSnapKind
		{
			Wall,
			Flat,
			Stack
		}

		internal const string PrefabName = "Drakes_PieceOfPaper";

		internal const string WrittenPrefabName = "Drakes_Paper_Written";

		private const string CloneSource = "LeatherScraps";

		private const string TokenName = "$item_drakes_pieceofpaper";

		private const string TokenDesc = "$item_drakes_pieceofpaper_desc";

		private const string TokenWrittenName = "$item_drakes_paper_written";

		private const string TokenWrittenDesc = "$item_drakes_paper_written_desc";

		private static readonly Vector2 BasePaperSize = new Vector2(0.2159f, 0.2794f);

		private const float GroundClearance = 0.045f;

		private const float FlatSurfaceLift = 0.04f;

		internal const float WallFaceGap = 0.008f;

		private static readonly Color OffWhite = new Color(0.93f, 0.89f, 0.8f, 1f);

		private static ManualLogSource? _log;

		private static string _pluginDir = "";

		private static Sprite? _blankIconSprite;

		private static Sprite? _writtenIconSprite;

		internal static Vector2 PaperSize => BasePaperSize * RenameitConfig.PaperScale;

		internal static void Register(ManualLogSource log, string pluginDirectory)
		{
			_log = log;
			_pluginDir = pluginDirectory ?? "";
			PaperAssets.Init(log, _pluginDir);
			PrefabManager.OnVanillaPrefabsAvailable -= AddPaperItems;
			PrefabManager.OnVanillaPrefabsAvailable += AddPaperItems;
		}

		private static void AddPaperItems()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= AddPaperItems;
			try
			{
				AddLocalization();
				Texture2D val = LoadParchmentTexture();
				Texture2D val2 = LoadMeshTexture() ?? (((Object)(object)val != (Object)null) ? CreateCutoutMeshTexture(val) : null);
				Texture2D? obj = LoadWrittenParchmentTexture() ?? val;
				Texture2D meshTex = CreateWrittenMeshTexture(obj, val, val2);
				RegisterBlank(val, val2);
				RegisterWritten(obj, meshTex);
			}
			catch (Exception arg)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogError((object)$"[Paper] Failed to register paper items: {arg}");
				}
			}
		}

		private static void RegisterBlank(Texture2D? parchment, Texture2D? meshTex)
		{
			//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_004e: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0024: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			Sprite val = null;
			if ((Object)(object)parchment != (Object)null)
			{
				val = Sprite.Create(parchment, new Rect(0f, 0f, (float)((Texture)parchment).width, (float)((Texture)parchment).height), new Vector2(0.5f, 0.5f));
			}
			ItemConfig val2 = new ItemConfig
			{
				Name = "$item_drakes_pieceofpaper",
				Description = "$item_drakes_pieceofpaper_desc",
				Enabled = RenameitConfig.PaperEnabled,
				Amount = 1
			};
			if ((Object)(object)val != (Object)null)
			{
				val2.Icon = val;
			}
			ApplyRecipeFromConfig(val2);
			CustomItem val3 = new CustomItem("Drakes_PieceOfPaper", "LeatherScraps", val2);
			SanitizeItemDrop(val3, stackable: true);
			BuildPaper2Visual(val3.ItemPrefab, meshTex, written: false);
			ItemManager.Instance.AddItem(val3);
			if (val3.ItemDrop?.m_itemData != null)
			{
				val3.ItemDrop.m_itemData.m_dropPrefab = val3.ItemPrefab;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)(string.Format("[Paper] Registered blank {0} (stack={1}, ", "Drakes_PieceOfPaper", RenameitConfig.BlankPaperStackSize) + $"enabled={RenameitConfig.PaperEnabled}, cost='{RenameitConfig.PaperCost}')."));
			}
		}

		private static void RegisterWritten(Texture2D? parchment, Texture2D? meshTex)
		{
			//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_004e: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0024: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			Sprite val = null;
			if ((Object)(object)parchment != (Object)null)
			{
				val = Sprite.Create(parchment, new Rect(0f, 0f, (float)((Texture)parchment).width, (float)((Texture)parchment).height), new Vector2(0.5f, 0.5f));
			}
			ItemConfig val2 = new ItemConfig
			{
				Name = "$item_drakes_paper_written",
				Description = "$item_drakes_paper_written_desc",
				Enabled = RenameitConfig.PaperEnabled,
				Amount = 1
			};
			if ((Object)(object)val != (Object)null)
			{
				val2.Icon = val;
			}
			CustomItem val3 = new CustomItem("Drakes_Paper_Written", "LeatherScraps", val2);
			SanitizeItemDrop(val3, stackable: false);
			BuildPaper2Visual(val3.ItemPrefab, meshTex, written: true);
			ItemManager.Instance.AddItem(val3);
			if (val3.ItemDrop?.m_itemData != null)
			{
				val3.ItemDrop.m_itemData.m_dropPrefab = val3.ItemPrefab;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)"[Paper] Registered written Drakes_Paper_Written (stack=1).");
			}
		}

		internal static void ApplyLocalizationFromConfig()
		{
			try
			{
				AddLocalization();
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[Paper] Localization refresh failed: " + ex.Message));
				}
			}
		}

		private static void AddLocalization()
		{
			string text = (string.IsNullOrWhiteSpace(RenameitConfig.PaperName) ? "Piece of Paper" : RenameitConfig.PaperName.Trim());
			string text2 = (string.IsNullOrWhiteSpace(RenameitConfig.PaperDescription) ? "A blank piece of paper you can write on. Renaming uses one sheet and creates a Written Page." : RenameitConfig.PaperDescription.Trim());
			string text3 = (string.IsNullOrWhiteSpace(RenameitConfig.WrittenPaperName) ? "Written Page" : RenameitConfig.WrittenPaperName.Trim());
			string text4 = (string.IsNullOrWhiteSpace(RenameitConfig.WrittenPaperDescription) ? "A page with writing on it." : RenameitConfig.WrittenPaperDescription.Trim());
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text5 = "English";
			string text6 = "item_drakes_pieceofpaper";
			localization.AddTranslation(ref text5, ref text6, text);
			text5 = "English";
			text6 = "item_drakes_pieceofpaper_desc";
			localization.AddTranslation(ref text5, ref text6, text2);
			text5 = "Spanish";
			text6 = "item_drakes_pieceofpaper";
			localization.AddTranslation(ref text5, ref text6, text);
			text5 = "Spanish";
			text6 = "item_drakes_pieceofpaper_desc";
			localization.AddTranslation(ref text5, ref text6, text2);
			text5 = "English";
			text6 = "item_drakes_paper_written";
			localization.AddTranslation(ref text5, ref text6, text3);
			text5 = "English";
			text6 = "item_drakes_paper_written_desc";
			localization.AddTranslation(ref text5, ref text6, text4);
			text5 = "Spanish";
			text6 = "item_drakes_paper_written";
			localization.AddTranslation(ref text5, ref text6, text3);
			text5 = "Spanish";
			text6 = "item_drakes_paper_written_desc";
			localization.AddTranslation(ref text5, ref text6, text4);
		}

		private static Texture2D? LoadParchmentTexture()
		{
			return LoadTextureFile("paper.png", "icon");
		}

		private static Texture2D? LoadWrittenParchmentTexture()
		{
			return LoadTextureFile("paper_written.png", "written");
		}

		private static Texture2D? LoadMeshTexture()
		{
			return LoadTextureFile("paper_mesh.png", "mesh");
		}

		private static Texture2D? LoadTextureFile(string fileName, string label)
		{
			string text = (Path.IsPathRooted(fileName) ? fileName : Path.Combine(_pluginDir, "Assets", fileName));
			if (!File.Exists(text) && fileName.IndexOf(Path.DirectorySeparatorChar) < 0 && fileName.IndexOf(Path.AltDirectorySeparatorChar) < 0)
			{
				text = Path.Combine(_pluginDir, "Assets", "Icons", fileName);
			}
			if (!File.Exists(text))
			{
				text = Path.Combine(_pluginDir, Path.GetFileName(fileName));
			}
			if (!File.Exists(text))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[Paper] " + label + " texture not found at " + text + "."));
				}
				return null;
			}
			try
			{
				return AssetUtils.LoadTexture(text, false);
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Paper] Failed to load " + label + " texture: " + ex.Message));
				}
				return null;
			}
		}

		private static void ApplyRecipeFromConfig(ItemConfig itemConfig)
		{
			string text = RenameitConfig.PaperCraftingStation?.Trim() ?? "";
			itemConfig.CraftingStation = (string.IsNullOrEmpty(text) ? null : text);
			foreach (var (text2, num) in ParseCost(RenameitConfig.PaperCost))
			{
				itemConfig.AddRequirement(text2, num, 0);
			}
		}

		internal static List<(string PrefabName, int Amount)> ParseCost(string? raw)
		{
			List<(string, int)> list = new List<(string, int)>();
			if (string.IsNullOrWhiteSpace(raw))
			{
				return list;
			}
			string[] array = raw.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num = text.LastIndexOf(':');
				if (num <= 0 || num >= text.Length - 1)
				{
					RenameitConfig.VerboseWarning("[Paper] Ignoring invalid cost segment: \"" + text + "\"");
					continue;
				}
				string item = text.Substring(0, num).Trim();
				if (!int.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result <= 0)
				{
					RenameitConfig.VerboseWarning("[Paper] Ignoring invalid amount in: \"" + text + "\"");
				}
				else
				{
					list.Add((item, result));
				}
			}
			if (list.Count == 0)
			{
				list.Add(("Wood", 1));
				list.Add(("Coal", 1));
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)"[Paper] PaperCost had no valid entries; using Wood:1,Coal:1.");
				}
			}
			return list;
		}

		private static void SanitizeItemDrop(CustomItem paper, bool stackable)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			ItemDrop itemDrop = paper.ItemDrop;
			if (itemDrop?.m_itemData?.m_shared != null)
			{
				SharedData shared = itemDrop.m_itemData.m_shared;
				shared.m_name = (stackable ? "$item_drakes_pieceofpaper" : "$item_drakes_paper_written");
				shared.m_description = (stackable ? "$item_drakes_pieceofpaper_desc" : "$item_drakes_paper_written_desc");
				shared.m_maxStackSize = ((!stackable) ? 1 : RenameitConfig.BlankPaperStackSize);
				shared.m_itemType = ResolveItemType();
				shared.m_weight = 0.1f;
				shared.m_value = 0;
				shared.m_teleportable = true;
				shared.m_questItem = false;
				shared.m_maxQuality = 1;
				shared.m_useDurability = false;
				shared.m_food = 0f;
				shared.m_foodStamina = 0f;
				shared.m_foodEitr = 0f;
			}
		}

		private static ItemType ResolveItemType()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_002f: 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_002d: Invalid comparison between Unknown and I4
			string text = RenameitConfig.PaperItemType?.Trim() ?? "";
			if (Enum.TryParse<ItemType>(text, ignoreCase: true, out ItemType result) && ((int)result == 1 || (int)result == 16))
			{
				return result;
			}
			if (!string.IsNullOrEmpty(text) && !text.Equals("Material", StringComparison.OrdinalIgnoreCase))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[Paper] PaperItemType '" + text + "' invalid; use Material or Misc. Falling back to Material."));
				}
			}
			return (ItemType)1;
		}

		internal static void ClearBlankPlaceTool(ItemData? item)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//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)
			if (IsBlankPaper(item) && item.m_shared != null && !IsWrittenPaper(item))
			{
				item.m_shared.m_buildPieces = null;
				if ((int)item.m_shared.m_itemType == 19)
				{
					item.m_shared.m_itemType = ResolveItemType();
				}
			}
		}

		internal static bool IsBlankPaper(ItemData? item)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			if (PrefabsMatch(item, "Drakes_PieceOfPaper"))
			{
				return true;
			}
			return item.m_shared.m_name.Equals("$item_drakes_pieceofpaper", StringComparison.OrdinalIgnoreCase);
		}

		internal static bool IsWrittenPaper(ItemData? item)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			if (PrefabsMatch(item, "Drakes_Paper_Written"))
			{
				return true;
			}
			return item.m_shared.m_name.Equals("$item_drakes_paper_written", StringComparison.OrdinalIgnoreCase);
		}

		internal static bool IsAnyPaper(ItemData? item)
		{
			if (!IsBlankPaper(item))
			{
				return IsWrittenPaper(item);
			}
			return true;
		}

		internal static bool IsPaperItem(ItemData? item)
		{
			return IsAnyPaper(item);
		}

		private static bool PrefabsMatch(ItemData item, string prefabName)
		{
			if ((Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			string name = ((Object)item.m_dropPrefab).name;
			if (!name.Equals(prefabName, StringComparison.OrdinalIgnoreCase))
			{
				return name.StartsWith(prefabName, StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		internal static Sprite? GetBlankIconSprite()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_blankIconSprite != (Object)null)
			{
				return _blankIconSprite;
			}
			Texture2D val = LoadTextureFile(Path.Combine("Items", "paper_item", "icon.png"), "forge-item-icon") ?? LoadTextureFile(Path.Combine("Items", "paper_piece", "icon.png"), "forge-piece-icon") ?? LoadParchmentTexture();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			_blankIconSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			return _blankIconSprite;
		}

		internal static Sprite? GetWrittenIconSprite()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_writtenIconSprite != (Object)null)
			{
				return _writtenIconSprite;
			}
			Texture2D val = LoadWrittenParchmentTexture() ?? LoadParchmentTexture();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			_writtenIconSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			return _writtenIconSprite;
		}

		internal static void BuildDecorSheetVisual(GameObject? root, bool wall, bool written = false)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			try
			{
				if (CaptureDonorMaterial(root) == null)
				{
					FindFallbackWorldMaterial();
				}
				StripPieceDonorVisuals(root);
				Transform transform = new GameObject("drakes_paper_decor").transform;
				transform.SetParent(root.transform, false);
				transform.localPosition = (wall ? new Vector3(0f, 0f, -0.002f) : new Vector3(0f, 0.04f, 0f));
				transform.localScale = Vector3.one;
				Material val = CreateDecorPaperMaterial(written);
				bool flag = (Object)(object)PaperAssets.AttachForgeArt(transform, forItem: false, written, val) != (Object)null;
				if (flag)
				{
					transform.localRotation = (wall ? Quaternion.Euler(90f, 0f, 0f) : Quaternion.identity);
				}
				else
				{
					transform.localRotation = (wall ? Quaternion.identity : Quaternion.Euler(90f, 0f, 0f));
					CreatePaperFace(transform, "paper_front", val, Quaternion.identity, new Vector3(0f, 0f, 0.003f));
					CreatePaperFace(transform, "paper_back", val, Quaternion.Euler(0f, 180f, 0f), new Vector3(0f, 0f, -0.003f));
				}
				EnsureThinBoxCollider(root, wall);
				EnsurePaperSnapPoints(root, (!wall) ? PaperSnapKind.Flat : PaperSnapKind.Wall);
				ConfigurePaperPlacement(root, wall);
				EnsurePieceLayer(root);
				SanitizePaperWearNTear(root);
				PaperAssets.EnsurePersistentZNetView(root);
				EnsureVisualDepthBias(root, wall);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)string.Format("[Paper] Decor sheet on '{0}' wall={1} written={2} forge={3}.", ((Object)root).name, wall, written, flag ? "yes" : "quad-fallback"));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Paper] Decor sheet failed: " + ex.Message));
				}
			}
		}

		internal static void BuildPaperStackVisual(GameObject? root, int sheets = 12)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			try
			{
				StripPieceDonorVisuals(root);
				FindFallbackWorldMaterial();
				Transform transform = new GameObject("drakes_paper_stack").transform;
				transform.SetParent(root.transform, false);
				transform.localPosition = new Vector3(0f, 0.04f, 0f);
				transform.localRotation = Quaternion.identity;
				transform.localScale = Vector3.one;
				sheets = Math.Max(4, Math.Min(sheets, 20));
				float num = 0.008f;
				Material val = CreateDecorPaperMaterial(written: false);
				for (int i = 0; i < sheets; i++)
				{
					float num2 = (float)i * num + num * 0.5f;
					float num3 = (float)(i % 3 - 1) * 4f + (float)(i % 5) * 0.5f;
					float num4 = 1f - (float)(i % 4) * 0.015f;
					Transform transform2 = new GameObject($"sheet_{i}").transform;
					transform2.SetParent(transform, false);
					transform2.localPosition = new Vector3(0f, num2, 0f);
					transform2.localScale = new Vector3(num4, num4, 1f);
					if ((Object)(object)PaperAssets.AttachForgeArt(transform2, forItem: false, written: false, val) != (Object)null)
					{
						transform2.localRotation = Quaternion.Euler(0f, num3, 0f);
						continue;
					}
					transform2.localRotation = Quaternion.Euler(90f, num3, 0f);
					CreatePaperFace(transform2, "front", val, Quaternion.identity, new Vector3(0f, 0f, 0.0005f));
					CreatePaperFace(transform2, "back", val, Quaternion.Euler(0f, 180f, 0f), new Vector3(0f, 0f, -0.0005f));
				}
				Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren[j]);
				}
				BoxCollider obj = root.AddComponent<BoxCollider>();
				float num5 = (float)sheets * num;
				obj.center = new Vector3(0f, 0.04f + num5 * 0.5f, 0f);
				obj.size = new Vector3(PaperSize.x * 1.05f, Math.Max(0.02f, num5), PaperSize.y * 1.05f);
				EnsurePaperSnapPoints(root, PaperSnapKind.Stack, num5);
				ConfigurePaperPlacement(root, wall: false);
				EnsurePieceLayer(root);
				SanitizePaperWearNTear(root);
				PaperAssets.EnsurePersistentZNetView(root);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[Paper] Paper stack visual on '{((Object)root).name}' sheets={sheets}.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Paper] Paper stack visual failed: " + ex.Message));
				}
			}
		}

		internal static void EnsurePaperSnapPoints(GameObject root, PaperSnapKind kind, float stackHeight = 0.12f)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)root == (Object)null))
			{
				ClearSnapPointChildren(root.transform);
				float num = PaperSize.x * 0.5f;
				float num2 = PaperSize.y * 0.5f;
				switch (kind)
				{
				case PaperSnapKind.Wall:
					AddSnap(root, "Top Left", new Vector3(0f - num, num2, 0f));
					AddSnap(root, "Top", new Vector3(0f, num2, 0f));
					AddSnap(root, "Top Right", new Vector3(num, num2, 0f));
					AddSnap(root, "Bottom Left", new Vector3(0f - num, 0f - num2, 0f));
					AddSnap(root, "Bottom", new Vector3(0f, 0f - num2, 0f));
					AddSnap(root, "Bottom Right", new Vector3(num, 0f - num2, 0f));
					break;
				case PaperSnapKind.Flat:
				{
					float num5 = 0.04f;
					AddSnap(root, "Front Left", new Vector3(num, num5, 0f - num2));
					AddSnap(root, "Front Right", new Vector3(0f - num, num5, 0f - num2));
					AddSnap(root, "Back Left", new Vector3(num, num5, num2));
					AddSnap(root, "Back Right", new Vector3(0f - num, num5, num2));
					break;
				}
				case PaperSnapKind.Stack:
				{
					float num3 = 0.04f;
					float num4 = num3 + Math.Max(0.02f, stackHeight);
					AddSnap(root, "Bottom Front Left", new Vector3(num, num3, 0f - num2));
					AddSnap(root, "Bottom Front Right", new Vector3(0f - num, num3, 0f - num2));
					AddSnap(root, "Bottom Back Left", new Vector3(num, num3, num2));
					AddSnap(root, "Bottom Back Right", new Vector3(0f - num, num3, num2));
					AddSnap(root, "Top Front Left", new Vector3(num, num4, 0f - num2));
					AddSnap(root, "Top Front Right", new Vector3(0f - num, num4, 0f - num2));
					AddSnap(root, "Top Back Left", new Vector3(num, num4, num2));
					AddSnap(root, "Top Back Right", new Vector3(0f - num, num4, num2));
					AddSnap(root, "Top Center", new Vector3(0f, num4, 0f));
					break;
				}
				}
			}
		}

		private static void ClearSnapPointChildren(Transform root)
		{
			for (int num = root.childCount - 1; num >= 0; num--)
			{
				Transform child = root.GetChild(num);
				bool flag = ((Object)child).name.IndexOf("snap", StringComparison.OrdinalIgnoreCase) >= 0;
				bool flag2 = false;
				try
				{
					flag2 = ((Component)child).CompareTag("snappoint");
				}
				catch
				{
				}
				if (flag2 || flag)
				{
					Object.DestroyImmediate((Object)(object)((Component)child).gameObject);
				}
			}
		}

		private static void AddSnap(GameObject root, string label, Vector3 localPos)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(string.IsNullOrWhiteSpace(label) ? "Center" : label);
			Transform transform = val.transform;
			transform.SetParent(root.transform, false);
			transform.localPosition = localPos;
			transform.localRotation = Quaternion.identity;
			transform.localScale = Vector3.one;
			try
			{
				val.tag = "snappoint";
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[Paper] Failed to tag snappoint '" + label + "': " + ex.Message));
				}
			}
		}

		internal static void EnsureVisualDepthBias(GameObject root, bool wall)
		{
			if (!((Object)(object)root == (Object)null))
			{
				PaperVisualDepthBias paperVisualDepthBias = root.GetComponent<PaperVisualDepthBias>();
				if ((Object)(object)paperVisualDepthBias == (Object)null)
				{
					paperVisualDepthBias = root.AddComponent<PaperVisualDepthBias>();
				}
				paperVisualDepthBias.Configure(wall);
			}
		}

		internal static bool IsWallSheetPiece(Piece? piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			string name = ((Object)((Component)piece).gameObject).name;
			if (!name.StartsWith("Drakes_PaperBlank_Upright", StringComparison.Ordinal) && !name.StartsWith("Drakes_PaperNote_Vertical", StringComparison.Ordinal))
			{
				return name.StartsWith("Drakes_PaperBlank_UseVertical", StringComparison.Ordinal);
			}
			return true;
		}

		internal static Vector3 SeatWallSheet(Vector3 proposed, Transform ghost)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ghost == (Object)null)
			{
				return proposed;
			}
			Camera mainCamera = Utils.GetMainCamera();
			if ((Object)(object)mainCamera == (Object)null)
			{
				return proposed;
			}
			Vector3 position = ((Component)mainCamera).transform.position;
			Vector3 val = proposed - position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.2f)
			{
				return proposed;
			}
			Vector3 val2 = val / magnitude;
			RaycastHit[] array = Physics.RaycastAll(position, val2, magnitude + 1.25f, -5, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			bool flag = false;
			Vector3 val3 = Vector3.zero;
			Vector3 val4 = Vector3.zero;
			float num = float.MaxValue;
			RaycastHit[] array2 = array;
			for (int num2 = 0; num2 < array2.Length; num2++)
			{
				RaycastHit val5 = array2[num2];
				if ((Object)(object)((RaycastHit)(ref val5)).collider == (Object)null)
				{
					continue;
				}
				Transform transform = ((Component)((RaycastHit)(ref val5)).collider).transform;
				if ((Object)(object)transform == (Object)(object)ghost || transform.IsChildOf(ghost) || ghost.IsChildOf(transform))
				{
					continue;
				}
				float num3 = Vector3.Dot(((RaycastHit)(ref val5)).point - proposed, val2);
				if (!(num3 > 0.038f) && !(num3 < -1.15f))
				{
					float num4 = Mathf.Abs(num3);
					if (!(num4 >= num))
					{
						num = num4;
						val3 = ((RaycastHit)(ref val5)).point;
						val4 = ((RaycastHit)(ref val5)).normal;
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return proposed;
			}
			if (Vector3.Dot(val4, position - val3) < 0f)
			{
				val4 = -val4;
			}
			if (((Vector3)(ref val4)).sqrMagnitude < 0.0001f)
			{
				return proposed;
			}
			Vector3 val6 = val3 + ((Vector3)(ref val4)).normalized * 0.008f;
			return proposed + Vector3.Project(val6 - proposed, val4);
		}

		internal static void ConfigurePaperPlacement(GameObject? root, bool wall)
		{
			Piece val = (((Object)(object)root != (Object)null) ? root.GetComponent<Piece>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.m_groundPiece = false;
				val.m_groundOnly = false;
				val.m_waterPiece = false;
				val.m_noInWater = true;
				val.m_noClipping = false;
				val.m_notOnTiltingSurface = false;
				val.m_randomInitBuildRotation = false;
				val.m_canBeRemoved = true;
				if (wall)
				{
					val.m_clipGround = true;
					val.m_clipEverything = true;
					val.m_allowAltGroundPlacement = true;
				}
				else
				{
					val.m_clipGround = false;
					val.m_clipEverything = true;
					val.m_allowAltGroundPlacement = true;
				}
			}
		}

		internal static void EnsurePieceLayer(GameObject? root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer("piece");
			if (num < 0)
			{
				num = 10;
			}
			root.layer = num;
			Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponentInParent<Canvas>() != (Object)null))
				{
					((Component)val).gameObject.layer = num;
				}
			}
		}

		internal static void StripDonorGeometryKeepSignUi(GameObject root)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			List<GameObject> list = new List<GameObject>();
			foreach (Transform item in root.transform)
			{
				Transform val = item;
				if (!((Object)val).name.StartsWith("drakes_paper", StringComparison.OrdinalIgnoreCase) && !((Object)(object)((Component)val).GetComponentInChildren<Canvas>(true) != (Object)null) && !((Object)(object)((Component)val).GetComponentInChildren<TMP_Text>(true) != (Object)null))
				{
					if (((Object)val).name.IndexOf("snap", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						list.Add(((Component)val).gameObject);
					}
					else if ((Object)(object)((Component)val).GetComponent<MeshFilter>() != (Object)null || (Object)(object)((Component)val).GetComponentInChildren<MeshFilter>(true) != (Object)null)
					{
						list.Add(((Component)val).gameObject);
					}
				}
			}
			foreach (GameObject item2 in list)
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
			Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).GetComponentInParent<Canvas>() != (Object)null))
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
		}

		internal static void SanitizePaperWearNTear(GameObject? root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			WearNTear component = root.GetComponent<WearNTear>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			component.m_autoCreateFragments = false;
			component.m_fragmentRoots = Array.Empty<GameObject>();
			ApplySoftPaperBreakEffects(component);
			for (int num = root.transform.childCount - 1; num >= 0; num--)
			{
				Transform child = root.transform.GetChild(num);
				string name = ((Object)child).name;
				if (name.IndexOf("fragment", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("debris", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Object.DestroyImmediate((Object)(object)((Component)child).gameObject);
				}
			}
		}

		private static void ApplySoftPaperBreakEffects(WearNTear wnt)
		{
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121