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 StarLevelSystem v1.31.1
plugins/StarLevelSystem.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Jotunn; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using MonoMod.Utils; using SimpleJson; using SoftReferenceableAssets; using Splatform; using StarLevelSystem.Data; using StarLevelSystem.Modifiers; using StarLevelSystem.Modifiers.Shared; using StarLevelSystem.common; using StarLevelSystem.modules; using StarLevelSystem.modules.AnimationAndSpeed; using StarLevelSystem.modules.CreatureSetup; using StarLevelSystem.modules.Damage; using StarLevelSystem.modules.Health; using StarLevelSystem.modules.LevelSystem; using StarLevelSystem.modules.LocationReset; using StarLevelSystem.modules.Loot; using StarLevelSystem.modules.Modifiers; using StarLevelSystem.modules.NemesisSystem; using StarLevelSystem.modules.Raids; using StarLevelSystem.modules.Sizes; using StarLevelSystem.modules.UI; using TMPro; using Unity.Collections; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("StarLevelSystem")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("StarLevelSystem")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.31.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.31.1.0")] [CompilerGenerated] internal delegate void <>f__AnonymousDelegate0<T1, T2, T3>(T1 arg1 = default(T1), T2 arg2 = default(T2), T3 arg3 = default(T3)); [CompilerGenerated] internal delegate void <>f__AnonymousDelegate1<T1>(T1 arg = default(T1)); namespace StarLevelSystem { [PublicAPI] public static class API { private static readonly Type APIReciever; private static readonly MethodInfo UpdateCreatureLevel; private static readonly MethodInfo UpdateCreatureColorization; private static readonly MethodInfo GetBaseAttributeValue; private static readonly MethodInfo UpdateCreatureBaseAttributes; private static readonly MethodInfo GetAllBaseAttributeValues; private static readonly MethodInfo SetAllBaseAttributeValues; private static readonly MethodInfo GetPerLevelAttributeValue; private static readonly MethodInfo UpdateCreaturePerLevelAttributes; private static readonly MethodInfo GetAllPerLevelAttributeValues; private static readonly MethodInfo SetAllPerLevelAttributeValues; private static readonly MethodInfo GetCreatureDamageRecievedModifier; private static readonly MethodInfo UpdateCreatureDamageRecievedModifier; private static readonly MethodInfo GetAllDamageRecievedModifiers; private static readonly MethodInfo SetAllDamageRecievedModifiers; private static readonly MethodInfo GetCreatureDamageBonus; private static readonly MethodInfo UpdateCreatureDamageBonus; private static readonly MethodInfo GetAllDamageBonus; private static readonly MethodInfo SetAllDamageBonus; private static readonly MethodInfo ApplyUpdatesToCreature; private static readonly MethodInfo SetCreatureSpawnManagedMethod; private static readonly MethodInfo GetPossibleModifiersForType; private static readonly MethodInfo GetAllModifiersForCreature; private static readonly MethodInfo AddModifierToCreature; private static readonly MethodInfo RemoveModifierFromCreatureMethod; private static readonly MethodInfo SetCreatureModifierConfigMethod; private static readonly MethodInfo ClearCreatureModifierConfigMethod; private static readonly MethodInfo GetCreatureModifierConfigMethod; private static readonly MethodInfo AddNewModifierToSLS; private static readonly MethodInfo SetEnemyHudChangesDisabledMethod; private static readonly MethodInfo GetDisabledEnemyHudChangesMethod; private static readonly MethodInfo GetCreatureHudInfoMethod; private static readonly MethodInfo GetCreatureEvolveProgressMethod; private static readonly MethodInfo RegisterLocationResetTargetMethod; private static readonly MethodInfo UnregisterLocationResetTargetMethod; private static readonly MethodInfo GetRegisteredLocationResetTargetsMethod; private static readonly MethodInfo GetLocationResetTargetInfoMethod; private static readonly MethodInfo IsLocationResetReadyMethod; private static readonly MethodInfo GetLocationResetStatusMethod; private static readonly MethodInfo IsKnownResetTargetNameMethod; private static readonly MethodInfo GetLocationLastResetMethod; private static readonly MethodInfo GetSecondsUntilLocationResetMethod; private static readonly MethodInfo GetLocationResetInfoMethod; private static readonly MethodInfo GetChunkResetInfoMethod; private static readonly MethodInfo ResetNamedLocationMethod; private static readonly MethodInfo ResetLocationsInRadiusMethod; public const int EnemyHudBarLayout = 1; public const int EnemyHudStars = 2; public const int EnemyHudEvolveBar = 4; public const int EnemyHudHealthNumbers = 8; public const int EnemyHudAll = 15; public static bool IsAvailable => APIReciever != null; public static bool SupportsLocationReset => ResetNamedLocationMethod != null; public static bool SupportsSpawnManaged => SetCreatureSpawnManagedMethod != null; public static bool SupportsModifierConfig => SetCreatureModifierConfigMethod != null; public static bool SupportsEnemyHud => SetEnemyHudChangesDisabledMethod != null; static API() { APIReciever = Type.GetType("StarLevelSystem.modules.APIReciever, StarLevelSystem"); if (!(APIReciever == null)) { UpdateCreatureLevel = APIReciever.GetMethod("UpdateCreatureLevel", BindingFlags.Static | BindingFlags.Public); UpdateCreatureColorization = APIReciever.GetMethod("UpdateCreatureColorization", BindingFlags.Static | BindingFlags.Public); GetBaseAttributeValue = APIReciever.GetMethod("GetBaseAttributeValue", BindingFlags.Static | BindingFlags.Public); UpdateCreatureBaseAttributes = APIReciever.GetMethod("UpdateCreatureBaseAttributes", BindingFlags.Static | BindingFlags.Public); GetAllBaseAttributeValues = APIReciever.GetMethod("GetAllBaseAttributes", BindingFlags.Static | BindingFlags.Public); SetAllBaseAttributeValues = APIReciever.GetMethod("SetAllBaseAttributes", BindingFlags.Static | BindingFlags.Public); GetPerLevelAttributeValue = APIReciever.GetMethod("GetPerLevelAttributeValue", BindingFlags.Static | BindingFlags.Public); UpdateCreaturePerLevelAttributes = APIReciever.GetMethod("UpdateCreaturePerLevelAttributes", BindingFlags.Static | BindingFlags.Public); GetAllPerLevelAttributeValues = APIReciever.GetMethod("GetAllPerLevelAttributes", BindingFlags.Static | BindingFlags.Public); SetAllPerLevelAttributeValues = APIReciever.GetMethod("SetAllPerLevelAttributes", BindingFlags.Static | BindingFlags.Public); GetCreatureDamageRecievedModifier = APIReciever.GetMethod("GetCreatureDamageRecievedModifier", BindingFlags.Static | BindingFlags.Public); UpdateCreatureDamageRecievedModifier = APIReciever.GetMethod("UpdateCreatureDamageRecievedModifier", BindingFlags.Static | BindingFlags.Public); GetAllDamageRecievedModifiers = APIReciever.GetMethod("GetAllDamageRecievedModifiers", BindingFlags.Static | BindingFlags.Public); SetAllDamageRecievedModifiers = APIReciever.GetMethod("SetAllDamageRecievedModifiers", BindingFlags.Static | BindingFlags.Public); GetCreatureDamageBonus = APIReciever.GetMethod("GetCreatureDamageBonus", BindingFlags.Static | BindingFlags.Public); UpdateCreatureDamageBonus = APIReciever.GetMethod("UpdateCreatureDamageBonus", BindingFlags.Static | BindingFlags.Public); GetAllDamageBonus = APIReciever.GetMethod("GetAllDamageBonus", BindingFlags.Static | BindingFlags.Public); SetAllDamageBonus = APIReciever.GetMethod("SetAllDamageBonus", BindingFlags.Static | BindingFlags.Public); ApplyUpdatesToCreature = APIReciever.GetMethod("ApplyUpdatesToCreature", BindingFlags.Static | BindingFlags.Public); SetCreatureSpawnManagedMethod = APIReciever.GetMethod("SetCreatureSpawnManaged", BindingFlags.Static | BindingFlags.Public); GetPossibleModifiersForType = APIReciever.GetMethod("GetPossibleModifiersForType", BindingFlags.Static | BindingFlags.Public); GetAllModifiersForCreature = APIReciever.GetMethod("GetAllModifiersForCreature", BindingFlags.Static | BindingFlags.Public); AddModifierToCreature = APIReciever.GetMethod("AddModifierToCreature", BindingFlags.Static | BindingFlags.Public); RemoveModifierFromCreatureMethod = APIReciever.GetMethod("RemoveModifierFromCreature", BindingFlags.Static | BindingFlags.Public); SetCreatureModifierConfigMethod = APIReciever.GetMethod("SetCreatureModifierConfig", BindingFlags.Static | BindingFlags.Public); ClearCreatureModifierConfigMethod = APIReciever.GetMethod("ClearCreatureModifierConfig", BindingFlags.Static | BindingFlags.Public); GetCreatureModifierConfigMethod = APIReciever.GetMethod("GetCreatureModifierConfig", BindingFlags.Static | BindingFlags.Public); AddNewModifierToSLS = APIReciever.GetMethod("AddNewModifierToSLS", BindingFlags.Static | BindingFlags.Public); SetEnemyHudChangesDisabledMethod = APIReciever.GetMethod("SetEnemyHudChangesDisabled", BindingFlags.Static | BindingFlags.Public); GetDisabledEnemyHudChangesMethod = APIReciever.GetMethod("GetDisabledEnemyHudChanges", BindingFlags.Static | BindingFlags.Public); GetCreatureHudInfoMethod = APIReciever.GetMethod("GetCreatureHudInfo", BindingFlags.Static | BindingFlags.Public); GetCreatureEvolveProgressMethod = APIReciever.GetMethod("GetCreatureEvolveProgress", BindingFlags.Static | BindingFlags.Public); RegisterLocationResetTargetMethod = APIReciever.GetMethod("RegisterLocationResetTarget", BindingFlags.Static | BindingFlags.Public); UnregisterLocationResetTargetMethod = APIReciever.GetMethod("UnregisterLocationResetTarget", BindingFlags.Static | BindingFlags.Public); GetRegisteredLocationResetTargetsMethod = APIReciever.GetMethod("GetRegisteredLocationResetTargets", BindingFlags.Static | BindingFlags.Public); GetLocationResetTargetInfoMethod = APIReciever.GetMethod("GetLocationResetTargetInfo", BindingFlags.Static | BindingFlags.Public); IsLocationResetReadyMethod = APIReciever.GetMethod("IsLocationResetReady", BindingFlags.Static | BindingFlags.Public); GetLocationResetStatusMethod = APIReciever.GetMethod("GetLocationResetStatus", BindingFlags.Static | BindingFlags.Public); IsKnownResetTargetNameMethod = APIReciever.GetMethod("IsKnownResetTargetName", BindingFlags.Static | BindingFlags.Public); GetLocationLastResetMethod = APIReciever.GetMethod("GetLocationLastReset", BindingFlags.Static | BindingFlags.Public); GetSecondsUntilLocationResetMethod = APIReciever.GetMethod("GetSecondsUntilLocationReset", BindingFlags.Static | BindingFlags.Public); GetLocationResetInfoMethod = APIReciever.GetMethod("GetLocationResetInfo", BindingFlags.Static | BindingFlags.Public); GetChunkResetInfoMethod = APIReciever.GetMethod("GetChunkResetInfo", BindingFlags.Static | BindingFlags.Public); ResetNamedLocationMethod = APIReciever.GetMethod("ResetNamedLocation", BindingFlags.Static | BindingFlags.Public); ResetLocationsInRadiusMethod = APIReciever.GetMethod("ResetLocationsInRadius", BindingFlags.Static | BindingFlags.Public); } } private static object Call(MethodInfo method, object fallback, params object[] args) { if (method == null) { return fallback; } return method.Invoke(null, args); } public static bool SetCreatureLevel(Character creatureId, int newLevel) { return (bool)UpdateCreatureLevel.Invoke(null, new object[2] { creatureId, newLevel }); } public static bool SetCreatureColorization(Character creatureId, float value, float hue, float sat, bool emission = false) { return (bool)UpdateCreatureColorization.Invoke(null, new object[5] { creatureId, value, hue, sat, emission }); } public static float GetCreatureBaseAttribute(Character creatureId, int attribute) { return (float)GetBaseAttributeValue.Invoke(null, new object[2] { creatureId, attribute }); } public static bool SetCreatureBaseAttribute(Character creatureId, int attribute, float value) { return (bool)UpdateCreatureBaseAttributes.Invoke(null, new object[3] { creatureId, attribute, value }); } public static Dictionary<int, float> GetAllCreatureBaseAttributes(Character creatureId) { return (Dictionary<int, float>)GetAllBaseAttributeValues.Invoke(null, new object[1] { creatureId }); } public static bool SetAllCreatureBaseAttributes(Character creatureId, Dictionary<int, float> attributes) { return (bool)SetAllBaseAttributeValues.Invoke(null, new object[2] { creatureId, attributes }); } public static float GetCreaturePerLevelAttribute(Character creatureId, int attribute) { return (float)GetPerLevelAttributeValue.Invoke(null, new object[2] { creatureId, attribute }); } public static bool SetCreaturePerLevelAttribute(Character creatureId, int attribute, float value) { return (bool)UpdateCreaturePerLevelAttributes.Invoke(null, new object[3] { creatureId, attribute, value }); } public static Dictionary<int, float> GetAllCreaturePerLevelAttributes(Character creatureId) { return (Dictionary<int, float>)GetAllPerLevelAttributeValues.Invoke(null, new object[1] { creatureId }); } public static bool SetAllCreaturePerLevelAttributes(Character creatureId, Dictionary<int, float> attributes) { return (bool)SetAllPerLevelAttributeValues.Invoke(null, new object[2] { creatureId, attributes }); } public static float GetCreatureDamageReceivedModifier(Character creatureId, int damageType) { return (float)GetCreatureDamageRecievedModifier.Invoke(null, new object[2] { creatureId, damageType }); } public static bool SetCreatureDamageReceivedModifier(Character creatureId, int damageType, float value) { return (bool)UpdateCreatureDamageRecievedModifier.Invoke(null, new object[3] { creatureId, damageType, value }); } public static Dictionary<int, float> GetAllCreatureDamageReceivedModifiers(Character creatureId) { return (Dictionary<int, float>)GetAllDamageRecievedModifiers.Invoke(null, new object[1] { creatureId }); } public static bool SetAllCreatureDamageReceivedModifiers(Character creatureId, Dictionary<int, float> attributes) { return (bool)SetAllDamageRecievedModifiers.Invoke(null, new object[2] { creatureId, attributes }); } public static float GetCreatureFlatDamageBonus(Character creatureId, int damageType) { return (float)GetCreatureDamageBonus.Invoke(null, new object[2] { creatureId, damageType }); } public static bool SetCreatureFlatDamageBonus(Character creatureId, int damageType, float value) { return (bool)UpdateCreatureDamageBonus.Invoke(null, new object[3] { creatureId, damageType, value }); } public static Dictionary<int, float> GetAllCreatureFlatDamageBonuses(Character creatureId) { return (Dictionary<int, float>)GetAllDamageBonus.Invoke(null, new object[1] { creatureId }); } public static bool SetAllCreatureFlatDamageBonuses(Character creatureId, Dictionary<int, float> attributes) { return (bool)SetAllDamageBonus.Invoke(null, new object[2] { creatureId, attributes }); } public static bool ApplyCreatureUpdates(Character creatureId) { return (bool)ApplyUpdatesToCreature.Invoke(null, new object[1] { creatureId }); } public static bool SetCreatureSpawnManaged(Character creatureId, bool managed = true) { return (bool)Call(SetCreatureSpawnManagedMethod, false, creatureId, managed); } public static List<string> GetPossibleModifiers(int modType = 0) { return (List<string>)GetPossibleModifiersForType.Invoke(null, new object[1] { modType }); } public static Dictionary<string, int> GetCreaturesModifiers(Character creatureId) { return (Dictionary<string, int>)GetAllModifiersForCreature.Invoke(null, new object[1] { creatureId }); } public static bool AddModifierToTargetCreature(Character creatureId, string modifierName, int modifierType, bool update = true) { return (bool)AddModifierToCreature.Invoke(null, new object[4] { creatureId, modifierName, modifierType, update }); } public static bool RemoveModifierFromTargetCreature(Character creatureId, string modifierName) { return (bool)Call(RemoveModifierFromCreatureMethod, false, creatureId, modifierName); } public static bool SetCreatureModifierConfig(Character creatureId, string modifierName, Dictionary<string, float> values) { return (bool)Call(SetCreatureModifierConfigMethod, false, creatureId, modifierName, values); } public static bool ClearCreatureModifierConfig(Character creatureId, string modifierName, string key = null) { return (bool)Call(ClearCreatureModifierConfigMethod, false, creatureId, modifierName, key); } public static Dictionary<string, float> GetCreatureModifierConfig(Character creatureId, string modifierName, int modifierType = -1) { return (Dictionary<string, float>)Call(GetCreatureModifierConfigMethod, null, creatureId, modifierName, modifierType); } public static bool SetEnemyHudChangesDisabled(string sourceId, int changes) { return (bool)Call(SetEnemyHudChangesDisabledMethod, false, sourceId, changes); } public static int GetDisabledEnemyHudChanges() { return (int)Call(GetDisabledEnemyHudChangesMethod, 0); } public static Dictionary<string, object> GetCreatureHudInfo(Character creatureId) { return (Dictionary<string, object>)Call(GetCreatureHudInfoMethod, null, creatureId); } public static float GetCreatureEvolveProgress(Character creatureId) { return (float)Call(GetCreatureEvolveProgressMethod, -1f, creatureId); } public static bool AddNewModifier(int modifierID, string modifier_name, Delegate setupMethod = null, float selectionWeight = 10f, float basepower = 0f, float perlevelpower = 0f, Dictionary<Biome, List<string>> biomeConfig = null, int namingStyle = 2, string name_suffixes = null, string name_prefixes = null, int visualStyle = 0, Sprite starIcon = null, GameObject visualEffect = null, List<string> allowed_creatures = null, List<string> unallowed_creatures = null, List<Biome> allowed_biomes = null) { return (bool)AddNewModifierToSLS.Invoke(null, new object[16] { modifierID, modifier_name, setupMethod, selectionWeight, basepower, perlevelpower, biomeConfig, namingStyle, name_suffixes, name_prefixes, visualStyle, starIcon, visualEffect, allowed_creatures, unallowed_creatures, allowed_biomes }); } public static bool RegisterLocationReset(string prefabName, string sourceId, float resetHours = 0f, string resetSchedule = null, bool enabled = true, int mode = 0, bool resetTerrain = false, float terrainRadius = 0f, float extraTerrainRadius = 0f, bool resetInterior = true, float minDistance = 0f, float maxDistance = 0f, Action<bool> onResult = null) { return (bool)Call(RegisterLocationResetTargetMethod, false, prefabName, sourceId, resetHours, resetSchedule, mode, resetTerrain, terrainRadius, extraTerrainRadius, resetInterior, minDistance, maxDistance, enabled, onResult); } public static bool UnregisterLocationReset(string prefabName, string sourceId, Action<bool> onResult = null) { return (bool)Call(UnregisterLocationResetTargetMethod, false, prefabName, sourceId, onResult); } public static bool GetRegisteredLocationResets(string sourceId, Action<List<string>> onResult) { return (bool)Call(GetRegisteredLocationResetTargetsMethod, false, sourceId, onResult); } public static bool GetLocationResetTargetInfo(string prefabName, Action<Dictionary<string, object>> onResult) { return (bool)Call(GetLocationResetTargetInfoMethod, false, prefabName, onResult); } public static bool IsLocationResetReady(Action<bool> onResult) { return (bool)Call(IsLocationResetReadyMethod, false, onResult); } public static bool GetLocationResetStatus(Action<Dictionary<string, object>> onResult) { return (bool)Call(GetLocationResetStatusMethod, false, onResult); } public static bool IsKnownLocationResetTarget(string prefabName, Action<bool> onResult) { return (bool)Call(IsKnownResetTargetNameMethod, false, prefabName, onResult); } public static bool GetLocationLastReset(string locationName, Vector3 center, float radius, Action<long> onResult) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(GetLocationLastResetMethod, false, locationName, center, radius, onResult); } public static bool GetSecondsUntilLocationReset(string locationName, Vector3 center, float radius, Action<double> onResult) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(GetSecondsUntilLocationResetMethod, false, locationName, center, radius, onResult); } public static bool GetLocationResetInfo(string locationName, Vector3 center, float radius, Action<Dictionary<string, object>> onResult) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(GetLocationResetInfoMethod, false, locationName, center, radius, onResult); } public static bool GetChunkResetInfo(Vector3 position, bool includePrefabs, Action<Dictionary<string, object>> onResult) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(GetChunkResetInfoMethod, false, position, includePrefabs, onResult); } public static bool ResetNamedLocation(string locationName, Vector3 center, float radius = 128f, int safety = 0, bool resetAllMatches = false, float safeWaitSeconds = 0f, bool includeDetail = false, Action<Dictionary<string, object>> onComplete = null) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(ResetNamedLocationMethod, false, locationName, center, radius, safety, resetAllMatches, safeWaitSeconds, includeDetail, onComplete); } public static bool ResetLocationsInRadius(Vector3 center, float radius = 128f, int safety = 0, float safeWaitSeconds = 0f, bool includeDetail = false, Action<Dictionary<string, object>> onComplete = null) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) return (bool)Call(ResetLocationsInRadiusMethod, false, center, radius, safety, safeWaitSeconds, includeDetail, onComplete); } } internal static class Logger { public static LogLevel Level = (LogLevel)16; public static bool IsDebugEnabled => (int)Level >= 32; public static void EnableDebugLogging(object sender, EventArgs e) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void CheckEnableDebugLogging() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void LogNemesis(string message) { if (ValConfig.EnableDebugNemesisDetails.Value) { StarLevelSystem.Log.LogInfo((object)("[Nemesis] " + message)); } } public static void LogRaid(string message) { if (ValConfig.EnableDebugRaidDetails.Value) { StarLevelSystem.Log.LogInfo((object)("[Raid] " + message)); } } public static void LogLoot(string message) { if (ValConfig.EnableDebugLootDetails.Value) { StarLevelSystem.Log.LogInfo((object)("[Loot] " + message)); } } public static void LogLocationReset(string message) { if (ValConfig.EnableDebugLocationResetDetails.Value) { StarLevelSystem.Log.LogInfo((object)("[LocationReset] " + message)); } } public static void LogLocationResetAlways(string message) { StarLevelSystem.Log.LogInfo((object)("[LocationReset] " + message)); } public static void LogLocationResetWarning(string message) { StarLevelSystem.Log.LogWarning((object)("[LocationReset] " + message)); } public static void LogLocationResetError(string message) { StarLevelSystem.Log.LogError((object)("[LocationReset] " + message)); } public static void LogDebug(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 32) { StarLevelSystem.Log.LogInfo((object)message); } } public static void LogInfo(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 16) { StarLevelSystem.Log.LogInfo((object)message); } } public static void LogWarning(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 4) { StarLevelSystem.Log.LogWarning((object)message); } } public static void LogError(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 2) { StarLevelSystem.Log.LogError((object)message); } } } [BepInPlugin("MidnightsFX.StarLevelSystem", "StarLevelSystem", "1.31.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("org.bepinex.plugins.creaturelevelcontrol")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class StarLevelSystem : BaseUnityPlugin { public const string PluginGUID = "MidnightsFX.StarLevelSystem"; public const string PluginName = "StarLevelSystem"; public const string PluginVersion = "1.31.1"; public ValConfig cfg; public static CustomLocalization Localization; public static AssetBundle EmbeddedResourceBundle; public static ManualLogSource Log; public static Harmony HarmonyInstance { get; private set; } public void Awake() { Localization = LocalizationManager.Instance.GetLocalization(); Log = ((BaseUnityPlugin)this).Logger; cfg = new ValConfig(((BaseUnityPlugin)this).Config); cfg.SetupConfigRPCs(); TaskRunner.Setup(); Compatibility.CheckModCompat(); EmbeddedResourceBundle = LoadEmbeddedBundle("StarLevelSystem.assets.starlevelsystems"); HarmonyInstance = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "MidnightsFX.StarLevelSystem"); Compatibility.ApplyConditionalPatches(HarmonyInstance); Colorization.UpdateMapColorSelection(); Colorization.UpdateZoneOverlayColorSelection(); YamlConfigManager.Init(); QuickConfigureTool.Init(); LocalizationLoader.AddLocalizations(); PrefabManager.OnVanillaPrefabsAvailable += CreatureModifiersData.LoadPrefabs; PrefabManager.OnVanillaPrefabsAvailable += UpdateLevelsOnChange.UpdateFishMaxLevel; PrefabManager.OnVanillaPrefabsAvailable += UpdateLevelsOnChange.UpdateFishScaleByQuality; PrefabManager.OnVanillaPrefabsAvailable += UIHudControl.SetDefaultStar; PrefabManager.OnVanillaPrefabsAvailable += NemesisRemoteSpawnControl.LoadAssets; PrefabManager.OnPrefabsRegistered += PrefabLookup.ResetWarnings; PrefabManager.OnPrefabsRegistered += SwimAnimationModifications.ApplyToPrefabs; PrefabManager.OnPrefabsRegistered += LootSystemData.AttachPrefabsWhenReady; MinimapManager.OnVanillaMapDataLoaded += DistanceScaleSystem.DelayedMinimapSetup; MinimapManager.OnVanillaMapDataLoaded += ZoneScaleSystem.Initialize; MinimapManager.OnVanillaMapDataLoaded += NemesisMinimap.OnMapReady; PrefabManager.OnPrefabsRegistered += SizeModifications.PrepareSizeRefCache; PrefabManager.OnPrefabsRegistered += NovaBurstFx.Register; PrefabManager.OnPrefabsRegistered += ModifierSounds.Apply; UIHudControl.LoadAssets(); ModifierStatusEffects.Register(); RaidControl.LoadAssets(); TerminalManager.Init(); NemesisSystem.Initialize(); } private static AssetBundle LoadEmbeddedBundle(string resourceName) { Stopwatch stopwatch = Stopwatch.StartNew(); Assembly assembly = typeof(StarLevelSystem).Assembly; string text = assembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith(resourceName)); if (text == null) { Log.LogError((object)("The asset bundle " + resourceName + " is not embedded in this build.")); return null; } byte[] array; using (Stream stream = assembly.GetManifestResourceStream(text)) { array = new byte[stream.Length]; int num2; for (int num = 0; num < array.Length; num += num2) { num2 = stream.Read(array, num, array.Length - num); if (num2 <= 0) { break; } } } AssetBundle result = AssetBundle.LoadFromMemory(array); Logger.LogDebug($"Opened the embedded asset bundle ({array.Length / 1024} KB) from memory in {stopwatch.Elapsed.TotalMilliseconds:0.0} ms."); return result; } } } namespace StarLevelSystem.modules { internal static class APIOwnerRelay { internal enum Op { SetLevel, SetSpawnManaged, UpdateBaseAttribute, SetAllBaseAttributes, UpdatePerLevelAttribute, SetAllPerLevelAttributes, UpdateDamageRecieved, SetAllDamageRecieved, UpdateDamageBonus, SetAllDamageBonus, ApplyUpdates, AddModifier, RemoveModifier, SetModifierConfig, ClearModifierConfig } [HarmonyPatch(typeof(Character), "Awake")] public static class RegisterApiRelayRPC { private static void Postfix(Character __instance) { if (!__instance.IsPlayer() && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.GetZDO() != null) { __instance.m_nview.Register<ZPackage>("SLS_ApiRelay", (Action<long, ZPackage>)delegate(long sender, ZPackage call) { Replay(__instance, call); }); } } } private const string RPC_ApiRelay = "SLS_ApiRelay"; private const int MaxHops = 3; internal static void ClaimIfUnowned(Character chara) { ZNetView val = (((Object)(object)chara != (Object)null) ? chara.m_nview : null); if (!((Object)(object)val == (Object)null) && val.IsValid() && !val.GetZDO().HasOwner()) { val.ClaimOwnership(); } } internal static void SendToOwner(Character chara, Op op, Action<ZPackage> writeArgs = null) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown ZNetView val = (((Object)(object)chara != (Object)null) ? chara.m_nview : null); if (!((Object)(object)val == (Object)null) && val.IsValid() && !val.IsOwner()) { ZPackage val2 = new ZPackage(); writeArgs?.Invoke(val2); Send(val, 0, op, val2); } } internal static void WriteAttributes(ZPackage package, Dictionary<int, float> attributes) { package.Write(attributes.Count); foreach (KeyValuePair<int, float> attribute in attributes) { package.Write(attribute.Key); package.Write(attribute.Value); } } internal static void WriteValues(ZPackage package, Dictionary<string, float> values) { package.Write(values.Count); foreach (KeyValuePair<string, float> value in values) { package.Write(value.Key); package.Write(value.Value); } } private static Dictionary<string, float> ReadValues(ZPackage package) { int num = package.ReadInt(); Dictionary<string, float> dictionary = new Dictionary<string, float>(num); for (int i = 0; i < num; i++) { string key = package.ReadString(); dictionary[key] = package.ReadSingle(); } return dictionary; } private static Dictionary<int, float> ReadAttributes(ZPackage package) { int num = package.ReadInt(); Dictionary<int, float> dictionary = new Dictionary<int, float>(num); for (int i = 0; i < num; i++) { int key = package.ReadInt(); dictionary[key] = package.ReadSingle(); } return dictionary; } private static void Send(ZNetView nview, int hops, Op op, ZPackage args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(hops); val.Write((int)op); val.Write(args); nview.InvokeRPC("SLS_ApiRelay", new object[1] { val }); } private static void Replay(Character chara, ZPackage call) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || !chara.m_nview.IsValid()) { return; } int num = call.ReadInt(); Op op = (Op)call.ReadInt(); ZPackage val = call.ReadPackage(); ZNetView nview = chara.m_nview; if (!nview.IsOwner() && nview.GetZDO().HasOwner()) { if (num < 3) { Send(nview, num + 1, op, val); } else { Logger.LogWarning($"SLS-API: dropping a replayed {op} for {((Object)chara).name}: its owner kept changing while the call was in flight."); } return; } switch (op) { case Op.SetLevel: { int num3 = val.ReadInt(); if (num3 < 1) { Logger.LogWarning($"SLS-API: dropping a replayed {op} for {((Object)chara).name}: {num3} is not a creature level."); } else { APIReciever.UpdateCreatureLevel(chara, num3); } break; } case Op.SetSpawnManaged: APIReciever.SetCreatureSpawnManaged(chara, val.ReadBool()); break; case Op.UpdateBaseAttribute: { int attribute = val.ReadInt(); APIReciever.UpdateCreatureBaseAttributes(chara, attribute, val.ReadSingle()); break; } case Op.SetAllBaseAttributes: APIReciever.SetAllBaseAttributes(chara, ReadAttributes(val)); break; case Op.UpdatePerLevelAttribute: { int attribute2 = val.ReadInt(); APIReciever.UpdateCreaturePerLevelAttributes(chara, attribute2, val.ReadSingle()); break; } case Op.SetAllPerLevelAttributes: APIReciever.SetAllPerLevelAttributes(chara, ReadAttributes(val)); break; case Op.UpdateDamageRecieved: { int attribute4 = val.ReadInt(); APIReciever.UpdateCreatureDamageRecievedModifier(chara, attribute4, val.ReadSingle()); break; } case Op.SetAllDamageRecieved: APIReciever.SetAllDamageRecievedModifiers(chara, ReadAttributes(val)); break; case Op.UpdateDamageBonus: { int attribute3 = val.ReadInt(); APIReciever.UpdateCreatureDamageBonus(chara, attribute3, val.ReadSingle()); break; } case Op.SetAllDamageBonus: APIReciever.SetAllDamageBonus(chara, ReadAttributes(val)); break; case Op.ApplyUpdates: APIReciever.ApplyUpdatesToCreature(chara); break; case Op.AddModifier: { string modifierName3 = val.ReadString(); int num2 = val.ReadInt(); bool update = val.ReadBool(); if (!Enum.IsDefined(typeof(DataObjects.ModifierType), num2)) { Logger.LogWarning($"SLS-API: dropping a replayed {op} for {((Object)chara).name}: {num2} is not a modifier type."); } else { APIReciever.AddModifierToCreature(chara, modifierName3, num2, update); } break; } case Op.RemoveModifier: APIReciever.RemoveModifierFromCreature(chara, val.ReadString()); break; case Op.SetModifierConfig: { string modifierName2 = val.ReadString(); APIReciever.SetCreatureModifierConfig(chara, modifierName2, ReadValues(val)); break; } case Op.ClearModifierConfig: { string modifierName = val.ReadString(); bool flag = val.ReadBool(); string text = val.ReadString(); APIReciever.ClearCreatureModifierConfig(chara, modifierName, flag ? text : null); break; } default: Logger.LogWarning($"SLS-API: unknown replayed call {(int)op} for {((Object)chara).name}."); break; } } } public static class APIReciever { public static bool UpdateCreatureLevel(Character chara, int level) { if ((Object)(object)chara == (Object)null) { return false; } Logger.LogDebug($"SLS-API: Update Creature level {chara} - {level}"); APIOwnerRelay.ClaimIfUnowned(chara); LevelSelection.SetAndUpdateCharacterLevel(chara, level); APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetLevel, delegate(ZPackage args) { args.Write(level); }); return true; } public static bool UpdateCreatureColorization(Character chara, float value, float hue, float sat, bool emission = false) { if ((Object)(object)chara == (Object)null) { return false; } DataObjects.CharacterCacheEntry cacheEntry = CompositeLazyCache.GetCacheEntry(chara); if (cacheEntry == null) { return false; } cacheEntry.Colorization = new DataObjects.ColorDef(hue, sat, value, emission); CompositeLazyCache.UpdateCharacterCacheEntry(chara, cacheEntry); Colorization.ApplyColorizationWithoutLevelEffects(((Component)chara).gameObject, cacheEntry.Colorization); return true; } public static bool SetCreatureSpawnManaged(Character chara, bool managed) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (CompositeLazyCache.IsZOwner(chara)) { ZDO zDO = chara.m_nview.GetZDO(); zDO.Set(DataObjects.SLS_SPAWN_MANAGED, managed); if (managed) { zDO.Set(DataObjects.SLS_SPAWN_MULT, true); } } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetSpawnManaged, delegate(ZPackage args) { args.Write(managed); }); return true; } public static float GetBaseAttributeValue(Character chara, int attribute) { if ((Object)(object)chara == (Object)null) { return -1f; } return CompositeLazyCache.GetAndSetLocalCache(chara)?.CreatureBaseValueModifiers[(DataObjects.CreatureBaseAttribute)attribute] ?? (-1f); } public static bool UpdateCreatureBaseAttributes(Character chara, int attribute, float value) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.Base, StatValues(attribute, value))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.UpdateBaseAttribute, delegate(ZPackage args) { args.Write(attribute); args.Write(value); }); return true; } public static Dictionary<int, float> GetAllBaseAttributes(Character chara) { if ((Object)(object)chara == (Object)null) { return null; } DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return null; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); foreach (KeyValuePair<DataObjects.CreatureBaseAttribute, float> creatureBaseValueModifier in andSetLocalCache.CreatureBaseValueModifiers) { dictionary[(int)creatureBaseValueModifier.Key] = creatureBaseValueModifier.Value; } return dictionary; } public static bool SetAllBaseAttributes(Character chara, Dictionary<int, float> attributes) { if ((Object)(object)chara == (Object)null || attributes == null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.Base, StatValues(attributes))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetAllBaseAttributes, delegate(ZPackage args) { APIOwnerRelay.WriteAttributes(args, attributes); }); return true; } public static float GetPerLevelAttributeValue(Character chara, int attribute) { if ((Object)(object)chara == (Object)null) { return -1f; } return CompositeLazyCache.GetAndSetLocalCache(chara)?.CreaturePerLevelValueModifiers[(DataObjects.CreaturePerLevelAttribute)attribute] ?? (-1f); } public static bool UpdateCreaturePerLevelAttributes(Character chara, int attribute, float value) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.PerLevel, StatValues(attribute, value))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.UpdatePerLevelAttribute, delegate(ZPackage args) { args.Write(attribute); args.Write(value); }); return true; } public static Dictionary<int, float> GetAllPerLevelAttributes(Character chara) { if ((Object)(object)chara == (Object)null) { return null; } DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return null; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); foreach (KeyValuePair<DataObjects.CreaturePerLevelAttribute, float> creaturePerLevelValueModifier in andSetLocalCache.CreaturePerLevelValueModifiers) { dictionary[(int)creaturePerLevelValueModifier.Key] = creaturePerLevelValueModifier.Value; } return dictionary; } public static bool SetAllPerLevelAttributes(Character chara, Dictionary<int, float> attributes) { if ((Object)(object)chara == (Object)null || attributes == null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.PerLevel, StatValues(attributes))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetAllPerLevelAttributes, delegate(ZPackage args) { APIOwnerRelay.WriteAttributes(args, attributes); }); return true; } public static float GetCreatureDamageRecievedModifier(Character chara, int attribute) { if ((Object)(object)chara == (Object)null) { return -1f; } return CompositeLazyCache.GetAndSetLocalCache(chara)?.DamageRecievedModifiers[(DataObjects.DamageType)attribute] ?? (-1f); } public static bool UpdateCreatureDamageRecievedModifier(Character chara, int attribute, float value) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.DamageTaken, StatValues(attribute, value))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.UpdateDamageRecieved, delegate(ZPackage args) { args.Write(attribute); args.Write(value); }); return true; } public static Dictionary<int, float> GetAllDamageRecievedModifiers(Character chara) { if ((Object)(object)chara == (Object)null) { return null; } DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return null; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); foreach (KeyValuePair<DataObjects.DamageType, float> damageRecievedModifier in andSetLocalCache.DamageRecievedModifiers) { dictionary[(int)damageRecievedModifier.Key] = damageRecievedModifier.Value; } return dictionary; } public static bool SetAllDamageRecievedModifiers(Character chara, Dictionary<int, float> attributes) { if ((Object)(object)chara == (Object)null || attributes == null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.DamageTaken, StatValues(attributes))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetAllDamageRecieved, delegate(ZPackage args) { APIOwnerRelay.WriteAttributes(args, attributes); }); return true; } public static float GetCreatureDamageBonus(Character chara, int attribute) { if ((Object)(object)chara == (Object)null) { return -1f; } DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return -1f; } if (andSetLocalCache.CreatureDamageBonus.ContainsKey((DataObjects.DamageType)attribute)) { return andSetLocalCache.CreatureDamageBonus[(DataObjects.DamageType)attribute]; } return 0f; } public static bool UpdateCreatureDamageBonus(Character chara, int attribute, float value) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.DamageBonus, StatValues(attribute, value))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.UpdateDamageBonus, delegate(ZPackage args) { args.Write(attribute); args.Write(value); }); return true; } public static Dictionary<int, float> GetAllDamageBonus(Character chara) { if ((Object)(object)chara == (Object)null) { return null; } DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return null; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); foreach (KeyValuePair<DataObjects.DamageType, float> creatureDamageBonu in andSetLocalCache.CreatureDamageBonus) { dictionary[(int)creatureDamageBonu.Key] = creatureDamageBonu.Value; } return dictionary; } public static bool SetAllDamageBonus(Character chara, Dictionary<int, float> attributes) { if ((Object)(object)chara == (Object)null || attributes == null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CreatureStatOverrides.Apply(chara, StatGroup.DamageBonus, StatValues(attributes))) { return false; } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetAllDamageBonus, delegate(ZPackage args) { APIOwnerRelay.WriteAttributes(args, attributes); }); return true; } private static Dictionary<int, float?> StatValues(int attribute, float value) { return new Dictionary<int, float?> { { attribute, value } }; } private static Dictionary<int, float?> StatValues(Dictionary<int, float> attributes) { Dictionary<int, float?> dictionary = new Dictionary<int, float?>(attributes.Count); foreach (KeyValuePair<int, float> attribute in attributes) { dictionary[attribute.Key] = attribute.Value; } return dictionary; } public static bool ApplyUpdatesToCreature(Character chara) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); DataObjects.CharacterCacheEntry andSetLocalCache = CompositeLazyCache.GetAndSetLocalCache(chara); if (andSetLocalCache == null) { return false; } SpeedModifications.ApplySpeedModifications(chara, andSetLocalCache); DamageModifications.ApplyDamageModification(chara, andSetLocalCache); SizeModifications.SetSizeModification(((Component)chara).gameObject, chara.m_nview, andSetLocalCache, update: true); HealthModifications.ForceApplyHealthModifications(chara, andSetLocalCache); APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.ApplyUpdates); return true; } public static List<string> GetPossibleModifiersForType(int modifierType) { List<string> list = new List<string>(); switch (modifierType) { case 0: foreach (string key in CreatureModifiersData.ActiveCreatureModifiers.MajorModifiers.Keys) { list.Add(key); } break; case 1: foreach (string key2 in CreatureModifiersData.ActiveCreatureModifiers.MinorModifiers.Keys) { list.Add(key2); } break; case 2: foreach (string key3 in CreatureModifiersData.ActiveCreatureModifiers.BossModifiers.Keys) { list.Add(key3); } break; default: Logger.LogWarning($"Invalid modifier type {modifierType} passed to GetAllPossibleModifiers. Valid types are 0 (Major), 1 (Minor), 2 (Boss)."); break; } return list; } public static Dictionary<string, int> GetAllModifiersForCreature(Character chara) { Dictionary<string, DataObjects.ModifierType> creatureModifiers = CompositeLazyCache.GetCreatureModifiers(chara); if (creatureModifiers == null) { return null; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (KeyValuePair<string, DataObjects.ModifierType> item in creatureModifiers) { dictionary.Add(item.Key.ToString(), (int)item.Value); } return dictionary; } public static bool AddModifierToCreature(Character chara, string modifierName, int modifierType, bool update = true) { if ((Object)(object)chara == (Object)null) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (CompositeLazyCache.GetAndSetLocalCache(chara) == null) { return false; } bool num = CreatureModifiers.AddCreatureModifier(chara, (DataObjects.ModifierType)modifierType, modifierName, update); if (num && CompositeLazyCache.IsZOwner(chara)) { ModifierPeerRefresh.SendChanged(chara); } APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.AddModifier, delegate(ZPackage args) { args.Write(modifierName); args.Write(modifierType); args.Write(update); }); return num; } public static bool RemoveModifierFromCreature(Character chara, string modifierName) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null || string.IsNullOrEmpty(modifierName)) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CompositeLazyCache.IsZOwner(chara)) { APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.RemoveModifier, delegate(ZPackage args) { args.Write(modifierName); }); return true; } bool num = CreatureModifiers.RemoveCreatureModifier(chara, modifierName); if (num) { ModifierPeerRefresh.SendChanged(chara); } return num; } public static bool SetCreatureModifierConfig(Character chara, string modifierName, Dictionary<string, float> values) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null || values == null || values.Count == 0) { return false; } if (string.IsNullOrEmpty(modifierName) || modifierName == CreatureModifiers.NoMods || !CreatureModifiersData.ModifierNamesLookupTable.ContainsName(modifierName)) { Logger.LogWarning("SLS-API: " + modifierName + " is not a modifier; no values were set on " + ((Object)chara).name + "."); return false; } foreach (KeyValuePair<string, float> value in values) { if (string.IsNullOrEmpty(value.Key) || float.IsNaN(value.Value) || float.IsInfinity(value.Value)) { Logger.LogWarning($"SLS-API: {modifierName} value '{value.Key}' = {value.Value} is not usable; no values were set on {((Object)chara).name}."); return false; } } APIOwnerRelay.ClaimIfUnowned(chara); if (!CompositeLazyCache.IsZOwner(chara)) { APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.SetModifierConfig, delegate(ZPackage args) { args.Write(modifierName); APIOwnerRelay.WriteValues(args, values); }); return true; } if (CreatureModifierOverrides.Set(chara, modifierName, values)) { RefreshIfCarried(chara, modifierName); } return true; } public static bool ClearCreatureModifierConfig(Character chara, string modifierName, string key = null) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null || string.IsNullOrEmpty(modifierName)) { return false; } APIOwnerRelay.ClaimIfUnowned(chara); if (!CompositeLazyCache.IsZOwner(chara)) { APIOwnerRelay.SendToOwner(chara, APIOwnerRelay.Op.ClearModifierConfig, delegate(ZPackage args) { args.Write(modifierName); args.Write(key != null); args.Write(key ?? string.Empty); }); return true; } bool num = CreatureModifierOverrides.Clear(chara, modifierName, key); if (num) { RefreshIfCarried(chara, modifierName); } return num; } public static Dictionary<string, float> GetCreatureModifierConfig(Character chara, string modifierName, int modifierType = -1) { if ((Object)(object)chara == (Object)null || string.IsNullOrEmpty(modifierName)) { return null; } DataObjects.ModifierType type = DataObjects.ModifierType.Major; DataObjects.ModifierType type2; if (Enum.IsDefined(typeof(DataObjects.ModifierType), modifierType)) { type = (DataObjects.ModifierType)modifierType; } else if (CompositeLazyCache.TryGetCreatureModifier(chara, modifierName, out type2)) { type = type2; } return CreatureModifierOverrides.GetEffectiveValues(chara, modifierName, type); } private static void RefreshIfCarried(Character chara, string modifierName) { if (CompositeLazyCache.TryGetCreatureModifier(chara, modifierName, out var _)) { ModifierPeerRefresh.SendChanged(chara); } } public static bool SetEnemyHudChangesDisabled(string sourceId, int changes) { return EnemyHudChanges.Set(sourceId, changes); } public static int GetDisabledEnemyHudChanges() { EnemyHudChanges.Refresh(); return (int)EnemyHudChanges.Disabled; } public static Dictionary<string, object> GetCreatureHudInfo(Character chara) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null || chara.IsPlayer()) { return null; } try { return UIHudControl.GetHudInfo(chara); } catch (Exception ex) { Logger.LogDebug("SLS-API: no hud info for " + ((Object)chara).name + " yet: " + ex.Message); return null; } } public static float GetCreatureEvolveProgress(Character chara) { if ((Object)(object)chara == (Object)null || (Object)(object)chara.m_nview == (Object)null || chara.m_nview.GetZDO() == null) { return -1f; } try { return UIHudControl.GetEvolveProgress(chara); } catch (Exception ex) { Logger.LogDebug("SLS-API: no evolve progress for " + ((Object)chara).name + " yet: " + ex.Message); return -1f; } } public static bool AddNewModifierToSLS(int modifierID, string modifier_name, Delegate setupMethod = null, float selectionWeight = 10f, float basepower = 0f, float perlevelpower = 0f, Dictionary<Biome, List<string>> biomeConfig = null, int namingStyle = 2, string name_suffixes = null, string name_prefixes = null, int visualStyle = 0, Sprite starIcon = null, GameObject visualEffect = null, List<string> allowed_creatures = null, List<string> unallowed_creatures = null, List<Biome> allowed_biomes = null) { if (CreatureModifiersData.ModifierNamesLookupTable.ContainsID(modifierID)) { Logger.LogWarning($"Modifier ID {modifierID} already exists as {CreatureModifiersData.ModifierNamesLookupTable.GetValue(modifierID)}, please choose a different ID"); return false; } CreatureModifiersData.ModifierNamesLookupTable.AddValue(modifier_name, modifierID); DataObjects.CreatureModifierDefinition creatureModifierDefinition = new DataObjects.CreatureModifierDefinition(); if ((Object)(object)starIcon != (Object)null) { creatureModifierDefinition.StarVisualAPI = starIcon; creatureModifierDefinition.StarVisual = ((Object)starIcon).name; } if ((Object)(object)visualEffect != (Object)null) { creatureModifierDefinition.VisualEffectAPI = visualEffect; creatureModifierDefinition.VisualEffect = ((Object)visualEffect).name; } if ((object)setupMethod != null) { creatureModifierDefinition.SetupEvent = setupMethod; } if (name_suffixes != null) { creatureModifierDefinition.NameSuffix = name_suffixes; } if (name_prefixes != null) { creatureModifierDefinition.NamePrefix = name_prefixes; } if (namingStyle > 2 || namingStyle < 0) { namingStyle = 2; } creatureModifierDefinition.NamingConvention = (DataObjects.NameSelectionStyle)namingStyle; if (visualStyle > 3 || visualStyle < 0) { visualStyle = 0; } creatureModifierDefinition.VisualEffectStyle = (DataObjects.VisualEffectStyle)visualStyle; DataObjects.CreatureModifierConfiguration creatureModifierConfiguration = new DataObjects.CreatureModifierConfiguration(); creatureModifierConfiguration.Config = new DataObjects.CreatureModConfig { BasePower = basepower, PerlevelPower = perlevelpower, BiomeObjects = biomeConfig }; creatureModifierConfiguration.SelectionWeight = selectionWeight; if (allowed_creatures != null) { creatureModifierConfiguration.AllowedCreatures = allowed_creatures; } if (unallowed_creatures != null) { creatureModifierConfiguration.UnallowedCreatures = unallowed_creatures; } if (allowed_biomes != null) { creatureModifierConfiguration.AllowedBiomes = allowed_biomes; } CreatureModifiersData.RegisterAPIModifier(modifier_name, creatureModifierDefinition, creatureModifierConfiguration); return true; } public static bool RegisterLocationResetTarget(string prefabName, string sourceId, float resetHours, string resetSchedule, int mode, bool resetTerrain, float terrainRadius, float extraTerrainRadius, bool resetInterior, float minDistance, float maxDistance, bool enabled, Action<bool> onResult) { return RelayScalar(LocationResetNetwork.Op.Register, new Dictionary<string, object> { { "name", prefabName ?? "" }, { "sourceId", sourceId ?? "" }, { "resetHours", resetHours }, { "resetSchedule", resetSchedule ?? "" }, { "mode", mode }, { "resetTerrain", resetTerrain }, { "terrainRadius", terrainRadius }, { "extraTerrainRadius", extraTerrainRadius }, { "resetInterior", resetInterior }, { "minDistance", minDistance }, { "maxDistance", maxDistance }, { "enabled", enabled } }, () => LocalRegister(prefabName, sourceId, resetHours, resetSchedule, mode, resetTerrain, terrainRadius, extraTerrainRadius, resetInterior, minDistance, maxDistance, enabled), onResult, failure: false, 0f); } internal static bool LocalRegister(string prefabName, string sourceId, float resetHours, string resetSchedule, int mode, bool resetTerrain, float terrainRadius, float extraTerrainRadius, bool resetInterior, float minDistance, float maxDistance, bool enabled) { if (mode > 1 || mode < 0) { Logger.LogLocationResetWarning($"'{sourceId}' registered '{prefabName}' with mode {mode}; " + "valid values are 0 (Full) and 1 (TerrainOnly). Using Full."); mode = 0; } DataObjects.LocationResetEntry entry = new DataObjects.LocationResetEntry { Enabled = enabled, ResetHours = ((resetHours > 0f) ? new float?(resetHours) : ((float?)null)), ResetSchedule = (string.IsNullOrWhiteSpace(resetSchedule) ? null : resetSchedule.Trim()), Mode = (DataObjects.LocationResetMode)mode, ResetTerrain = resetTerrain, TerrainRadius = ((terrainRadius > 0f) ? new float?(terrainRadius) : ((float?)null)), ExtraTerrainRadius = ((extraTerrainRadius > 0f) ? new float?(extraTerrainRadius) : ((float?)null)), ResetInterior = resetInterior, Protection = null }; return LocationResetData.RegisterAPIResetTarget(prefabName, sourceId, entry, minDistance, maxDistance); } public static bool UnregisterLocationResetTarget(string prefabName, string sourceId, Action<bool> onResult) { return RelayScalar(LocationResetNetwork.Op.Unregister, new Dictionary<string, object> { { "name", prefabName ?? "" }, { "sourceId", sourceId ?? "" } }, () => LocationResetData.UnregisterAPIResetTarget(prefabName, sourceId), onResult, failure: false, 0f); } public static bool GetRegisteredLocationResetTargets(string sourceId, Action<List<string>> onResult) { return RelayScalar(LocationResetNetwork.Op.RegisteredNames, new Dictionary<string, object> { { "sourceId", sourceId ?? "" } }, () => LocationResetData.GetAPIRegisteredNames(sourceId), onResult, new List<string>(), 0f); } public static bool GetLocationResetTargetInfo(string prefabName, Action<Dictionary<string, object>> onResult) { return RelayDictionary(LocationResetNetwork.Op.TargetInfo, new Dictionary<string, object> { { "name", prefabName ?? "" } }, () => LocalTargetInfo(prefabName), onResult, 0f); } internal static Dictionary<string, object> LocalTargetInfo(string prefabName) { Dictionary<string, object> dictionary = new Dictionary<string, object> { { "name", prefabName ?? "" }, { "known", false }, { "configured", false }, { "enabled", false }, { "source", "none" } }; if (string.IsNullOrWhiteSpace(prefabName)) { return dictionary; } string text = prefabName.Trim(); int stableHashCode = StringExtensionMethods.GetStableHashCode(text); dictionary["name"] = text; dictionary["known"] = LocationResetData.IsKnownTargetName(stableHashCode); dictionary["source"] = LocationResetData.DescribeResolutionSource(text); dictionary["hardBlocked"] = LocationResetData.HardBlockedLocations.Contains(text); dictionary["registeredByAPI"] = LocationResetData.TryGetAPIRegistration(text, out var registration); dictionary["registeredBy"] = ((registration != null) ? registration.SourceId : ""); LocationResetData.ResolvedResetEntry entry; bool flag = LocationResetData.TryGetLocationEntry(stableHashCode, out entry); LocationResetData.ResolvedResetEntry entry2; bool flag2 = LocationResetData.TryGetVegetationEntry(stableHashCode, out entry2); if (entry == null) { entry = entry2; } dictionary["isLocation"] = flag; dictionary["isVegetation"] = flag2; dictionary["configured"] = entry != null; if (entry == null) { return dictionary; } dictionary["enabled"] = entry.Enabled; dictionary["groupName"] = entry.GroupName ?? ""; dictionary["resetSeconds"] = entry.ResetSeconds; dictionary["schedule"] = ((entry.Schedule != null) ? entry.Schedule.Expression : ""); dictionary["mode"] = (int)entry.Mode; dictionary["resetTerrain"] = entry.ResetTerrain; dictionary["terrainRadius"] = entry.TerrainRadius; dictionary["extraTerrainRadius"] = entry.ExtraTerrainRadius; dictionary["resetInterior"] = entry.ResetInterior; return dictionary; } public static bool IsLocationResetReady(Action<bool> onResult) { return RelayScalar(LocationResetNetwork.Op.Ready, null, LocalReady, onResult, failure: false, 0f); } internal static bool LocalReady() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } if (LocationResetData.BlockedByModConflict) { return false; } return LocationResetControl.Ready; } public static bool GetLocationResetStatus(Action<Dictionary<string, object>> onResult) { return RelayDictionary(LocationResetNetwork.Op.Status, null, LocalStatus, onResult, 0f); } internal static Dictionary<string, object> LocalStatus() { return new Dictionary<string, object> { { "available", true }, { "isServer", (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() }, { "ready", LocationResetControl.Ready }, { "sweepAllowed", LocationResetControl.SweepAllowed }, { "masterSwitchEnabled", ValConfig.EnableLocationReset.Value }, { "configEnabled", LocationResetData.ConfigEnabled }, { "blockedByModConflict", LocationResetData.BlockedByModConflict }, { "resetRunning", LocationResetControl.ManualResetRunning }, { "trackedZones", LocationResetState.TrackedZoneCount }, { "generatedZones", ((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_generatedZones.Count : 0 }, { "sweepFloorSeconds", LocationResetData.MinEnabledIntervalSeconds }, { "apiRegistrations", LocationResetData.APIAdded.Count }, { "clientMaxRadius", ValConfig.ClientLocationResetMaxRadius.Value }, { "clientMaxDistance", ValConfig.ClientLocationResetMaxDistance.Value }, { "clientCooldownSeconds", ValConfig.ClientLocationResetCooldownSeconds.Value } }; } public static bool IsKnownResetTargetName(string prefabName, Action<bool> onResult) { return RelayScalar(LocationResetNetwork.Op.IsKnownName, new Dictionary<string, object> { { "name", prefabName ?? "" } }, () => LocalIsKnownName(prefabName), onResult, failure: false, 0f); } internal static bool LocalIsKnownName(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } return LocationResetData.IsKnownTargetName(StringExtensionMethods.GetStableHashCode(prefabName.Trim())); } public static bool GetLocationLastReset(string locationName, Vector3 center, float radius, Action<long> onResult) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) return RelayScalar(LocationResetNetwork.Op.LastReset, LocationArgs(locationName, center, radius), () => LocationResetQuery.GetLocationLastReset(locationName, center, radius), onResult, -1L, 0f); } public static bool GetSecondsUntilLocationReset(string locationName, Vector3 center, float radius, Action<double> onResult) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) return RelayScalar(LocationResetNetwork.Op.SecondsUntilDue, LocationArgs(locationName, center, radius), () => LocationResetQuery.GetSecondsUntilDue(locationName, center, radius), onResult, -1.0, 0f); } public static bool GetLocationResetInfo(string locationName, Vector3 center, float radius, Action<Dictionary<string, object>> onResult) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) return RelayDictionary(LocationResetNetwork.Op.LocationInfo, LocationArgs(locationName, center, radius), () => LocationResetQuery.GetLocationInfo(locationName, center, radius), onResult, 0f); } public static bool GetChunkResetInfo(Vector3 position, bool includePrefabs, Action<Dictionary<string, object>> onResult) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> dictionary = PositionArgs(position); dictionary["includePrefabs"] = includePrefabs; return RelayDictionary(LocationResetNetwork.Op.ChunkInfo, dictionary, () => LocationResetQuery.GetChunkInfo(position, includePrefabs), onResult, 0f); } public static bool ResetNamedLocation(string locationName, Vector3 center, float radius, int safety, bool resetAllMatches, float safeWaitSeconds, bool includeDetail, Action<Dictionary<string, object>> onComplete) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(locationName)) { Logger.LogLocationResetWarning("SLS-API: ResetNamedLocation needs a location name."); Deliver(onComplete, ResetSummary.RefusalDictionary("no_name", "ResetNamedLocation needs a location name."), LocationResetNetwork.Op.ResetNamed); return false; } Dictionary<string, object> dictionary = ResetArgs(center, radius, safety, safeWaitSeconds, includeDetail); dictionary["name"] = locationName.Trim(); dictionary["resetAllMatches"] = resetAllMatches; return RelayReset(LocationResetNetwork.Op.ResetNamed, dictionary, safeWaitSeconds, onComplete, () => LocationResetControl.RequestReset(new LocationResetControl.ResetRequest { Center = center, Radius = radius, Safety = ClampSafety(safety), LocationName = locationName.Trim(), ResetAllMatches = resetAllMatches, SafeWaitSeconds = safeWaitSeconds, IncludeDetail = includeDetail, Source = "API reset '" + locationName.Trim() + "'" }, null, onComplete)); } public static bool ResetLocationsInRadius(Vector3 center, float radius, int safety, float safeWaitSeconds, bool includeDetail, Action<Dictionary<string, object>> onComplete) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) return RelayReset(LocationResetNetwork.Op.ResetRadius, ResetArgs(center, radius, safety, safeWaitSeconds, includeDetail), safeWaitSeconds, onComplete, () => LocationResetControl.RequestReset(new LocationResetControl.ResetRequest { Center = center, Radius = radius, Safety = ClampSafety(safety), SafeWaitSeconds = safeWaitSeconds, IncludeDetail = includeDetail, Source = $"API reset r={radius:0}" }, null, onComplete)); } private static int ClampSafety(int safety) { return (safety == 1) ? 1 : 0; } private static Dictionary<string, object> PositionArgs(Vector3 position) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) return new Dictionary<string, object> { { "x", position.x }, { "y", position.y }, { "z", position.z } }; } private static Dictionary<string, object> LocationArgs(string locationName, Vector3 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> dictionary = PositionArgs(center); dictionary["name"] = locationName ?? ""; dictionary["radius"] = radius; return dictionary; } private static Dictionary<string, object> ResetArgs(Vector3 center, float radius, int safety, float safeWaitSeconds, bool includeDetail) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> dictionary = PositionArgs(center); dictionary["radius"] = radius; dictionary["safety"] = safety; dictionary["safeWaitSeconds"] = safeWaitSeconds; dictionary["includeDetail"] = includeDetail; return dictionary; } private static bool RelayScalar<T>(LocationResetNetwork.Op op, Dictionary<string, object> args, Func<T> local, Action<T> onResult, T failure, float timeout) { if (LocationResetNetwork.IsServer) { T value = local(); Deliver(onResult, value, op); return true; } if (LocationResetNetwork.Send(op, args, timeout, delegate(Dictionary<string, object> result) { Deliver(onResult, Unwrap(result, failure, op), op); })) { return true; } Deliver(onResult, failure, op); return false; } private static bool RelayDictionary(LocationResetNetwork.Op op, Dictionary<string, object> args, Func<Dictionary<string, object>> local, Action<Dictionary<string, object>> onResult, float timeout) { if (LocationResetNetwork.IsServer) { Dictionary<string, object> value = local(); Deliver(onResult, value, op); return true; } if (LocationResetNetwork.Send(op, args, timeout, delegate(Dictionary<string, object> result) { LogIfRefused(result, op); Deliver(onResult, result, op); })) { return true; } Deliver(onResult, NoConnection(op), op); return false; } private static bool RelayReset(LocationResetNetwork.Op op, Dictionary<string, object> args, float safeWaitSeconds, Action<Dictionary<string, object>> onComplete, Func<bool> local) { if (LocationResetNetwork.IsServer) { return local(); } float timeoutSeconds = Mathf.Max(safeWaitSeconds, 300f) + 60f; if (LocationResetNetwork.Send(op, args, timeoutSeconds, delegate(Dictionary<string, object> result) { LogIfRefused(result, op); Deliver(onComplete, result, op); })) { return true; } Deliver(onComplete, NoConnection(op), op); return false; } private static Dictionary<string, object> NoConnection(LocationResetNetwork.Op op) { return ResetSummary.RefusalDictionary("no_connection", $"{op} could not be sent: this client has no server connection."); } private static T Unwrap<T>(Dictionary<string, object> result, T failure, LocationResetNetwork.Op op) { if (LogIfRefused(result, op)) { return failure; } if (result == null || !result.TryGetValue("value", out var value)) { return failure; } if (value == null) { return failure; } if (value is T) { return (T)value; } try { return (T)Convert.ChangeType(value, typeof(T)); } catch (Exception) { return failure; } } private static bool LogIfRefused(Dictionary<string, object> result, LocationResetNetwork.Op op) { if (result == null) { return false; } if (!result.TryGetValue("outcome", out var value)) { return false; } if (Convert.ToString(value) != "refused") { return false; } result.TryGetValue("reason", out var value2); result.TryGetValue("refusalCode", out var value3); Logger.LogLocationResetWarning($"SLS-API: {op} was refused [{value3}] - {value2}"); return true; } private static void Deliver<T>(Action<T> onResult, T value, LocationResetNetwork.Op op) { if (onResult == null) { return; } try { onResult(value); } catch (Exception arg) { Logger.LogLocationResetWarning($"A mod's {op} callback threw and was ignored: {arg}"); } } } internal static class BossNightSpawns { [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawnList")] public static class SkipTurnedOffNightSpawns { private static readonly List<SpawnData> switchedOff = new List<SpawnData>(); private static void Prefix(List<SpawnData> spawners, bool eventSpawners) { if (eventSpawners || spawners == null || !AnyTurnedOff()) { return; } foreach (SpawnData spawner in spawners) { if (spawner != null && spawner.m_enabled && IsBossNightSpawn(spawner, out var toggle) && !toggle.Value) { spawner.m_enabled = false; switchedOff.Add(spawner); } } } private static void Finalizer() { if (switchedOff.Count == 0) { return; } foreach (SpawnData item in switchedOff) { item.m_enabled = true; } switchedOff.Clear(); } } internal static readonly Dictionary<string, string> VanillaSpawns = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "defeated_eikthyr", "Greydwarfs in the Meadows" }, { "defeated_gdking", "Greydwarf brutes and shamans in the Meadows, and Draugr in fog across the Meadows, Black Forest, Mountain and Plains" }, { "defeated_bonemass", "Skeletons across the Meadows, Black Forest, Swamp, Mountain and Plains" }, { "defeated_dragon", "" }, { "defeated_goblinking", "Fulings across the Meadows, Black Forest and Mountain" }, { "defeated_queen", "Seekers, Seeker broods and Ticks across the Meadows, Black Forest, Mountain and Plains" }, { "defeated_fader", "" } }; private static Dictionary<string, ConfigEntry<bool>> toggles; private static Dictionary<string, ConfigEntry<bool>> Toggles { get { if (toggles == null) { toggles = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase) { { "defeated_eikthyr", ValConfig.EikthyrNightSpawns }, { "defeated_gdking", ValConfig.ElderNightSpawns }, { "defeated_bonemass", ValConfig.BonemassNightSpawns }, { "defeated_dragon", ValConfig.ModerNightSpawns }, { "defeated_goblinking", ValConfig.YagluthNightSpawns }, { "defeated_queen", ValConfig.QueenNightSpawns }, { "defeated_fader", ValConfig.FaderNightSpawns } }; } return toggles; } } internal static string SettingDescription(string bossKey, string bossName) { string value; string text = ((VanillaSpawns.TryGetValue(bossKey, out value) && value.Length > 0) ? ("In vanilla that is " + value + ".") : "None are known in vanilla, but other mods can add them."); return "Allows the creatures that only spawn at night once " + bossName + " is defeated. " + text + " Turn off to stop them; any already out still leave at dawn. Nothing else the boss unlocks is affected."; } internal static ConfigEntry<bool> ToggleFor(string bossKey) { if (string.IsNullOrEmpty(bossKey)) { return null; } if (!Toggles.TryGetValue(bossKey, out var value)) { return null; } return value; } private static bool AnyTurnedOff() { foreach (ConfigEntry<bool> value in Toggles.Values) { if (value != null && !value.Value) { return true; } } return false; } internal static bool IsBossNightSpawn(SpawnData spawn, out ConfigEntry<bool> toggle) { toggle = null; if (spawn == null || spawn.m_spawnAtDay || !spawn.m_spawnAtNight || string.IsNullOrEmpty(spawn.m_requiredGlobalKey)) { return false; } toggle = ToggleFor(spawn.m_requiredGlobalKey); if (toggle != null && (Object)(object)spawn.m_prefab != (Object)null) { return (Object)(object)spawn.m_prefab.GetComponent<Character>() != (Object)null; } return false; } internal static bool TryGetLiveSpawns(string bossKey, out List<SpawnData> spawns) { spawns = new List<SpawnData>(); SpawnSystem val = ((SpawnSystem.m_instances.Count > 0) ? SpawnSystem.m_instances[0] : null); if ((Object)(object)val == (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZoneSystem.instance.m_zoneCtrlPrefab != (Object)null) { val = ZoneSystem.instance.m_zoneCtrlPrefab.GetComponent<SpawnSystem>(); } if ((Object)(object)val == (Object)null || val.m_spawnLists == null) { return false; } foreach (SpawnSystemList spawnList in val.m_spawnLists) { if ((Object)(object)spawnList == (Object)null || spawnList.m_spawners == null) { continue; } foreach (SpawnData spawner in spawnList.m_spawners) { if (spawner.m_enabled && IsBossNightSpawn(spawner, out var _) && string.Equals(spawner.m_requiredGlobalKey, bossKey, StringComparison.OrdinalIgnoreCase)) { spawns.Add(spawner); } } } return true; } } internal static class BossPhases { [HarmonyPatch(typeof(Character), "OnDeath")] public static class CarryLevelToNextPhase { private static void Prefix(Character __instance) { pendingPhase = null; if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner() && NextPhase.TryGetValue(Utils.GetPrefabName(((Component)__instance).gameObject), out var value)) { int num = __instance.m_nview.GetZDO().GetInt(DataObjects.SLS_PHASE_LEVEL, 0); if (num <= 0) { num = __instance.GetLevel(); } pendingPhase = value; pendingLevel = num; } } private static void Finalizer() { pendingPhase = null; } } private static readonly HashSet<string> PinnedPrefabs = new HashSet<string> { "FrozenKing_p2" }; private static readonly Dictionary<string, string> NextPhase = new Dictionary<string, string> { { "FrozenKing", "FrozenKing_p2" }, { "FrozenKing_p2", "FrozenKing_p3" } }; private const string AspectPrefix = "Aspect_"; private static string pendingPhase; private static int pendingLevel; internal static bool IsPinned(Character chara) { if ((Object)(object)chara != (Object)null) { return PinnedPrefabs.Contains(Utils.GetPrefabName(((Component)chara).gameObject)); } return false; } internal static bool IsAspect(Character chara) { if ((Object)(object)chara != (Object)null) { return Utils.GetPrefabName(((Component)chara).gameObject).StartsWith("Aspect_", StringComparison.Ordinal); } return false; } internal static void TakeCarriedLevel(Character chara) { if (pendingPhase != null && !((Object)(object)chara == (Object)null) && !((Object)(object)chara.m_nview == (Object)null) && chara.m_nview.IsValid() && chara.m_nview.IsOwner() && !(Utils.GetPrefabName(((Component)chara).gameObject) != pendingPhase)) { ZDO zDO = chara.m_nview.GetZDO(); zDO.Set(DataObjects.SLS_PHASE_LEVEL, pendingLevel); if (!IsPinned(chara) && zDO.GetInt(ZDOVars.s_level, 0) <= 0) { zDO.Set(ZDOVars.s_level, pendingLevel, false); chara.m_level = pendingLevel; } } } } public static class Colorization { [HarmonyPatch(typeof(LevelEffects), "SetupLevelVisualization")] public static class PreventDefaultLevelSetup { public static bool Prefix() { return false; } } internal static DataObjects.CreatureColorizationSettings defaultColorizationSettings = new DataObjects.CreatureColorizationSettings { CharacterSpecificColorization = ColorizationData.characterColorizationData, DefaultLevelColorization = ColorizationData.defaultColorizationData, CharacterColorGenerators = ColorizationData.defaultColorGenerators }; public static DataObjects.CreatureColorizationSettings creatureColorizationSettings = defaultColorizationSettings; public static List<Color> mapRingColors = new List<Color>(); public static List<Color> zoneOverlayColors = new List<Color>(); public static readonly Dictionary<string, string> defaultColors = new Dictionary<string, string> { { "Red", "#ff1a1a" }, { "Orange", "#ff9933" }, { "Yellow", "#ffff1a" }, { "Green", "#50f83a" }, { "Teal", "#18e7a9" }, { "Blue", "#00abff" }, { "Purple", "#c966ff" }, { "Pink", "#ff4dcf" }, { "Gray", "#999999" }, { "Brown", "#b37700" }, { "Black", "#333333" }, { "White", "#f2f2f2" }, { "LightYellow", "#ffff99" }, { "LightOrange", "#ffc266" }, { "DarkOrange", "#cc6600" }, { "LightRed", "#ff6666" }, { "DarkRed", "#b30000" }, { "LightPurple", "#e0b3ff" }, { "DarkPurple", "#8000b3" } }; public static DataObjects.ColorDef defaultColorization = new DataObjects.ColorDef { Hue = 0f, Saturation = 0f, Value = 0f, IsEmissive = false }; private const string SLSInstancedMaterialSuffix = " (SLSColor)"; internal static void ApplyLoaded(DataObjects.CreatureColorizationSettings parsed) { if (parsed.DefaultLevelColorization == null) { parsed.DefaultLevelColorization = new Dictionary<int, DataObjects.ColorDef>(); } Colorization.creatureColorizationSettings = parsed; foreach (KeyValuePair<int, DataObjects.ColorDef> item in defaultColorizationSettings.DefaultLevelColorization) { if (!Enumerable.Contains(Colorization.creatureColorizationSettings.DefaultLevelColorization.Keys, item.Key)) { Colorization.creatureColorizationSettings.DefaultLevelColorization.Add(item.Key, item.Value); } } if (Colorization.creatureColorizationSettings.CharacterColorGenerators != null) { Logger.LogInfo("Running color generators"); DataObjects.CreatureColorizationSettings creatureColorizationSettings = Colorization.creatureColorizationSettings; if (creatureColorizationSettings.CharacterSpecificColorization == null) { Dictionary<string, Dictionary<int, DataObjects.ColorDef>> dictionary = (creatureColorizationSettings.CharacterSpecificColorization = new Dictionary<string, Dictionary<int, DataObjects.ColorDef>>()); } foreach (KeyValuePair<string, List<DataObjects.ColorRangeDef>> characterColorGenerator in Colorization.creatureColorizationSettings.CharacterColorGenerators) { Logger.LogInfo("Building color range for " + characterColorGenerator.Key); foreach (DataObjects.ColorRangeDef item2 in characterColorGenerator.Value) { BuildAddColorRange(characterColorGenerator.Key, item2); } } if (ValConfig.OutputColorizationGeneratorsData.Value) { File.WriteAllText(Path.Combine(Paths.ConfigPath, "StarLevelSystem", "DebugGeneratedColorValues.yaml"), DataObjects.yamlSerializer.Serialize((object)Colorization.creatureColorizationSettings)); } } Logger.LogInfo("Updated ColorizationSettings."); Character[] array = Resources.FindObjectsOfTypeAll<Character>(); foreach (Character val in array) { if (val.m_level > 1) { DataObjects.CharacterCacheEntry cacheEntry = CompositeLazyCache.GetCacheEntry(val); if (cacheEntry != null) { cacheEntry.Colorization = DetermineCharacterColorization(val, val.m_level); CompositeLazyCache.UpdateCharacterCacheEntry(val, cacheEntry); ApplyColorizationWithoutLevelEffects(((Component)val).gameObject, cacheEntry.Colorization); } } } } public static void ApplyLevelVisual(Character charc) { LevelEffects componentInChildren = ((Component)charc).gameObject.GetComponentInChildren<LevelEffects>(); if (!((Object)(object)componentInChildren == (Object)null) && componentInChildren.m_levelSetups != null && componentInChildren.m_levelSetups.Count > 0) { LevelSetup val = componentInChildren.m_levelSetups[Random.Range(0, componentInChildren.m_levelSetups.Count)]; if ((Object)(object)val.m_enableObject != (Object)null) { val.m_enableObject.SetActive(true); } } } internal static DataObjects.ColorDef DetermineCharacterColorization(Character cgo, int level) { if ((Object)(object)cgo == (Object)null) { return null; } string prefabName = Utils.GetPrefabName(((Component)cgo).gameObject); if (creatureColorizationSettings.CharacterSpecificColorization != null && creatureColorizationSettings.CharacterSpecificColorization.ContainsKey(prefabName) && creatureColorizationSettings.CharacterSpecificColorization[prefabName].ContainsKey(level - 1) && creatureColorizationSettings.CharacterSpecificColorization[prefabName].TryGetValue(level - 1, out var value)) { return value; } return GetDefaultColorization(level - 1); } internal static void ApplyColorizationWithoutLevelEffects(GameObject cgo, DataObjects.ColorDef colorization) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (!ValConfig.EnableColorization.Value || colorization == null) { return; } LevelSetup val = colorization.ToLevelEffect(); try { SkinnedMeshRenderer[] componentsInChildren = cgo.gameObject.GetComponentsInChildren<SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer val2 in componentsInChildren) { Material[] sharedMaterials = ((Renderer)val2).sharedMaterials; if (sharedMaterials.Length == 0) { continue; } Material val3 = sharedMaterials[0]; if (!((Object)(object)val3 == (Object)null)) { if (!((Object)val3).name.EndsWith(" (SLSColor)")) { val3 = new Material(val3); Material obj = val3; ((Object)obj).name = ((Object)obj).name + " (SLSColor)"; sharedMaterials[0] = val3; ((Renderer)val2).sharedMaterials = sharedMaterials; } val3.SetFloat("_Hue", val.m_hue); val3.SetFloat("_Saturation", val.m_saturation); val3.SetFloat("_Value", val.m_value); if (val.m_setEmissiveColor) { val3.SetColor("_EmissionColor", val.m_emissiveColor); } } } } catch (Exception arg) { Logger.LogError($"Exception while colorizing {arg}"); } } internal static void BuildAddColorRange(string creatureKey, DataObjects.ColorRangeDef colorGen) { float num = Mathf.Abs(colorGen.EndColorDef.Hue) + Mathf.Abs(colorGen.StartColorDef.Hue); Mathf.Clamp(num, 0f, 2f); float num2 = Mathf.Abs(colorGen.EndColorDef.Saturation) + Mathf.Abs(colorGen.StartColorDef.Saturation); Mathf.Clamp(num2, 0f, 2f); float num3 = Mathf.Abs(colorGen.EndColorDef.Value) + Mathf.Abs(colorGen.StartColorDef.Value); Mathf.Clamp(num3, 0f, 2f); int num4 = colorGen.RangeEnd - colorGen.RangeStart; float num5 = num / (float)num4; float num6 = num2 / (float)num4; float num7 = num3 / (float)num4; int num8 = ((!(colorGen.StartColorDef.Hue > colorGen.EndColorDef.Hue)) ? 1 : (-1)); int num9 = ((!(colorGen.StartColorDef.Saturation > colorGen.EndColorDef.Saturation)) ? 1 : (-1)); int num10 = ((!(colorGen.StartColorDef.Value > colorGen.EndColorDef.Value)) ? 1 : (-1)); if (colorGen.CharacterSpecific && !creatureColorizationSettings.CharacterSpecificColorization.ContainsKey(creatureKey)) { creatureColorizationSettings.CharacterSpecificColorization.Add(creatureKey, new Dictionary<int, DataObjects.ColorDef>()); } int num11 = colorGen.RangeStart; int num12 = 0; while (num11 < colorGen.RangeEnd + 1) { DataObjects.ColorDef value = new DataObjects.ColorDef { Hue = colorGen.StartColorDef.Hue + num5 * (float)num12 * (float)num8, Saturation = colorGen.StartColorDef.Saturation + num6 * (float)num12 * (float)num9, Value = colorGen.StartColorDef.Value + num7 * (float)num12 * (float)num10, IsEmissive = false }; if (colorGen.CharacterSpecific) { if (!creatureColorizationSettings.CharacterSpecificColorization.ContainsKey(creatureKey)) { creatureColorizationSettings.CharacterSpecificColorization.Add(creatureKey, new Dictionary<int, DataObjects.ColorDef>()); } if (creatureColorizationSettings.CharacterSpecificColorization[creatureKey].ContainsKey(num11)) { if (colorGen.OverwriteExisting) { creatureColorizationSettings.CharacterSpecificColorization[creatureKey][num11] = value; } } else { creatureColorizationSettings.CharacterSpecificColorization[creatureKey].Add(num11, value); } } else if (creatureColorizationSettings.DefaultLevelColorization.ContainsKey(num11)) { if (colorGen.OverwriteExisting) { creatureColorizationSettings.DefaultLevelColorization[num11] = value; } } else { creatureColorizationSettings.DefaultLevelColorization.Add(num11, value); } num11++; num12++; } } internal static DataObjects.ColorDef GetDefaultColorization(int level) { if (creatureColorizationSettings.DefaultLevelColorization.ContainsKey(level)) { return creatureColorizationSettings.DefaultLevelColorization[level]; } return defaultColorization; } public static void UpdateMapColorSelection() { ParseColorOptions(ValConfig.DistanceRingColorOptions.Value, mapRingColors, "distance ring"); } public static void UpdateZoneOverlayColorSelection() { ParseColorOptions(ValConfig.ZoneOverlayColorOptions.Value, zoneOverlayColors, "zone overlay"); } private static void ParseColorOptions(string optionsCsv, List<Color> target, string contextLabel) { //IL_004c: 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) target.Clear(); Color item = default(Color); Color item2 = default(Color); foreach (string item3 in optionsCsv.Split(new char[1] { ',' }).ToList()) { if (item3.StartsWith("#")) { if (ColorUtility.TryParseHtmlString(item3.Trim(), ref item)) { target.Add(item); continue; } Logger.LogWarning("Unable to parse color string " + item3 + " for " + contextLabel + " colors. It will be skipped"); } else { string key = StringExtensions.CapitalizeFirstLetter(item3.Trim()); if (defaultColors.TryGetValue(key, out var value) && ColorUtility.TryParseHtmlString(value, ref item2)) { target.Add(item2); } } } } } internal static class Compatibility { public static bool IsDropThatEnabled = false; public static bool IsExpandWorldEnabled = false; public static bool IsFGNEnabled = false; public static bool IsCustomRaidsEnabled = false; public static bool IsJewelcraftingEnabled = false; public static bool IsVentureLocationResetEnabled = false; public static bool IsUpgradeWorldEnabled = false; public static bool IsValheimPlusEnabled = false; internal const string AugaGUID = "randyknapp.mods.auga"; private const string DropThatGUID = "asharppen.valheim.drop_that"; private const string DropThatSessionManagerTypeName = "DropThat.Drop.CharacterDropSystem.Managers.CharacterDropSessionManager"; private static readonly Version DropThatCharacterDropTrackingFixed = new Version(3, 1, 6); private static Type DropThatCharacterDropSessionManager; private static MethodInfo DropThatCharacterModifyDrop; private static MethodInfo JewelcraftingBossHudPostfix; private const string ValheimPlusGUID = "org.bepinex.plugins.valheim_plus"; private static Func<GameObject, int, int> ValheimPlusPickableYield; private static PropertyInfo ValheimPlusConfigCurrent; private static PropertyInfo ValheimPlusGameSection; private static PropertyInfo ValheimPlusGameEnabled; private static PropertyInfo ValheimPlusDamageScale; private static PropertyInfo ValheimPlusHealthScale; private static bool ValheimPlusPickableYieldFailed; private static bool ValheimPlusDifficultyFailed; public static bool CustomRaidsCompatActive { get { if (IsCustomRaidsEnabled) { return ValConfig.EnableCustomRaidsCompat.Value; } return false; } } public static bool IsAugaEnabled => Chainloader.PluginInfos.ContainsKey("randyknapp.mods.auga"); public static bool DropThatCharacterModifyAvailable => DropThatCharacterModifyDrop != null; internal static void CheckModCompat() { try { Dictionary<string, BaseUnityPlugin> plugins = BepInExUtils.GetPlugins(false); if (plugins == null) { return; } if (plugins.TryGetValue("asharppen.valheim.drop_that", out var value)) { IsDropThatEnabled = true; DropThatCharacterDropSessionManager = ((object)value)?.GetType().Assembly.GetType("DropThat.Drop.CharacterDropSystem.Managers.CharacterDropSessionManager"); if (DropThatCharacterDropSessionManager != null) { DropThatCharacterModifyDrop = DropThatCharacterDropSessionManager.GetMethod("ModifyDrop", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(GameObject), typeof(List<KeyValuePair<GameObject, int>>), typeof(int) }, null); } if (!DropThatCharacterModifyAvailable) { Logger.LogWarning("Warning: DropThat compat method (CharacterDropSessionManager.ModifyDrop) not found; DropThat item modifiers will not be applied to creature loot."); } else { PluginInfo info = value.Info; object obj; if (info == null) { obj = null; } else { BepInPlugin metadata = info.Metadata; obj = ((metadata != null) ? metadata.Version : null); } Version version = (Version)obj; if (version != null && version < DropThatCharacterDropTrackingFixed) { Logger.LogWarning($"Drop That {version} detected; its creature drop modifiers need Drop That {DropThatCharacterDropTrackingFixed} or newer on this Valheim version and will not apply until it is updated."); } else { Logger.LogInfo("Drop That detected; its item modifiers will be applied to creature loot."); } } } if (Enumerable.Contains(plugins.Keys, "com.Fire.FiresGhettoNetworkMod")) { IsFGNEnabled = true; } if (Enumerable.Contains(plugins.Keys, "expand_world_size")) { IsExpandWorldEnabled = true; } if (Enumerable.Contains(plugins.Keys, "asharppen.valheim.custom_raids")) { IsCustomRaidsEnabled = true; Logger.LogInfo("Valheim.CustomRaids detected; CustomRaids raids will fire alongside SLS raids while EnableCustomRaidsCompat is enabled."); } if (Enumerable.Contains(plugins.Keys, "com.Venture.LocationReset")) { IsVentureLocationResetEnabled = true; LocationResetData.BlockedByModConflict = true; if (ValConfig.EnableLocationReset.Value) { Logger.LogWarning("VentureValheim LocationReset detected; SLS Location Reset has been disabled. Remove VentureValheim LocationReset to use SLS Location Reset - running both will fight over the same objects."); } else { Logger.LogInfo("VentureValheim LocationReset detected; SLS Location Reset is unavailable while it is installed."); } } if (Enumerable.Contains(plugins.Keys, "upgrade_world")) { IsUpgradeWorldEnabled = true; Logger.LogInfo("Upgrade World detected; its locations_reset / vegetation_reset commands overlap with SLS Location Reset. Avoid running both against the same zones."); } if (Enumerable.Contains(plugins.Keys, "org.bepinex.plugins.jewelcrafting")) { IsJewelcraftingEnabled = true; JewelcraftingBossHudPostfix = AccessTools.Method("Jewelcrafting.WorldBosses.BossHud+DisplayMultipleBossHuds:Postfix", (Type[])null, (Type[])null); if (JewelcraftingBossHudPostfix == null) { Logger.LogWarning("Jewelcrafting detected but DisplayMultipleBossHuds.Postfix could not be found; boss-HUD compatibility patch will be skipped."); } } if (plugins.TryGetValue("org.bepinex.plugins.valheim_plus", out var value2)) { IsValheimPlusEnabled = true; BindValheimPlus(((object)value2).GetType().Assembly); } } catch { Logger.LogWarning("Unable to check mod compatibility. Ensure that Bepinex can load."); } } public static void DropThat_ModifyCharacterDrop(GameObject drop, List<KeyValuePair<GameObject, int>> drops, int index) { if (!DropThatCharacterModifyAvailable) { return; } try { DropThatCharacterModifyDrop.Invoke(null, new object[3] { drop, drops, index }); } catch (Exception ex) { Logger.LogWarning("DropThat ModifyDrop failed: " + ex.Message); } } private static void BindValheimPlus(Assembly valheimPlus) { MethodInfo methodInfo = valheimPlus.GetType("ValheimPlus.GameClasses.PickableYieldState")?.GetMethod("CalculateYield", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(GameObject), typeof(int) }, null); if (methodInfo != null && methodInfo.ReturnType == typeof(int)) { ValheimPlusPickableYield = (Func<GameObject, int, int>)Delegate.CreateDelegate(typeof(Func<GameObject, int, int>), methodInfo); Logger.LogInfo("Valheim Plus detected; its [Pickable] yields apply to pickables with an SLS loot table."); } else { Logger.LogWarning("Valheim Plus detected but its pickable yield (PickableYieldState.CalculateYield) was not found; its [Pickable] yields will not apply to pickables with an SLS loot table."); } Type type = valheimPlus.GetType("ValheimPlus.Configurations.Configuration"); ValheimPlusGameSection = type?.GetProperty("Game", BindingFlags.Instance | BindingFlags.Public); Type obj = ValheimPlusGameSection?.PropertyType; ValheimPlusGameEnabled = obj?.GetProperty("IsEnabled", BindingFlags.Instance | BindingFlags.Public); ValheimPlusDamageScale = obj?.GetProperty("gameDifficultyDamageScale", BindingFlags.Instance | BindingFlags.Public); ValheimPlusHealthScale = obj?.GetProperty("gameDifficultyHealthScale", BindingFlags.Instance | BindingFlags.Public); if (ValheimPlusGameEnabled?.PropertyType == typeof(bool) && ValheimPlusDamageScale?.PropertyType == typeof(float) && ValheimPlusHealthScale?.PropertyType == typeof(float)) { ValheimPlusConfigCurrent = type.GetProperty("Cur