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 Razaotium Client Side v1.0.2
RazaotiumClientSide.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace Razaotium.ClientSide; [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("razaotium.valheim.client_side", "Razaotium Client Side", "1.0.2")] public class RazaotiumClientSidePlugin : BaseUnityPlugin { private enum Toggle { Off, On } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private static class CharacterDropGenerateDropListPatch { private static bool Prefix(CharacterDrop __instance, ref List<KeyValuePair<GameObject, int>> __result) { if (ShouldBlock(__instance, out var prefab, out var requiredTier, out var playerTier)) { __result = new List<KeyValuePair<GameObject, int>>(); if (_logBlockedDrops.Value) { ((BaseUnityPlugin)_instance).Logger.LogInfo((object)$"Blocked drops from {prefab}: creature tier {requiredTier}, player tier {playerTier}."); } return false; } return true; } } public const string PluginGuid = "razaotium.valheim.client_side"; public const string PluginName = "Razaotium Client Side"; public const string PluginVersion = "1.0.2"; private const string DefaultCreatureTiers = "Greydwarf=1,Greydwarf_Elite=1,Greydwarf_Shaman=1,Troll=1,Ghost=1,Skeleton=1,Skeleton_Poison=1,RancidRemains=1,Blob=2,BlobElite=2,Draugr=2,Draugr_Elite=2,Leech=2,Surtling=2,Wraith=2,Abomination=2,Wolf=3,Fenring=3,Fenring_Cultist=3,Ulv=3,Bat=3,Hatchling=3,StoneGolem=3,Deathsquito=4,Goblin=4,GoblinArcher=4,GoblinBrute=4,GoblinShaman=4,Lox=4,Growth=4,Seeker=5,SeekerBrute=5,SeekerBrood=5,Gjall=5,Tick=5,Dverger=5,DvergerMage=5,DvergerMageFire=5,DvergerMageIce=5,DvergerMageSupport=5,DvergerRogue=5,Charred_Archer=6,Charred_Melee=6,Charred_Mage=6,Charred_Twitcher=6,Morgen=6,FallenValkyrie=6,Volture=6,Asksvin=6,BlobLava=6,BonemawSerpent=6,gd_king=2,Bonemass=3,Dragon=4,GoblinKing=5,SeekerQueen=6,Fader=6"; private static ConfigEntry<Toggle> _lockConfiguration; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _useKillerProgress; private static ConfigEntry<float> _closestPlayerFallbackRange; private static ConfigEntry<bool> _allowUnknownCreatures; private static ConfigEntry<bool> _includeBossDrops; private static ConfigEntry<bool> _logBlockedDrops; private static ConfigEntry<string> _tierKeys; private static ConfigEntry<string> _creatureTiers; private static readonly FieldInfo LastHitField = AccessTools.Field(typeof(Character), "m_lastHit"); private static readonly Dictionary<string, int> ParsedCreatureTiers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<int, string> ParsedTierKeys = new Dictionary<int, string>(); private static RazaotiumClientSidePlugin _instance; private Harmony _harmony; private void Awake() { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown _instance = this; _lockConfiguration = BindSynced("General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); _enabled = BindSynced("General", "Enabled", defaultValue: true, "Enable biome-based drop blocking."); _useKillerProgress = BindSynced("General", "UseKillerProgress", defaultValue: true, "Use the player who landed the killing hit. If false, use the closest player."); _closestPlayerFallbackRange = BindSynced("General", "ClosestPlayerFallbackRange", 80f, "Range used to find a nearby player when the killer is not a player or cannot be found."); _allowUnknownCreatures = BindSynced("General", "AllowUnknownCreatures", defaultValue: true, "If true, creatures not listed in CreatureTiers keep their drops."); _includeBossDrops = BindSynced("General", "IncludeBossDrops", defaultValue: false, "If true, listed boss prefabs are also blocked by progression."); _logBlockedDrops = BindSynced("General", "LogBlockedDrops", defaultValue: true, "Log when a creature drop is blocked."); _tierKeys = BindSynced("Progression", "TierKeys", "1=defeated_eikthyr,2=defeated_gdking,3=defeated_bonemass,4=defeated_dragon,5=defeated_goblinking,6=defeated_queen", "Tier unlock keys. Tier 0 is always unlocked. Defaults: 1 Black Forest, 2 Swamp, 3 Mountains, 4 Plains, 5 Mistlands, 6 Ashlands."); _creatureTiers = BindSynced("Progression", "CreatureTiers", "Greydwarf=1,Greydwarf_Elite=1,Greydwarf_Shaman=1,Troll=1,Ghost=1,Skeleton=1,Skeleton_Poison=1,RancidRemains=1,Blob=2,BlobElite=2,Draugr=2,Draugr_Elite=2,Leech=2,Surtling=2,Wraith=2,Abomination=2,Wolf=3,Fenring=3,Fenring_Cultist=3,Ulv=3,Bat=3,Hatchling=3,StoneGolem=3,Deathsquito=4,Goblin=4,GoblinArcher=4,GoblinBrute=4,GoblinShaman=4,Lox=4,Growth=4,Seeker=5,SeekerBrute=5,SeekerBrood=5,Gjall=5,Tick=5,Dverger=5,DvergerMage=5,DvergerMageFire=5,DvergerMageIce=5,DvergerMageSupport=5,DvergerRogue=5,Charred_Archer=6,Charred_Melee=6,Charred_Mage=6,Charred_Twitcher=6,Morgen=6,FallenValkyrie=6,Volture=6,Asksvin=6,BlobLava=6,BonemawSerpent=6,gd_king=2,Bonemass=3,Dragon=4,GoblinKing=5,SeekerQueen=6,Fader=6", "Creature prefab to tier mapping. Format: Prefab=Tier,Prefab=Tier. Creatures whose tier is above the player's unlocked tier drop nothing."); ReloadConfig(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { ReloadConfig(); }; _harmony = new Harmony("razaotium.valheim.client_side"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded with {2} configured creatures.", "Razaotium Client Side", "1.0.2", ParsedCreatureTiers.Count)); } private ConfigEntry<T> BindSynced<T>(string section, string key, T defaultValue, string description) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown ConfigFile config = ((BaseUnityPlugin)this).Config; string text = description + " [Synced with Server]"; object[] array = new object[1]; ConfigurationManagerAttributes val = new ConfigurationManagerAttributes(); val.IsAdminOnly = true; array[0] = val; return config.Bind<T>(section, key, defaultValue, new ConfigDescription(text, (AcceptableValueBase)null, array)); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } private static void ReloadConfig() { ParsedTierKeys.Clear(); int result; foreach (KeyValuePair<string, string> item in SplitPairs(_tierKeys.Value)) { if (int.TryParse(item.Key, out result) && !string.IsNullOrWhiteSpace(item.Value)) { ParsedTierKeys[result] = item.Value.Trim(); } } ParsedCreatureTiers.Clear(); foreach (KeyValuePair<string, string> item2 in SplitPairs(_creatureTiers.Value)) { if (int.TryParse(item2.Value, out result) && !string.IsNullOrWhiteSpace(item2.Key)) { ParsedCreatureTiers[item2.Key.Trim()] = result; } } } private static IEnumerable<KeyValuePair<string, string>> SplitPairs(string value) { if (string.IsNullOrWhiteSpace(value)) { yield break; } try { string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string raw in array) { string[] parts = raw.Split(new char[1] { '=' }, 2); if (parts.Length == 2) { yield return new KeyValuePair<string, string>(parts[0].Trim(), parts[1].Trim()); } } } finally { } } private static bool ShouldBlock(CharacterDrop dropper, out string prefab, out int requiredTier, out int playerTier) { prefab = GetPrefabName(dropper); requiredTier = 0; playerTier = 0; if (!_enabled.Value || string.IsNullOrWhiteSpace(prefab)) { return false; } if (!ParsedCreatureTiers.TryGetValue(prefab, out requiredTier)) { return !_allowUnknownCreatures.Value; } if (!_includeBossDrops.Value && IsBossPrefab(prefab)) { return false; } Player player = FindProgressPlayer(dropper); playerTier = GetUnlockedTier(player); return requiredTier > playerTier; } private static Player FindProgressPlayer(CharacterDrop dropper) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) Character component = ((Component)dropper).GetComponent<Character>(); if (_useKillerProgress.Value && (Object)(object)component != (Object)null && LastHitField != null) { object? value = LastHitField.GetValue(component); HitData val = (HitData)((value is HitData) ? value : null); Character val2 = ((val != null && val.HaveAttacker()) ? val.GetAttacker() : null); Player val3 = (Player)(object)((val2 is Player) ? val2 : null); if ((Object)(object)val3 != (Object)null) { return val3; } } return Player.GetClosestPlayer(((Component)dropper).transform.position, _closestPlayerFallbackRange.Value); } private static int GetUnlockedTier(Player player) { int num = 0; foreach (KeyValuePair<int, string> item in ParsedTierKeys.OrderBy((KeyValuePair<int, string> entry) => entry.Key)) { if (HasKey(player, item.Value)) { num = Math.Max(num, item.Key); } } return num; } private static bool HasKey(Player player, string key) { if (string.IsNullOrWhiteSpace(key)) { return true; } if ((Object)(object)player != (Object)null && ((Humanoid)player).HaveUniqueKey(key)) { return true; } return (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(key); } private static string GetPrefabName(CharacterDrop dropper) { string name = ((Object)((Component)dropper).gameObject).name; return (name == null) ? string.Empty : name.Replace("(Clone)", string.Empty).Trim(); } private static bool IsBossPrefab(string prefab) { return prefab.Equals("Eikthyr", StringComparison.OrdinalIgnoreCase) || prefab.Equals("gd_king", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Bonemass", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Dragon", StringComparison.OrdinalIgnoreCase) || prefab.Equals("GoblinKing", StringComparison.OrdinalIgnoreCase) || prefab.Equals("SeekerQueen", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Fader", StringComparison.OrdinalIgnoreCase); } }