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 FrostVale ModPack 3 v3.1.2
plugins/FrostValeCompat/FrostValeCompat.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FrostValeCompat { [BepInPlugin("frostvale.compat", "FrostVale Compat", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class RiceWaterLevelPlugin : BaseUnityPlugin { public const string PluginGuid = "frostvale.compat"; public const string PluginName = "FrostVale Compat"; public const string PluginVersion = "1.1.0"; internal static ConfigEntry<float> MinGroundOffset; internal static ConfigEntry<float> MaxGroundOffset; internal static ConfigEntry<bool> BlockRiceAwayFromWater; internal static ConfigEntry<bool> EnableCreatureGemDrops; internal static ConfigEntry<float> CreatureGemDefaultChance; internal static RiceWaterLevelPlugin Instance; internal static ManualLogSource Log; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; BlockRiceAwayFromWater = ((BaseUnityPlugin)this).Config.Bind<bool>("RtDOcean Rice", "Block rice away from water level", true, "If enabled, RtDOcean rice saplings can only be placed near the configured water-level band."); MinGroundOffset = ((BaseUnityPlugin)this).Config.Bind<float>("RtDOcean Rice", "Minimum ground offset from water", -0.35f, "Lowest allowed terrain height relative to water level, in meters."); MaxGroundOffset = ((BaseUnityPlugin)this).Config.Bind<float>("RtDOcean Rice", "Maximum ground offset from water", 0.15f, "Highest allowed terrain height relative to water level, in meters."); EnableCreatureGemDrops = ((BaseUnityPlugin)this).Config.Bind<bool>("Jewelcrafting Creature Drops", "Enable star-scaled creature gem drops", true, "If enabled, FrostVale adds Jewelcrafting gems to non-boss creature drops based on CLLC star level."); CreatureGemDefaultChance = ((BaseUnityPlugin)this).Config.Bind<float>("Jewelcrafting Creature Drops", "Default low-star unrefined drop chance", 1.5f, "Percent chance used for 0-3 star unrefined gem drops."); Harmony.CreateAndPatchAll(typeof(RiceWaterLevelPlugin).Assembly, "frostvale.compat"); DiscordNameDisplayPatches.Patch(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FrostVale compatibility patches loaded."); } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class RicePlacementPatch { private static bool Prefix(Piece piece, ref bool __result) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!RiceWaterLevelPlugin.BlockRiceAwayFromWater.Value || !RiceWaterLevelRules.IsRiceSapling(piece)) { return true; } Vector3 position = ((Component)piece).transform.position; if (RiceWaterLevelRules.IsWithinWaterBand(position, out var groundHeight, out var waterLevel)) { return true; } __result = false; ShowMessage($"Rice must be planted at water level. Ground {groundHeight - waterLevel:0.00}m from water."); return false; } private static void ShowMessage(string message) { try { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false); } } catch (Exception ex) { RiceWaterLevelPlugin.Log.LogDebug((object)("Could not show rice placement message: " + ex.Message)); } } } [HarmonyPatch(typeof(Plant), "GetStatus")] internal static class RicePlantStatusPatch { private static void Postfix(Plant __instance, ref Status __result) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (RiceWaterLevelPlugin.BlockRiceAwayFromWater.Value && (int)__result == 0 && RiceWaterLevelRules.IsRicePlant(__instance) && !RiceWaterLevelRules.IsWithinWaterBand(((Component)__instance).transform.position, out var _, out var _)) { __result = (Status)3; } } } internal static class RiceWaterLevelRules { public static bool IsRiceSapling(Piece piece) { if ((Object)(object)piece == (Object)null) { return false; } return LooksLikeRice(((Object)piece).name) || LooksLikeRice(((Object)((Component)piece).gameObject).name) || LooksLikeRice(piece.m_name); } public static bool IsRicePlant(Plant plant) { if ((Object)(object)plant == (Object)null) { return false; } return LooksLikeRice(((Object)plant).name) || LooksLikeRice(((Object)((Component)plant).gameObject).name) || LooksLikeRice(plant.m_name); } public static bool IsWithinWaterBand(Vector3 position, out float groundHeight, out float waterLevel) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) ZoneSystem instance = ZoneSystem.instance; waterLevel = (((Object)(object)instance != (Object)null) ? instance.m_waterLevel : 30f); groundHeight = position.y; float num = default(float); if ((Object)(object)instance != (Object)null && instance.GetGroundHeight(position, ref num)) { groundHeight = num; } float num2 = groundHeight - waterLevel; return num2 >= RiceWaterLevelPlugin.MinGroundOffset.Value && num2 <= RiceWaterLevelPlugin.MaxGroundOffset.Value; } private static bool LooksLikeRice(string value) { return !string.IsNullOrEmpty(value) && value.IndexOf("Rice", StringComparison.OrdinalIgnoreCase) >= 0 && value.IndexOf("_RtD", StringComparison.OrdinalIgnoreCase) >= 0; } } internal static class DiscordNameDisplayPatches { private static readonly Dictionary<string, string> NamesById = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private static readonly Regex NumericIdPattern = new Regex("\\b\\d{15,20}\\b", RegexOptions.Compiled); public static void Patch() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown try { Harmony harmony = new Harmony("frostvale.compat.discord-names"); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordIntegrationCore", "OnPlayerJoin", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordIntegrationCore", "OnPlayerLeave", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordIntegrationCore", "OnClientLoginArtifacts", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordIntegrationCore", "SendClientLogOnRequest", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.ClientLogRelay.ClientLogRelayIntegration", "PostDisconnectLog", typeof(DiscordPlayerNameTracker).GetMethod("IdFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.ClientLogRelay.ClientLogRelayIntegration", "PostDisconnectLogAsync", typeof(DiscordPlayerNameTracker).GetMethod("IdFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordStatusTracker", "RecordJoin", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordStatusTracker", "RecordLeave", typeof(DiscordPlayerNameTracker).GetMethod("PlayerNameFirstPrefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordWebhookService", "SendMessage", typeof(DiscordVisibleTextRewriter).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordWebhookService", "SendEmbed", typeof(DiscordVisibleTextRewriter).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordWebhookService", "SendEmbedWithFiles", typeof(DiscordVisibleTextRewriter).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic)); PatchPrefix(harmony, "FiresDiscordIntegration.Discord.DiscordWebhookService", "EnqueuePost", typeof(DiscordVisibleTextRewriter).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic)); RiceWaterLevelPlugin.Log.LogInfo((object)"FrostVale Discord name-display patch loaded."); } catch (Exception ex) { RiceWaterLevelPlugin.Log.LogWarning((object)("FrostVale Discord name-display patch skipped: " + ex.Message)); } } private static void PatchPrefix(Harmony harmony, string typeName, string methodName, MethodInfo prefix) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown if (prefix == null) { return; } Type type = AccessTools.TypeByName(typeName); if (type == null) { return; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (declaredMethod.Name == methodName) { harmony.Patch((MethodBase)declaredMethod, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } internal static void Remember(string platformId, string playerName) { if (!string.IsNullOrWhiteSpace(platformId) && !string.IsNullOrWhiteSpace(playerName) && !IsRawId(playerName)) { NamesById[platformId.Trim()] = playerName.Trim(); } } internal static string RewriteText(string value) { if (string.IsNullOrEmpty(value) || NamesById.Count == 0) { return value; } string value2; return NumericIdPattern.Replace(value, (Match match) => NamesById.TryGetValue(match.Value, out value2) ? value2 : match.Value); } internal static bool IsRawId(string value) { return !string.IsNullOrWhiteSpace(value) && NumericIdPattern.IsMatch(value.Trim()); } } internal static class DiscordPlayerNameTracker { private static void PlayerNameFirstPrefix(object[] __args) { if (__args != null && __args.Length >= 2) { DiscordNameDisplayPatches.Remember(__args[1] as string, __args[0] as string); } } private static void IdFirstPrefix(object[] __args) { if (__args != null && __args.Length >= 2) { DiscordNameDisplayPatches.Remember(__args[0] as string, __args[1] as string); } } } internal static class DiscordVisibleTextRewriter { private static void Prefix(object[] __args) { if (__args == null) { return; } for (int i = 0; i < __args.Length; i++) { object obj = __args[i]; if (obj is string value) { __args[i] = DiscordNameDisplayPatches.RewriteText(value); } else { RewriteObject(obj, new HashSet<object>(ReferenceEqualityComparer.Instance)); } } } private static void RewriteObject(object value, HashSet<object> visited) { if (value == null || value is string || value.GetType().IsPrimitive || !visited.Add(value)) { return; } if (value is IDictionary dictionary) { List<object> list = new List<object>(); foreach (object key in dictionary.Keys) { list.Add(key); } { foreach (object item in list) { object obj = dictionary[item]; string text = obj as string; dictionary[item] = ((text != null) ? DiscordNameDisplayPatches.RewriteText(text) : RewriteAndReturn(obj, visited)); } return; } } if (value is IList list2) { for (int i = 0; i < list2.Count; i++) { object obj2 = list2[i]; string text2 = obj2 as string; list2[i] = ((text2 != null) ? DiscordNameDisplayPatches.RewriteText(text2) : RewriteAndReturn(obj2, visited)); } return; } FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(string)) { string value2 = fieldInfo.GetValue(value) as string; fieldInfo.SetValue(value, DiscordNameDisplayPatches.RewriteText(value2)); } else if (!fieldInfo.FieldType.IsValueType) { RewriteObject(fieldInfo.GetValue(value), visited); } } } private static object RewriteAndReturn(object value, HashSet<object> visited) { RewriteObject(value, visited); return value; } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] internal static class JewelcraftingCreatureDropPatch { private static readonly FieldRef<CharacterDrop, Character> CharacterRef = AccessTools.FieldRefAccess<CharacterDrop, Character>("m_character"); private static readonly string[] UnrefinedGemPrefabs = new string[7] { "Uncut_Green_Stone", "Uncut_Orange_Stone", "Uncut_Black_Stone", "Uncut_Red_Stone", "Uncut_Blue_Stone", "Uncut_Purple_Stone", "Uncut_Yellow_Stone" }; private static readonly string[] SimpleGemPrefabs = new string[7] { "Simple_Green_Socket", "Simple_Orange_Socket", "Simple_Black_Socket", "Simple_Red_Socket", "Simple_Blue_Socket", "Simple_Purple_Socket", "Simple_Yellow_Socket" }; private static readonly string[] AdvancedGemPrefabs = new string[7] { "Advanced_Green_Socket", "Advanced_Orange_Socket", "Advanced_Black_Socket", "Advanced_Red_Socket", "Advanced_Blue_Socket", "Advanced_Purple_Socket", "Advanced_Yellow_Socket" }; private static readonly HashSet<string> MissingPrefabWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static void Postfix(CharacterDrop __instance, ref List<KeyValuePair<GameObject, int>> __result) { if (!RiceWaterLevelPlugin.EnableCreatureGemDrops.Value || (Object)(object)__instance == (Object)null || __result == null) { return; } Character val = CharacterRef.Invoke(__instance); if ((Object)(object)val == (Object)null) { val = ((Component)__instance).GetComponent<Character>(); } if (!((Object)(object)val == (Object)null) && !val.IsBoss()) { switch (Math.Max(0, Math.Min(5, val.GetLevel() - 1))) { case 0: AddDefaultGatedDrops(__result, UnrefinedGemPrefabs, 1); break; case 1: AddDefaultGatedDrops(__result, UnrefinedGemPrefabs, 2); break; case 2: AddDefaultGatedDrops(__result, UnrefinedGemPrefabs, 3); break; case 3: AddRandomDrops(__result, SimpleGemPrefabs, 0, 1); AddDefaultGatedDrops(__result, UnrefinedGemPrefabs, 2); break; case 4: AddRandomDrops(__result, SimpleGemPrefabs, 0, 2); AddRandomDrops(__result, UnrefinedGemPrefabs, 1, 3); break; default: AddRandomDrops(__result, AdvancedGemPrefabs, 0, 2); AddRandomDrops(__result, UnrefinedGemPrefabs, 2, 4); break; } } } private static void AddDefaultGatedDrops(List<KeyValuePair<GameObject, int>> drops, string[] prefabNames, int maxAmount) { float num = Mathf.Clamp(RiceWaterLevelPlugin.CreatureGemDefaultChance.Value, 0f, 100f); if (!(Random.Range(0f, 100f) >= num)) { AddRandomDrops(drops, prefabNames, 1, maxAmount); } } private static void AddRandomDrops(List<KeyValuePair<GameObject, int>> drops, string[] prefabNames, int minAmount, int maxAmount) { int num = Random.Range(minAmount, maxAmount + 1); for (int i = 0; i < num; i++) { GameObject randomPrefab = GetRandomPrefab(prefabNames); if ((Object)(object)randomPrefab != (Object)null) { drops.Add(new KeyValuePair<GameObject, int>(randomPrefab, 1)); } } } private static GameObject GetRandomPrefab(string[] prefabNames) { if (prefabNames == null || prefabNames.Length == 0) { return null; } string text = prefabNames[Random.Range(0, prefabNames.Length)]; GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null); if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.GetPrefab(text); } if ((Object)(object)val == (Object)null && MissingPrefabWarnings.Add(text)) { RiceWaterLevelPlugin.Log.LogWarning((object)("FrostVale Jewelcrafting drop prefab not found: " + text)); } return val; } } internal sealed class ReferenceEqualityComparer : IEqualityComparer<object> { public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); private ReferenceEqualityComparer() { } public new bool Equals(object x, object y) { return x == y; } public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } }