Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimChestNaming v1.2.2
plugins/ValheimChestNaming.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; using Valheim.SettingsGui; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ValheimChestNaming")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.2.0")] [assembly: AssemblyInformationalVersion("1.2.2")] [assembly: AssemblyProduct("ValheimChestNaming")] [assembly: AssemblyTitle("ValheimChestNaming")] [assembly: AssemblyVersion("1.2.2.0")] namespace ValheimChestNaming; internal class ChestNameReceiver : TextReceiver { private readonly Container _container; public ChestNameReceiver(Container container) { _container = container; } public string GetText() { if ((Object)(object)_container == (Object)null) { return ""; } return ChestNameStore.Get(_container); } public void SetText(string text) { if ((Object)(object)_container == (Object)null) { Patches.Message(Patches.L("箱子已不存在,改名取消", "Container is gone, rename cancelled")); return; } if (!ChestNameStore.Set(_container, text)) { Patches.Message(Patches.L("改名失败:没有权限或箱子已失效", "Rename failed: no permission or container is gone")); return; } string text2 = (text ?? "").Trim(); if (string.IsNullOrEmpty(text2)) { Patches.Message(Patches.L("已清除箱子名字", "Container name cleared")); } else { Patches.Message(Patches.L("箱子已命名为「" + text2 + "」", "Container named \"" + text2 + "\"")); } } } internal static class ChestNameStore { private static readonly int NameKey = StringExtensionMethods.GetStableHashCode("chestnaming_name"); public static string Get(Container c) { if ((Object)(object)c == (Object)null) { return ""; } ZNetView val = NView(c); if (!Valid(val)) { return ""; } try { return val.GetZDO().GetString(NameKey, "") ?? ""; } catch { return ""; } } public static string GetDisplayName(Container c) { string text = Get(c); if (!string.IsNullOrEmpty(text)) { return text; } try { Inventory inventory = c.GetInventory(); return (inventory != null) ? inventory.GetName() : ""; } catch { return ""; } } public static bool Set(Container c, string text) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)c == (Object)null) { return false; } ZNetView val = NView(c); if (!Valid(val)) { return false; } if (ChestNamingPlugin.RequireAccess.Value) { try { if (!PrivateArea.CheckAccess(((Component)c).transform.position, 0f, true, false)) { ChestNamingPlugin.Log.LogInfo((object)"[ChestNaming] 拒绝改名:不在自己的私人区域内"); return false; } } catch { } } string text2 = (text ?? "").Trim(); int num = Mathf.Max(1, ChestNamingPlugin.CharacterLimit.Value); if (text2.Length > num) { text2 = text2.Substring(0, num); } try { if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set(NameKey, text2); ChestNamingPlugin.Debug("[ChestNaming] 已写入名字:'" + text2 + "'"); return true; } catch (Exception ex) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 写入箱子名字失败:" + ex)); return false; } } private static ZNetView NView(Container c) { try { if ((Object)(object)c.m_rootObjectOverride != (Object)null) { ZNetView component = ((Component)c.m_rootObjectOverride).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null) { return component; } } return ((Component)c).GetComponent<ZNetView>(); } catch { return null; } } private static bool Valid(ZNetView nv) { try { return (Object)(object)nv != (Object)null && nv.IsValid() && nv.GetZDO() != null; } catch { return false; } } } [BepInPlugin("SuperVikingDepartment.ValheimChestNaming", "ValheimChestNaming", "1.2.2")] public class ChestNamingPlugin : BaseUnityPlugin { public const string PluginGuid = "SuperVikingDepartment.ValheimChestNaming"; public const string PluginName = "ValheimChestNaming"; public const string PluginVersion = "1.2.2"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> CharacterLimit; internal static ConfigEntry<bool> ShowHoverHint; internal static ConfigEntry<bool> ShowInContainerTitle; internal static ConfigEntry<bool> RequireAccess; internal static ConfigEntry<bool> DebugLogging; private Harmony _harmony; private static MethodInfo _takeInputMethod; private void Awake() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "总开关。关闭后不再显示快捷键提示、也不能改名,行为完全恢复原版。"); CharacterLimit = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CharacterLimit", 30, "箱子名字的最大长度。原版输入框会按此值限制输入,超长部分在保存时也会被截断。\n名字显示在悬停提示第一行,过长会显得拥挤,建议 30 以内。"); ShowHoverHint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHoverHint", true, "看着箱子时,在悬停提示里显示一行快捷操作提示(排在原版「按 E 打开」下方)。\n关闭后悬停提示不再有本 mod 添加的那一行,但改名功能仍然可用。"); ShowInContainerTitle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowInContainerTitle", true, "打开箱子后,把界面顶部的标题换成自定义名字。\n关闭后标题始终显示原版名字,但悬停提示仍会显示自定义名字。"); RequireAccess = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireAccess", true, "只有站在自己私人区域内时才能改名,与原版告示牌的限制一致。\n多人游戏里可以防止别人给你的箱子乱起名字。"); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "DebugLogging", false, "输出改名细节日志,用于排查问题。正常游玩建议关闭。"); _harmony = new Harmony("SuperVikingDepartment.ValheimChestNaming"); Patches.Apply(_harmony); CustomKeyBind.Apply(_harmony); LogPatchStatus(); _takeInputMethod = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null); if (_takeInputMethod == null) { Log.LogError((object)"[ChestNaming][diag] 未找到 Player.TakeInput!悬停改名入口将不可用(打开箱子后按 N 仍可用)。"); } Log.LogInfo((object)"ValheimChestNaming loaded (v1.2.2)"); Log.LogInfo((object)($"[ChestNaming] enabled={Enabled.Value}, " + $"characterLimit={CharacterLimit.Value}, showHoverHint={ShowHoverHint.Value}, " + $"showInContainerTitle={ShowInContainerTitle.Value}, requireAccess={RequireAccess.Value}")); } private static void LogPatchStatus() { Report(typeof(Container), "GetHoverText"); Report(typeof(Container), "GetHoverName"); Report(typeof(InventoryGui), "UpdateContainer"); Report(typeof(InventoryGui), "Update"); Report(typeof(ZInput), "Reset"); Report(typeof(KeyboardMouseSettings), "SetupKeys"); Log.LogInfo((object)((ZInput.instance == null) ? "[ChestNaming][diag] ZInput 尚未创建,按键会在其初始化时由 Reset 补丁注册" : "[ChestNaming][diag] ZInput 已存在,按键注册状态见上方 RegisterButton 日志")); } private static void Report(Type type, string method) { MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogError((object)("[ChestNaming][diag] 未找到 " + type.Name + "." + method + "!游戏版本可能不兼容。")); } else { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); Log.LogInfo((object)("[ChestNaming][diag] " + type.Name + "." + method + ": " + $"prefix={(patchInfo?.Prefixes?.Count).GetValueOrDefault()}, postfix={(patchInfo?.Postfixes?.Count).GetValueOrDefault()}")); } } internal static void Debug(string msg) { if (DebugLogging != null && DebugLogging.Value) { Log.LogInfo((object)msg); } } private void Update() { if (!Enabled.Value) { return; } try { if (TextInput.IsVisible() || !PlayerAcceptsInput()) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Container hoveredContainer = GetHoveredContainer(localPlayer); if (!((Object)(object)hoveredContainer == (Object)null) && ZInput.GetButtonDown("ChestNaming")) { Patches.OpenDialogForHover(hoveredContainer); } } } catch (Exception ex) { Log.LogError((object)("[ChestNaming] 悬停改名处理出错:" + ex)); } } private bool PlayerAcceptsInput() { try { if (_takeInputMethod == null) { return false; } return (bool)_takeInputMethod.Invoke(Player.m_localPlayer, null); } catch { return false; } } private static Container GetHoveredContainer(Player player) { GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if (!((Object)(object)hoverObject != (Object)null)) { return null; } return hoverObject.GetComponentInParent<Container>(); } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Log.LogWarning((object)("[ChestNaming] 卸载补丁时出错:" + ex.Message)); } } } internal static class CustomKeyBind { public const string ButtonName = "ChestNaming"; private const string DefaultPath = "<Keyboard>/n"; private static readonly FieldInfo ButtonsField = AccessTools.Field(typeof(ZInput), "m_buttons"); private static readonly MethodInfo PerformedMethod = AccessTools.Method(typeof(ZInput), "OnActionPerformed", (Type[])null, (Type[])null); private static readonly MethodInfo CanceledMethod = AccessTools.Method(typeof(ZInput), "OnActionCanceled", (Type[])null, (Type[])null); private static readonly FieldInfo KeysField = AccessTools.Field(typeof(KeyboardMouseSettings), "m_keys"); internal static bool Registered { get; private set; } public static void Apply(Harmony harmony) { TryPatchPostfix(harmony, typeof(ZInput), "Reset", "ZInput_Reset_Postfix"); TryPatchPrefix(harmony, typeof(KeyboardMouseSettings), "SetupKeys", "SetupKeys_Prefix"); EnsureRegistered(); } private static void TryPatchPostfix(Harmony harmony, Type type, string method, string handler) { TryPatch(harmony, type, method, handler, prefix: false); } private static void TryPatchPrefix(Harmony harmony, Type type, string method, string handler) { TryPatch(harmony, type, method, handler, prefix: true); } private static void TryPatch(Harmony harmony, Type type, string method, string handler, bool prefix) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 找不到 " + type.Name + "." + method + ",该补丁跳过")); return; } try { HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(CustomKeyBind), handler, (Type[])null, (Type[])null)); if (prefix) { harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } ChestNamingPlugin.Log.LogInfo((object)("[ChestNaming] 已挂载补丁 " + type.Name + "." + method + "(" + (prefix ? "prefix" : "postfix") + ")")); } catch (Exception arg) { ChestNamingPlugin.Log.LogError((object)$"[ChestNaming] 挂载 {type.Name}.{method} 失败:{arg}"); } } internal static bool EnsureRegistered() { try { return RegisterButton(ZInput.instance); } catch (Exception ex) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 注册按键失败:" + ex)); return false; } } private static void ZInput_Reset_Postfix(ZInput __instance) { try { RegisterButton(__instance); } catch (Exception ex) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 重建按键注册失败:" + ex)); } } private static bool RegisterButton(ZInput instance) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown if (instance == null || ButtonsField == null) { return false; } if (!(ButtonsField.GetValue(instance) is IDictionary dictionary)) { return false; } if (dictionary.Contains("ChestNaming")) { Registered = true; return true; } ButtonDef val = new ButtonDef("ChestNaming", "<Keyboard>/n", (string)null, (InputSource)170, false, true, -1f, -1f, "0.4"); dictionary.Add("ChestNaming", val); val.ButtonAction.Enable(); val.ButtonAction.performed += delegate(CallbackContext ctx) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) PerformedMethod?.Invoke(instance, new object[1] { ctx }); }; val.ButtonAction.canceled += delegate(CallbackContext ctx) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) CanceledMethod?.Invoke(instance, new object[1] { ctx }); }; Registered = true; ChestNamingPlugin.Log.LogInfo((object)"[ChestNaming] 已注册按键 ChestNaming(默认 <Keyboard>/n,可在设置-键盘与鼠标中改键)"); return true; } private static void SetupKeys_Prefix(KeyboardMouseSettings __instance) { try { if (!EnsureRegistered()) { ChestNamingPlugin.Log.LogWarning((object)"[ChestNaming] 按键尚未注册,本次设置页跳过注入(下次打开设置页会重试)"); } else { InjectRow(__instance); } } catch (Exception ex) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 注入设置页按键行失败:" + ex)); } } private static void InjectRow(KeyboardMouseSettings settings) { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0238: 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) if (KeysField == null) { return; } if (KeysField.GetValue(settings) is List<KeySetting> { Count: not 0 } list) { foreach (KeySetting item2 in list) { if (item2 != null && item2.m_keyName == "ChestNaming") { return; } } KeySetting val = list.Find((KeySetting k) => k != null && k.m_keyName == "AutoPickup") ?? list[0]; if ((Object)(object)val?.m_keyTransform == (Object)null) { ChestNamingPlugin.Log.LogWarning((object)"[ChestNaming] 找不到可克隆的模板按键行,注入跳过"); return; } Transform parent = ((Transform)val.m_keyTransform).parent; if ((Object)(object)parent == (Object)null) { ChestNamingPlugin.Log.LogWarning((object)"[ChestNaming] 模板行没有父节点,注入跳过"); return; } GameObject obj = Object.Instantiate<GameObject>(((Component)val.m_keyTransform).gameObject, parent); ((Object)obj).name = "KeyBinding_ChestNaming"; obj.SetActive(true); RectTransform val2 = (RectTransform)obj.transform; int num = list.IndexOf(val) + 1; ((Transform)val2).SetSiblingIndex(((Transform)val.m_keyTransform).GetSiblingIndex() + 1); KeySetting item = new KeySetting { m_keyName = "ChestNaming", m_keyTransform = val2, m_blockedButtons = (KeyCode[])(object)new KeyCode[0] }; string text = Patches.L("重命名箱子", "Rename container"); TMP_Text[] componentsInChildren = obj.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val3 in componentsInChildren) { if (!((Object)(object)((Component)val3).GetComponentInParent<Button>(true) != (Object)null)) { val3.text = text; } } list.Insert(num, item); LayoutGroup component = ((Component)parent).GetComponent<LayoutGroup>(); if ((Object)(object)component != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((parent is RectTransform) ? parent : null)); } else { Rect rect = val.m_keyTransform.rect; float num3 = ((Rect)(ref rect)).height; if (num3 <= 1f) { num3 = val.m_keyTransform.sizeDelta.y; } if (num3 <= 1f) { num3 = 32f; } val2.anchoredPosition = val.m_keyTransform.anchoredPosition + new Vector2(0f, 0f - num3); } ChestNamingPlugin.Log.LogInfo((object)($"[ChestNaming] 已注入设置页按键行:索引={num}/{list.Count}," + "父节点=" + ((Object)parent).name + ",布局组=" + (((Object)(object)component != (Object)null) ? ((object)component).GetType().Name : "无") + ",模板=" + val.m_keyName)); } else { ChestNamingPlugin.Log.LogWarning((object)"[ChestNaming] KeyboardMouseSettings.m_keys 为空,无法注入按键行"); } } } internal static class Patches { private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static ChestNameReceiver _receiver; public static void Apply(Harmony harmony) { Patch(harmony, typeof(Container), "GetHoverText", "GetHoverText_Postfix"); Patch(harmony, typeof(Container), "GetHoverName", "GetHoverName_Postfix"); Patch(harmony, typeof(InventoryGui), "UpdateContainer", "UpdateContainer_Postfix"); Patch(harmony, typeof(InventoryGui), "Update", "Update_Postfix"); } private static void Patch(Harmony harmony, Type type, string method, string postfix) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 找不到 " + type.Name + "." + method + ",该补丁跳过")); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Patches), postfix, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ChestNamingPlugin.Log.LogInfo((object)("[ChestNaming] 已挂载补丁 " + type.Name + "." + method)); } catch (Exception arg) { ChestNamingPlugin.Log.LogError((object)$"[ChestNaming] 挂载 {type.Name}.{method} 失败:{arg}"); } } private static void GetHoverText_Postfix(Container __instance, ref string __result) { if (!ChestNamingPlugin.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } try { string text = ChestNameStore.Get(__instance); if (!string.IsNullOrEmpty(text)) { string[] array = (__result ?? "").Split('\n'); array[0] = text; __result = string.Join("\n", array); } if (ChestNamingPlugin.ShowHoverHint.Value) { string text2 = Localize("[<color=yellow><b>$KEY_ChestNaming</b></color>] " + L("重命名", "Rename")); __result = __result + "\n" + text2; } } catch (Exception ex) { ChestNamingPlugin.Debug("[ChestNaming] GetHoverText 补丁出错:" + ex); } } private static void GetHoverName_Postfix(Container __instance, ref string __result) { if (!ChestNamingPlugin.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } try { string text = ChestNameStore.Get(__instance); if (!string.IsNullOrEmpty(text)) { __result = text; } } catch (Exception ex) { ChestNamingPlugin.Debug("[ChestNaming] GetHoverName 补丁出错:" + ex); } } private static void UpdateContainer_Postfix(InventoryGui __instance) { if (!ChestNamingPlugin.Enabled.Value || !ChestNamingPlugin.ShowInContainerTitle.Value || (Object)(object)__instance == (Object)null) { return; } try { if ((Object)(object)__instance.m_containerName == (Object)null) { return; } Container val = CurrentContainer(); if ((Object)(object)val == (Object)null) { return; } string displayName = ChestNameStore.GetDisplayName(val); if (!string.IsNullOrEmpty(displayName)) { string text = Localize(displayName); if (__instance.m_containerName.text != text) { __instance.m_containerName.text = text; } } } catch (Exception ex) { ChestNamingPlugin.Debug("[ChestNaming] UpdateContainer 补丁出错:" + ex); } } private static void Update_Postfix(InventoryGui __instance) { if (!ChestNamingPlugin.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } try { if (!TextInput.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus())) { Container val = CurrentContainer(); if (!((Object)(object)val == (Object)null) && ZInput.GetButtonDown("ChestNaming")) { OpenDialog(val); } } } catch (Exception ex) { ChestNamingPlugin.Log.LogError((object)("[ChestNaming] 快捷键处理出错:" + ex)); } } private static void OpenDialog(Container c) { if ((Object)(object)TextInput.instance == (Object)null) { ChestNamingPlugin.Log.LogWarning((object)"[ChestNaming] TextInput 实例不存在,无法弹出输入框"); return; } _receiver = new ChestNameReceiver(c); string text = L("输入箱子名字(留空则恢复默认)", "Enter a name for this container (empty to reset)"); TextInput.instance.RequestText((TextReceiver)(object)_receiver, text, Mathf.Max(1, ChestNamingPlugin.CharacterLimit.Value)); ChestNamingPlugin.Debug("[ChestNaming] 已弹出改名输入框"); } internal static void OpenDialogForHover(Container c) { OpenDialog(c); } private static Container CurrentContainer() { try { if ((Object)(object)InventoryGui.instance == (Object)null) { return null; } if (CurrentContainerField == null) { return null; } object? value = CurrentContainerField.GetValue(InventoryGui.instance); return (Container)((value is Container) ? value : null); } catch { return null; } } internal static bool IsChinese() { try { Localization instance = Localization.instance; string text = ((instance != null) ? instance.GetSelectedLanguage() : null); return text == "Chinese" || text == "Chinese_Trad"; } catch { return false; } } internal static string L(string zh, string en) { if (!IsChinese()) { return en; } return zh; } private static string Localize(string text) { try { return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } catch { return text; } } internal static void Message(string msg) { try { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, msg, 0, (Sprite)null, false); } } catch { } } }