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 NameThis v1.1.0
NameThis.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [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("NameThis")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("NameThis")] [assembly: AssemblyTitle("NameThis")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 NameThis { internal static class JotunnSource { internal static void Collect(Action<string, string> claim) { foreach (CustomItem item in ModRegistry.GetItems()) { if ((Object)(object)((item != null) ? item.ItemPrefab : null) != (Object)null) { string name = ((Object)item.ItemPrefab).name; BepInPlugin sourceMod = ((CustomEntity)item).SourceMod; claim(name, (sourceMod != null) ? sourceMod.GUID : null); } } foreach (CustomPrefab prefab in ModRegistry.GetPrefabs()) { if ((Object)(object)((prefab != null) ? prefab.Prefab : null) != (Object)null) { string name2 = ((Object)prefab.Prefab).name; BepInPlugin sourceMod2 = ((CustomEntity)prefab).SourceMod; claim(name2, (sourceMod2 != null) ? sourceMod2.GUID : null); } } } } [BepInPlugin("local.namethis", "NameThis", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string GUID = "local.namethis"; public const string NAME = "NameThis"; public const string VERSION = "1.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<string> Format; internal static ConfigEntry<string> VanillaLabel; internal static ConfigEntry<string> UnknownLabel; internal static ConfigEntry<string> Overrides; internal static ConfigEntry<bool> DumpToLog; private void Awake() { //IL_0109: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ogolne", "Wlaczony", true, "Pokazuje w opisie przedmiotu, z jakiego moda pochodzi."); Format = ((BaseUnityPlugin)this).Config.Bind<string>("Ogolne", "Format", "<size=80%><color=#9a9a9a>{0}</color></size>", "Wyglad napisu. {0} = nazwa moda. Obsluguje znaczniki <size>, <color>, <i>."); VanillaLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Ogolne", "Napis dla gry", "Vanilla", "Napis dla przedmiotow z samej gry."); UnknownLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Ogolne", "Napis dla nieznanych", "Mod", "Napis, gdy przedmiot na pewno nie jest z gry, ale nie da sie ustalic moda."); Overrides = ((BaseUnityPlugin)this).Config.Bind<string>("Ogolne", "Wlasne nazwy modow", "", "Zmiana wyswietlanej nazwy moda: GUID=Nazwa, oddzielone ';'. Np. Therzie.Warfare=Therzie Warfare"); DumpToLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostyka", "Zrzut mapy do logu", false, "Po wczytaniu swiata zapisuje do LogOutput.log, ile przedmiotow przypisano do kazdego moda."); Overrides.SettingChanged += delegate { Sources.ResetNames(); }; new Harmony("local.namethis").PatchAll(typeof(Plugin).Assembly); } } internal static class Sources { [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake { [HarmonyPriority(800)] private static void Prefix(ObjectDB __instance) { if (_vanillaCaptured || __instance.m_items == null || __instance.m_items.Count == 0) { return; } foreach (GameObject item in __instance.m_items) { if ((Object)(object)item != (Object)null) { Vanilla.Add(((Object)item).name); } } _vanillaCaptured = true; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake { private static void Postfix() { _byPrefab = null; PrefabByShared.Clear(); if (!((Object)(object)ZNetScene.instance == (Object)null)) { if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) { ((MonoBehaviour)ZNetScene.instance).StartCoroutine(BuildSoon()); } if (Plugin.DumpToLog.Value) { ((MonoBehaviour)ZNetScene.instance).StartCoroutine(DumpLater()); } } } } private static readonly HashSet<string> Vanilla = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static bool _vanillaCaptured; private static Dictionary<string, PluginInfo> _byPrefab; private static readonly Dictionary<string, string> Labels = new Dictionary<string, string>(); private static readonly Dictionary<SharedData, string> PrefabByShared = new Dictionary<SharedData, string>(); private static Dictionary<string, string> _nameOverrides; private static readonly HashSet<string> IgnoredOwners = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "com.jotunn.jotunn", "ValheimModding.YamlDotNet", "ValheimModding.JsonDotNET", "local.namethis" }; internal static void ResetNames() { Labels.Clear(); _nameOverrides = null; } internal static string LabelFor(ItemData item) { string text = PrefabName(item); if (text == null) { return null; } if (Vanilla.Contains(text)) { return Plugin.VanillaLabel.Value; } if (!_vanillaCaptured) { return null; } PluginInfo val = OwnerOf(text); if (val != null) { return DisplayName(val); } return Plugin.UnknownLabel.Value; } private static string PrefabName(ItemData item) { if (item == null || item.m_shared == null) { return null; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return null; } if (PrefabByShared.Count == 0) { foreach (GameObject item2 in instance.m_items) { ItemDrop val = (((Object)(object)item2 == (Object)null) ? null : item2.GetComponent<ItemDrop>()); if ((Object)(object)val != (Object)null && val.m_itemData?.m_shared != null) { PrefabByShared[val.m_itemData.m_shared] = ((Object)item2).name; } } } if (PrefabByShared.TryGetValue(item.m_shared, out var value)) { return value; } foreach (GameObject item3 in instance.m_items) { ItemDrop val2 = (((Object)(object)item3 == (Object)null) ? null : item3.GetComponent<ItemDrop>()); if ((Object)(object)val2 != (Object)null && val2.m_itemData?.m_shared?.m_name == item.m_shared.m_name) { return ((Object)item3).name; } } return null; } internal static PluginInfo OwnerOf(string prefab) { if (_byPrefab == null) { Build(); } if (!_byPrefab.TryGetValue(prefab, out var value)) { return null; } return value; } private static void Build() { _byPrefab = new Dictionary<string, PluginInfo>(StringComparer.OrdinalIgnoreCase); Stopwatch stopwatch = Stopwatch.StartNew(); Dictionary<Assembly, PluginInfo> dictionary = new Dictionary<Assembly, PluginInfo>(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if ((Object)(object)((value != null) ? value.Instance : null) != (Object)null && !IgnoredOwners.Contains(value.Metadata.GUID)) { dictionary[((object)value.Instance).GetType().Assembly] = value; } } Dictionary<AssetBundle, PluginInfo> bundleOwner = new Dictionary<AssetBundle, PluginInfo>(); try { FromJotunn(); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Jotunn: " + ex.Message)); } try { FromStaticFields(dictionary, bundleOwner); } catch (Exception ex2) { Plugin.Log.LogDebug((object)("Pola: " + ex2.Message)); } try { FromBundles(bundleOwner); } catch (Exception ex3) { Plugin.Log.LogDebug((object)("Paczki: " + ex3.Message)); } Plugin.Log.LogInfo((object)$"Mapa zrodel przedmiotow: {_byPrefab.Count} prefabow z modow, {Vanilla.Count} z gry ({stopwatch.ElapsedMilliseconds} ms)."); } private static void Claim(string prefab, PluginInfo owner) { if (!string.IsNullOrEmpty(prefab) && owner != null && !Vanilla.Contains(prefab) && !_byPrefab.ContainsKey(prefab)) { _byPrefab[prefab] = owner; } } private static void FromJotunn() { if (!Chainloader.PluginInfos.ContainsKey("com.jotunn.jotunn")) { return; } JotunnSource.Collect(delegate(string prefab, string guid) { if (guid != null && Chainloader.PluginInfos.TryGetValue(guid, out var value)) { Claim(prefab, value); } }); } private static void FromStaticFields(Dictionary<Assembly, PluginInfo> byAssembly, Dictionary<AssetBundle, PluginInfo> bundleOwner) { Dictionary<PluginInfo, HashSet<string>> dictionary = new Dictionary<PluginInfo, HashSet<string>>(); foreach (KeyValuePair<Assembly, PluginInfo> item in byAssembly) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); int vanillaRefs = 0; Type[] array; try { array = item.Key.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array2 = array; foreach (Type type in array2) { if (type.ContainsGenericParameters) { continue; } FieldInfo[] fields; try { fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } FieldInfo[] array3 = fields; foreach (FieldInfo fieldInfo in array3) { if (!fieldInfo.IsLiteral && Interesting(fieldInfo.FieldType)) { object value; try { value = fieldInfo.GetValue(null); } catch { continue; } Visit(value, 0, hashSet, item.Value, bundleOwner, ref vanillaRefs); } } } if (vanillaRefs <= 50 && hashSet.Count > 0) { dictionary[item.Value] = hashSet; } } Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); foreach (HashSet<string> value3 in dictionary.Values) { foreach (string item2 in value3) { dictionary2[item2] = ((!dictionary2.TryGetValue(item2, out var value2)) ? 1 : (value2 + 1)); } } foreach (KeyValuePair<PluginInfo, HashSet<string>> item3 in dictionary) { foreach (string item4 in item3.Value) { if (dictionary2[item4] == 1) { Claim(item4, item3.Key); } } } } private static bool Interesting(Type t) { if (t.IsPrimitive || t.IsEnum || t == typeof(string)) { return false; } if (typeof(Delegate).IsAssignableFrom(t)) { return false; } return true; } private static void Visit(object v, int depth, HashSet<string> names, PluginInfo owner, Dictionary<AssetBundle, PluginInfo> bundleOwner, ref int vanillaRefs) { if (v == null || depth > 2) { return; } GameObject val = (GameObject)((v is GameObject) ? v : null); if (val != null) { if (!((Object)(object)val == (Object)null)) { if (Vanilla.Contains(((Object)val).name)) { vanillaRefs++; } else if ((Object)(object)val.GetComponent<ItemDrop>() != (Object)null) { names.Add(((Object)val).name); } } return; } AssetBundle val2 = (AssetBundle)((v is AssetBundle) ? v : null); if (val2 != null) { if ((Object)(object)val2 != (Object)null && !bundleOwner.ContainsKey(val2)) { bundleOwner[val2] = owner; } } else { if (v is Object || v is string) { return; } if (v is IDictionary dictionary) { int num = 0; { foreach (DictionaryEntry item in dictionary) { if (++num > 5000) { break; } Visit(item.Value, depth + 1, names, owner, bundleOwner, ref vanillaRefs); } return; } } if (v is IEnumerable enumerable) { int num2 = 0; { foreach (object item2 in enumerable) { if (++num2 > 5000) { break; } Visit(item2, depth + 1, names, owner, bundleOwner, ref vanillaRefs); } return; } } if (depth >= 2) { return; } Type type = v.GetType(); if (type.IsValueType || type.Assembly == typeof(object).Assembly) { return; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(GameObject)) || !(fieldInfo.FieldType != typeof(AssetBundle))) { object value; try { value = fieldInfo.GetValue(v); } catch { continue; } Visit(value, depth + 1, names, owner, bundleOwner, ref vanillaRefs); } } } } private static void FromBundles(Dictionary<AssetBundle, PluginInfo> bundleOwner) { List<PluginInfo> mods = Chainloader.PluginInfos.Values.Where((PluginInfo p) => (Object)(object)((p != null) ? p.Instance : null) != (Object)null && !IgnoredOwners.Contains(p.Metadata.GUID)).ToList(); foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle == (Object)null) { continue; } if (!bundleOwner.TryGetValue(allLoadedAssetBundle, out var value)) { value = GuessOwner(((Object)allLoadedAssetBundle).name, mods); } if (value == null) { continue; } string[] allAssetNames; try { allAssetNames = allLoadedAssetBundle.GetAllAssetNames(); } catch { continue; } string[] array = allAssetNames; foreach (string text in array) { if (text.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) { Claim(Path.GetFileNameWithoutExtension(text), value); } } } } private static PluginInfo GuessOwner(string bundleName, List<PluginInfo> mods) { string text = Norm(Path.GetFileNameWithoutExtension(bundleName ?? "")); if (text.Length < 3) { return null; } PluginInfo result = null; int num = 0; foreach (PluginInfo mod in mods) { foreach (string item in Tokens(mod)) { int num2 = 0; if (item == text) { num2 = 100 + item.Length; } else if (item.Length >= 4 && text.Contains(item)) { num2 = 50 + item.Length; } else if (text.Length >= 4 && item.Contains(text)) { num2 = 40 + text.Length; } if (num2 > num) { num = num2; result = mod; } } } return result; } private static IEnumerable<string> Tokens(PluginInfo p) { yield return Norm(p.Metadata.Name); string[] array = p.Metadata.GUID.Split('.', '-', '_'); foreach (string s in array) { yield return Norm(s); } string fileName = Path.GetFileName(Path.GetDirectoryName(p.Location) ?? ""); array = fileName.Split('-'); foreach (string s2 in array) { yield return Norm(s2); } } private static string Norm(string s) { StringBuilder stringBuilder = new StringBuilder(); string text = s ?? ""; foreach (char c in text) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } internal static string DisplayName(PluginInfo p) { if (Labels.TryGetValue(p.Metadata.GUID, out var value)) { return value; } string text = null; if (_nameOverrides == null) { _nameOverrides = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string[] array = Plugin.Overrides.Value.Split(';'); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num > 0) { _nameOverrides[text2.Substring(0, num).Trim()] = text2.Substring(num + 1).Trim(); } } } if (_nameOverrides.TryGetValue(p.Metadata.GUID, out var value2)) { text = value2; } if (text == null) { text = ThunderstoreName(p); } if (string.IsNullOrEmpty(text)) { text = Pretty(p.Metadata.Name); } Labels[p.Metadata.GUID] = text; return text; } private static string ThunderstoreName(PluginInfo p) { try { string directoryName = Path.GetDirectoryName(p.Location); for (int i = 0; i < 3; i++) { if (string.IsNullOrEmpty(directoryName)) { break; } string path = Path.Combine(directoryName, "manifest.json"); if (File.Exists(path)) { Match match = Regex.Match(File.ReadAllText(path), "\"name\"\\s*:\\s*\"([^\"]+)\""); if (match.Success) { return Pretty(match.Groups[1].Value); } } if (!Path.GetFileName(Path.GetDirectoryName(directoryName) ?? "").Equals("plugins", StringComparison.OrdinalIgnoreCase)) { directoryName = Path.GetDirectoryName(directoryName); continue; } break; } } catch { } return null; } internal static string Pretty(string s) { if (string.IsNullOrEmpty(s)) { return s; } s = s.Replace('_', ' ').Trim(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < s.Length; i++) { char c = s[i]; if (i > 0 && char.IsUpper(c) && char.IsLower(s[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(c); } return Regex.Replace(stringBuilder.ToString(), "\\s+", " "); } private static IEnumerator BuildSoon() { yield return null; yield return null; if (_byPrefab == null && (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count > 0) { Build(); } } private static IEnumerator DumpLater() { yield return (object)new WaitForSeconds(5f); ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { yield break; } Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); foreach (GameObject item in instance.m_items) { ItemDrop val = (((Object)(object)item == (Object)null) ? null : item.GetComponent<ItemDrop>()); if (!((Object)(object)val == (Object)null)) { string key = LabelFor(val.m_itemData) ?? "?"; if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<string>()); } value.Add(((Object)item).name); } } StringBuilder stringBuilder = new StringBuilder("Zrodla przedmiotow (NameThis):\n"); foreach (KeyValuePair<string, List<string>> item2 in dictionary.OrderByDescending((KeyValuePair<string, List<string>> k) => k.Value.Count)) { stringBuilder.AppendLine(string.Format(" {0}: {1} np. {2}", item2.Key, item2.Value.Count, string.Join(", ", item2.Value.Take(6)))); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class ItemData_GetTooltip { [HarmonyPriority(0)] private static void Postfix(ItemData item, bool appending, ref string __result) { if (!appending && Plugin.Enabled.Value && item != null && __result != null) { string text; try { text = Sources.LabelFor(item); } catch (Exception ex) { Plugin.Log.LogDebug((object)ex); return; } if (!string.IsNullOrEmpty(text)) { __result = __result.TrimEnd() + "\n\n" + string.Format(Plugin.Format.Value, text); } } } } }