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 CatosMobDropsEditor v0.1.2
CatosMobDropsEditor.dll
Decompiled 3 weeks agousing System; 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.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("CatosMobDropsEditor")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2+0289ac670986326c262dd31306333b216b0ff2db")] [assembly: AssemblyProduct("CatosMobDropsEditor")] [assembly: AssemblyTitle("CatosMobDropsEditor")] [assembly: AssemblyVersion("0.1.2.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 CatosMobDropsEditor { [BepInPlugin("catos.mobdropseditor", "Cato's Mob Drops Editor", "0.1.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private enum DropOperation { Add, Edit, Remove, Replace, Disabled } private sealed class DropRule { public string MobPrefab { get; } public DropOperation Operation { get; } public string DropPrefab { get; } public int AmountMin { get; } public int AmountMax { get; } public float ChancePercent { get; } public bool ScaleByLevel { get; } public bool OnePerPlayer { get; } public DropRule(string mobPrefab, DropOperation operation, string dropPrefab, int amountMin, int amountMax, float chancePercent, bool scaleByLevel, bool onePerPlayer) { MobPrefab = mobPrefab; Operation = operation; DropPrefab = dropPrefab; AmountMin = amountMin; AmountMax = amountMax; ChancePercent = chancePercent; ScaleByLevel = scaleByLevel; OnePerPlayer = onePerPlayer; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwakePatch { private static void Postfix() { GenerateItemReferenceFile(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { LoadAuthorityRules("server config"); } } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNetAwakePatch { private static void Prefix() { _effectiveRules = Array.Empty<DropRule>(); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class ZNetOnDestroyPatch { private static void Postfix() { _effectiveRules = Array.Empty<DropRule>(); } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private static class CharacterDropGenerateDropListPatch { private static void Prefix(CharacterDrop __instance, out List<Drop>? __state) { __state = null; if (_effectiveRules.Count == 0) { return; } string mobName = ((Object)((Component)__instance).gameObject).name.Replace("(Clone)", string.Empty).Trim(); if (_effectiveRules.Any((DropRule rule) => rule.MobPrefab.Equals(mobName, StringComparison.OrdinalIgnoreCase))) { __state = __instance.m_drops; __instance.m_drops = ((IEnumerable<Drop>)__state).Select((Func<Drop, Drop>)((Drop drop) => new Drop { m_prefab = drop.m_prefab, m_amountMin = drop.m_amountMin, m_amountMax = drop.m_amountMax, m_chance = drop.m_chance, m_onePerPlayer = drop.m_onePerPlayer, m_levelMultiplier = drop.m_levelMultiplier, m_dontScale = drop.m_dontScale })).ToList(); ApplyRulesToLiveDropComponent(__instance); } } private static void Postfix(CharacterDrop __instance, List<Drop>? __state) { if (__state != null) { __instance.m_drops = __state; } } private static Exception Finalizer(CharacterDrop __instance, List<Drop>? __state, Exception __exception) { if (__state != null) { __instance.m_drops = __state; } return __exception; } } public const string Guid = "catos.mobdropseditor"; public const string Name = "Cato's Mob Drops Editor"; public const string Version = "0.1.2"; private static Plugin? _instance; private static ConfigEntry<string>? _overrides; private static IReadOnlyList<DropRule> _effectiveRules = Array.Empty<DropRule>(); private static readonly Harmony Harmony = new Harmony("catos.mobdropseditor"); private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown _instance = this; _overrides = ((BaseUnityPlugin)this).Config.Bind<string>("Drops", "Overrides", "", new ConfigDescription("One rule per line: MobPrefab|Operation|DropPrefab|Min|Max|ChancePercent|ScaleByLevel|OnePerPlayer. To disable all drops from a mob, use MobPrefab|Disabled. Blank means vanilla behavior.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, ReadOnly = true } })); _overrides.SettingChanged += delegate { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { LoadAuthorityRules("server config changed"); } }; Harmony.PatchAll(); SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Cato's Mob Drops Editor 0.1.2 loaded. Client config edits do not activate drop rules in multiplayer."); } private void OnDestroy() { SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized; Harmony.UnpatchSelf(); } private static void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs args) { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { LoadAuthorityRules("server synchronization"); } } private static void LoadAuthorityRules(string source) { if (_overrides != null) { _effectiveRules = ParseRules(_overrides.Value).ToList(); ((BaseUnityPlugin)_instance).Logger.LogInfo((object)$"Loaded {_effectiveRules.Count} drop rule(s) from {source}."); } } private static void ApplyRule(GameObject mob, CharacterDrop characterDrop, DropRule rule) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown Drop val = ((IEnumerable<Drop>)characterDrop.m_drops).FirstOrDefault((Func<Drop, bool>)((Drop drop) => (Object)(object)drop.m_prefab != (Object)null && ((Object)drop.m_prefab).name.Equals(rule.DropPrefab, StringComparison.OrdinalIgnoreCase))); switch (rule.Operation) { default: return; case DropOperation.Disabled: characterDrop.m_drops.Clear(); return; case DropOperation.Remove: characterDrop.m_drops.RemoveAll((Drop drop) => (Object)(object)drop.m_prefab != (Object)null && ((Object)drop.m_prefab).name.Equals(rule.DropPrefab, StringComparison.OrdinalIgnoreCase)); return; case DropOperation.Replace: characterDrop.m_drops.Clear(); val = null; break; case DropOperation.Edit: if (val == null) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)("Cannot edit drop '" + rule.DropPrefab + "' on '" + ((Object)mob).name + "': it is not in the vanilla/current drop table.")); } else { SetDrop(val, rule); } return; case DropOperation.Add: break; } GameObject prefab = ZNetScene.instance.GetPrefab(rule.DropPrefab); if ((Object)(object)prefab == (Object)null) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)("Drop prefab '" + rule.DropPrefab + "' was not found; skipping rule for '" + ((Object)mob).name + "'.")); return; } if (val != null) { characterDrop.m_drops.Remove(val); } Drop val2 = new Drop { m_prefab = prefab }; SetDrop(val2, rule); characterDrop.m_drops.Add(val2); } private static void ApplyRulesToLiveDropComponent(CharacterDrop characterDrop) { if (_overrides == null) { return; } string mobName = ((Object)((Component)characterDrop).gameObject).name.Replace("(Clone)", string.Empty).Trim(); List<DropRule> list = _effectiveRules.Where((DropRule rule) => rule.MobPrefab.Equals(mobName, StringComparison.OrdinalIgnoreCase)).ToList(); foreach (DropRule item in list) { ApplyRule(((Component)characterDrop).gameObject, characterDrop, item); } if (list.Count > 0) { ((BaseUnityPlugin)_instance).Logger.LogInfo((object)($"Generating drops for '{mobName}' with {list.Count} configured rule(s): " + string.Join(", ", characterDrop.m_drops.Select((Drop drop) => (!((Object)(object)drop.m_prefab != (Object)null)) ? "<missing>" : ((Object)drop.m_prefab).name)))); } } private static void SetDrop(Drop drop, DropRule rule) { drop.m_amountMin = rule.AmountMin; drop.m_amountMax = rule.AmountMax; drop.m_chance = rule.ChancePercent / 100f; drop.m_levelMultiplier = rule.ScaleByLevel; drop.m_onePerPlayer = rule.OnePerPlayer; } private static IEnumerable<DropRule> ParseRules(string value) { string[] array = value.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length != 0 && !text2.StartsWith("#") && !text2.StartsWith("//")) { string[] array2 = (from field in text2.Split(new char[1] { '|' }) select field.Trim()).ToArray(); DropOperation result; int result2; int result3; float result4; bool result5; bool result6; if (array2.Length == 2 && array2[1].Equals("Disabled", StringComparison.OrdinalIgnoreCase)) { yield return new DropRule(array2[0], DropOperation.Disabled, string.Empty, 1, 1, 0f, scaleByLevel: false, onePerPlayer: false); } else if (array2.Length != 8 || !Enum.TryParse<DropOperation>(array2[1], ignoreCase: true, out result) || !int.TryParse(array2[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out result2) || !int.TryParse(array2[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out result3) || !float.TryParse(array2[5], NumberStyles.Float, CultureInfo.InvariantCulture, out result4) || !bool.TryParse(array2[6], out result5) || !bool.TryParse(array2[7], out result6)) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)("Invalid drop rule (expected 8 pipe-separated fields): " + text)); } else if (result2 < 1 || result3 < result2 || result4 < 0f || result4 > 100f) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)("Invalid amount/chance in drop rule: " + text)); } else { yield return new DropRule(array2[0], result, array2[2], result2, result3, result4, result5, result6); } } } } private static void GenerateItemReferenceFile() { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } try { var list = (from @group in (from prefab in ZNetScene.instance.m_prefabs where (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<ItemDrop>() != (Object)null select new { Prefab = ((Object)prefab).name, DisplayName = (prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name ?? string.Empty) }).GroupBy(item => item.Prefab, StringComparer.OrdinalIgnoreCase) select @group.First()).OrderBy(item => item.Prefab, StringComparer.OrdinalIgnoreCase).ToList(); List<string> list2 = new List<string> { "# Cato's Mob Drops Editor - generated item prefab reference", "# Use the Prefab ID in drop rules, not the localized display name.", "# Generated from the live Valheim ZNetScene registry, including loaded modded items.", "# Jotunn reference: https://valheim-modding.github.io/Jotunn/data/objects/item-list.html", "#", "# Prefab ID | Display name" }; list2.AddRange(list.Select(item => item.Prefab + " | " + StripRichText(item.DisplayName))); string text = Path.Combine(Paths.ConfigPath, "catos.mobdropseditor.item-prefabs.txt"); File.WriteAllLines(text, list2); ((BaseUnityPlugin)_instance).Logger.LogInfo((object)$"Generated item prefab reference with {list.Count} entries: {text}"); } catch (Exception ex) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)("Could not generate the item prefab reference: " + ex.Message)); } } private static string StripRichText(string value) { string text = value; while (true) { int num = text.IndexOf('<'); if (num < 0) { return text; } int num2 = text.IndexOf('>', num); if (num2 < 0) { break; } text = text.Remove(num, num2 - num + 1); } return text; } } }