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 LethalCardLoader v0.2.0
LethalCardLoader.dll
Decompiled 8 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalCardLoader.Config; using LethalCardLoader.CustomProps; using LethalCardLoader.ModLoading; using LethalCardLoader.Models; using LethalCardLoader.NetcodePatcher; using LethalLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LethalCardLoader")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Trading Cards for Lethal Company")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+0973080823146e5b641a5d6f62a6afe9237984d4")] [assembly: AssemblyProduct("LethalCardLoader")] [assembly: AssemblyTitle("LethalCardLoader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 LethalCardLoader { [BepInPlugin("com.sholiver.lethalcardloader", "LethalCardLoader", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string modGUID = "com.sholiver.lethalcardloader"; public const string modName = "LethalCardLoader"; public const string modVersion = "0.2.0"; public static Plugin Instance; public static ManualLogSource logger; private void Awake() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } Instance = this; logger = ((BaseUnityPlugin)this).Logger; string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ConfigManager.LoadMoonConfigs(); ConfigManager.CreateDefaults(); ConfigManager.LoadSetConfigs(); ConfigManager.LoadSpawnGroupConfigs(); ConfigManager.LoadRarityConfigs(); CardRegistryHelper cardRegistryHelper = new CardRegistryHelper(logger, directoryName); cardRegistryHelper.RegisterAllCards(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.sholiver.lethalcardloader"); logger.LogInfo((object)"Plugin com.sholiver.lethalcardloader is loaded!"); } } public static class PluginInfo { public const string PLUGIN_GUID = "LethalCardLoader"; public const string PLUGIN_NAME = "LethalCardLoader"; public const string PLUGIN_VERSION = "0.2.0"; } } namespace LethalCardLoader.Patches { [HarmonyPatch(typeof(DepositItemsDesk), "SellItemsOnServer")] internal static class DepositItemsDeskPatch { private static readonly List<int> _pendingSoldCardIds = new List<int>(); [HarmonyPrefix] private static void BeforeSell(DepositItemsDesk __instance) { _pendingSoldCardIds.Clear(); foreach (GrabbableObject item in __instance.itemsOnCounter) { if (item is BaseCardProp baseCardProp) { _pendingSoldCardIds.Add(baseCardProp.TemplateId); } } } [HarmonyPostfix] private static void AfterSell() { foreach (int pendingSoldCardId in _pendingSoldCardIds) { CollectionTracker.IncrementSold(pendingSoldCardId); } _pendingSoldCardIds.Clear(); } } [HarmonyPatch(typeof(GrabbableObject))] internal static class GrabbableObjectPatch { [HarmonyPrefix] [HarmonyPatch("SetScrapValue")] public static bool SetScrapValuePrefix(GrabbableObject __instance, int setValueTo) { TemplatableProp templatableProp = __instance as TemplatableProp; if ((Object)(object)templatableProp == (Object)null) { return true; } return !templatableProp.isSynced; } [HarmonyPostfix] [HarmonyPatch("SetScrapValue")] public static void SetScrapValuePostfix(GrabbableObject __instance, int setValueTo) { TemplatableProp templatableProp = __instance as TemplatableProp; if (!((Object)(object)templatableProp == (Object)null)) { templatableProp.isSynced = true; } } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [HarmonyPostfix] [HarmonyPatch("Start")] private static void StartPostfix(StartOfRound __instance) { Dictionary<string, string> source = __instance.levels.Where((SelectableLevel l) => (Object)(object)l != (Object)null && !string.IsNullOrWhiteSpace(l.PlanetName)).ToDictionary((SelectableLevel l) => l.PlanetName, (SelectableLevel l) => ((Object)l).name); Dictionary<string, string> dictionary = source.Where((KeyValuePair<string, string> kvp) => !ConfigManager.Moons.Any((MoonEntry m) => m.PlanetName == kvp.Key)).ToDictionary((KeyValuePair<string, string> kvp) => kvp.Key, (KeyValuePair<string, string> kvp) => kvp.Value); if (dictionary.Count > 0) { ConfigManager.CreateMissingMoonConfigs(dictionary); } else { Plugin.logger.LogInfo((object)"[StartOfRoundPatch] No missing moons to register."); } CollectionTracker.Initialise(); } } [HarmonyPatch(typeof(Terminal))] internal static class TerminalPatch { private static Terminal _terminalInstance; [HarmonyPatch("OnSubmit")] [HarmonyPrefix] private static void OnSubmit(Terminal __instance) { TMP_InputField screenText = __instance.screenText; if ((Object)(object)screenText == (Object)null) { return; } string text = screenText.text; if (!string.IsNullOrWhiteSpace(text)) { string[] source = text.Split('\n'); string text2 = source.LastOrDefault()?.Trim().ToLower(); if (!string.IsNullOrWhiteSpace(text2) && text2.StartsWith("cards")) { string[] source2 = text2.Split(' ', StringSplitOptions.RemoveEmptyEntries); string[] args = source2.Skip(1).ToArray(); string text3 = CardCommand.Execute(args); __instance.LoadNewNode(CreateTextNode(text3)); screenText.text = ""; } } } private static TerminalNode CreateTextNode(string text) { TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.displayText = text + "\n\n"; val.clearPreviousText = true; val.terminalEvent = ""; return val; } } } namespace LethalCardLoader.ModLoading { public class CardCommand { private const int MaxNameDisplayLength = 15; private const int CardsPerPage = 15; public static string Execute(string[] args) { if (args.Length == 0) { return GetOverview(); } string setKey = args[0]; if (args.Length == 1) { return GetSetListView(setKey, 1); } string text = args[1].ToLower(); if (text.Length > 1 && text[0] == 'p' && int.TryParse(text.Substring(1), out var result)) { return GetSetListView(setKey, result); } if (int.TryParse(text, out var result2)) { return GetCardView(setKey, result2); } return "Usage: cards [setKey] [p<pageNumber>|<cardNumber>]"; } private static string GetOverview() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("╔════════════════════════════════════════════════╗"); stringBuilder.AppendLine("║ LETHAL CARD COLLECTION ║"); stringBuilder.AppendLine("╚════════════════════════════════════════════════╝\n"); foreach (SetEntry set in ConfigManager.Sets) { IEnumerable<int> enumerable = ModCardDatabase.Sets[set.Key].Cards.Select((KeyValuePair<int, ModCardDatabase.CardInfo> a) => a.Value.Id); (int owned, int sold) totalsForSet = CollectionTracker.GetTotalsForSet(enumerable); int item = totalsForSet.owned; int item2 = totalsForSet.sold; int num = enumerable.Count(); stringBuilder.AppendLine($"{set.Name,-10} ({set.Key}): {item,3} / {num,-3} found ({item2} sold)"); } stringBuilder.AppendLine("\nUse 'cards [setKey]' to view cards in a set."); return stringBuilder.ToString(); } private static string GetSetListView(string setKey, int page) { SetEntry setEntry = ConfigManager.Sets.FirstOrDefault((SetEntry s) => s.Key.Equals(setKey, StringComparison.OrdinalIgnoreCase)); if (setEntry == null) { return "Set '" + setKey + "' not found."; } List<ModCardDatabase.CardInfo> list = ModCardDatabase.Sets[setKey].Cards.Values.OrderBy((ModCardDatabase.CardInfo a) => a.Number).ToList(); if (list.Count() == 0) { return "No cards found in set '" + setEntry.Name + "'."; } int num = (list.Count + 15 - 1) / 15; if (page < 1) { page = 1; } if (page > num) { page = num; } List<ModCardDatabase.CardInfo> list2 = list.Skip((page - 1) * 15).Take(15).ToList(); int num2 = 3; int num3 = 15; int num4 = 9; int num5 = 5; int num6 = 4; StringBuilder stringBuilder = new StringBuilder(); string text = $"=== {setEntry.Name.ToUpper()} (Page {page}/{num}) ==="; stringBuilder.AppendLine(text); stringBuilder.AppendLine(new string('═', text.Length)); stringBuilder.Append("No.".PadRight(num2) + " │ "); stringBuilder.Append("Name".PadRight(num3) + " │ "); stringBuilder.Append("Status".PadRight(num4) + " │ "); stringBuilder.Append("Owned".PadLeft(num5) + " │ "); stringBuilder.AppendLine("Sold".PadLeft(num6) ?? ""); int count = num2 + 3 + num3 + 3 + num4 + 3 + num5 + 3 + num6; stringBuilder.AppendLine(new string('─', count)); foreach (ModCardDatabase.CardInfo item in list2) { int owned = CollectionTracker.GetOwned(item.Id); int sold = CollectionTracker.GetSold(item.Id); string text2 = ((owned > 0) ? "Collected" : "Missing"); string text3 = ((item.Name.Length > 15) ? (item.Name.Substring(0, 12) + "...") : item.Name); stringBuilder.Append(item.Number.ToString().PadRight(num2) + " │ "); stringBuilder.Append(text3.PadRight(num3) + " │ "); stringBuilder.Append(text2.PadRight(num4) + " │ "); stringBuilder.Append(owned.ToString().PadLeft(num5) + " │ "); stringBuilder.AppendLine(sold.ToString().PadLeft(num6) ?? ""); } stringBuilder.AppendLine(); if (num > 1) { if (page < num) { stringBuilder.AppendLine($"Next: cards {setKey} p{page + 1}"); } if (page > 1) { stringBuilder.AppendLine($"Prev: cards {setKey} p{page - 1}"); } } stringBuilder.AppendLine("Detail: cards " + setKey + " [number]"); return stringBuilder.ToString(); } private static string GetCardView(string setKey, int cardNumber) { if (!ModCardDatabase.Sets.TryGetValue(setKey, out var value)) { return "Set '" + setKey + "' not found."; } if (!value.Cards.TryGetValue(cardNumber, out var card)) { return $"Card #{cardNumber} not found in set '{setKey}'."; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("=== CARD DETAILS ===\n"); stringBuilder.AppendLine("Name: " + card.Name); stringBuilder.AppendLine("Set: " + ConfigManager.Sets.First((SetEntry s) => s.Key == card.SetKey).Name); stringBuilder.AppendLine($"Number: {card.Number:D3}"); stringBuilder.AppendLine("Rarity: " + card.Rarity); stringBuilder.AppendLine("Metallic: " + (card.Metallic ? "Yes" : "No")); stringBuilder.AppendLine($"Value: {card.MinValue} - {card.MaxValue}"); stringBuilder.AppendLine($"Owned: {CollectionTracker.GetOwned(card.Id)}"); stringBuilder.AppendLine($"Sold: {CollectionTracker.GetSold(card.Id)}"); var list = (from kvp in card.MoonSpawnWeights where kvp.Value > 0.0 orderby kvp.Value descending select new { InternalName = kvp.Key, Weight = kvp.Value, PlanetName = ConfigManager.LevelNamesMap.FirstOrDefault((KeyValuePair<string, string> a) => a.Value == kvp.Key).Key }).ToList(); if (list.Count > 0) { stringBuilder.AppendLine("\n=== SPAWN LOCATIONS ==="); foreach (var item in list) { stringBuilder.AppendLine($"{item.PlanetName,-20} | Weight: {item.Weight:F2}"); } } else { stringBuilder.AppendLine("\nNo spawn locations configured for this card."); } return stringBuilder.ToString(); } } public class CardRegistryHelper { private readonly ManualLogSource _logger; private readonly string _pluginDir; private readonly string _contentDir; private Item _cardBaseItem; private Item _cardPackBaseItem; private Dictionary<string, RarityEntry> _rarities; private Dictionary<string, SpawnGroupEntry> _spawnGroups; public CardRegistryHelper(ManualLogSource logger, string pluginDir) { _logger = logger; _pluginDir = pluginDir; _contentDir = Path.Combine(_pluginDir, "Content"); } public void RegisterAllCards() { _spawnGroups = ConfigManager.SpawnGroups.ToDictionary((SpawnGroupEntry s) => s.Key, (SpawnGroupEntry s) => s); _rarities = ConfigManager.RarityConfigs.ToDictionary((RarityEntry r) => r.Key, (RarityEntry r) => r); if (LoadBundle()) { LoadAndRegisterSets(); ModCardDatabase.CalculateMoonSpawnWeightsForCards(); ModCardDatabase.CalculateMoonSpawnWeightsForPacks(); ModCardDatabase.CalculatePackDropRates(_rarities); } } private bool LoadBundle() { string text = Path.Combine(_pluginDir, "lethalcardloader"); AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val == (Object)null) { _logger.LogError((object)("Failed to load asset bundle from " + text)); return false; } _cardBaseItem = val.LoadAsset<Item>("Assets/LethalCardLoader/CardBase_Item.asset"); _cardBaseItem.saveItemVariable = true; ((Object)_cardBaseItem).name = "BaseCard"; _cardBaseItem.itemName = "BaseCard"; _cardBaseItem.isScrap = true; BaseCardProp baseCardProp = _cardBaseItem.spawnPrefab.AddComponent<BaseCardProp>(); ((GrabbableObject)baseCardProp).grabbable = true; ((GrabbableObject)baseCardProp).grabbableToEnemies = true; ((GrabbableObject)baseCardProp).itemProperties = _cardBaseItem; ((Object)baseCardProp).name = "BaseCard"; NetworkPrefabs.RegisterNetworkPrefab(_cardBaseItem.spawnPrefab); Utilities.FixMixerGroups(_cardBaseItem.spawnPrefab); (Dictionary<LevelTypes, int>, Dictionary<string, int>) tuple = SplitLevelRarity(ConfigManager.Moons.ToDictionary((MoonEntry a) => a.InternalName, (MoonEntry a) => a.CardScrapRarity)); Items.RegisterScrap(_cardBaseItem, tuple.Item1, tuple.Item2); _cardPackBaseItem = val.LoadAsset<Item>("Assets/LethalCardLoader/CardPackBase_Item.asset"); _cardPackBaseItem.saveItemVariable = true; ((Object)_cardPackBaseItem).name = "BasePack"; _cardPackBaseItem.itemName = "BasePack"; _cardPackBaseItem.isScrap = true; BoosterPackProp boosterPackProp = _cardPackBaseItem.spawnPrefab.AddComponent<BoosterPackProp>(); ((GrabbableObject)boosterPackProp).grabbable = true; ((GrabbableObject)boosterPackProp).grabbableToEnemies = true; ((GrabbableObject)boosterPackProp).itemProperties = _cardPackBaseItem; ((Object)boosterPackProp).name = "BasePack"; NetworkPrefabs.RegisterNetworkPrefab(_cardPackBaseItem.spawnPrefab); Utilities.FixMixerGroups(_cardPackBaseItem.spawnPrefab); (Dictionary<LevelTypes, int>, Dictionary<string, int>) tuple2 = SplitLevelRarity(ConfigManager.Moons.ToDictionary((MoonEntry a) => a.InternalName, (MoonEntry a) => a.PackScrapRarity)); Items.RegisterScrap(_cardPackBaseItem, tuple2.Item1, tuple2.Item2); return true; } public (Dictionary<LevelTypes, int> vanilla, Dictionary<string, int> modded) SplitLevelRarity(Dictionary<string, int> levels) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) Dictionary<LevelTypes, int> dictionary = new Dictionary<LevelTypes, int>(); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> level in levels) { if (Enum.TryParse(typeof(LevelTypes), level.Key, out object result)) { dictionary[(LevelTypes)result] = level.Value; } else { dictionary2[level.Key] = level.Value; } } return (dictionary, dictionary2); } private void LoadAndRegisterSets() { foreach (SetEntry set in ConfigManager.Sets) { LoadAndRegisterSet(set); } } private void LoadAndRegisterSet(SetEntry setEntry) { string path = Path.Combine(_contentDir, setEntry.Key, setEntry.Key + ".json"); SetManifest setManifest = LoadJson<SetManifest>(path); if (setManifest == null) { _logger.LogWarning((object)("Skipping set '" + setEntry.Key + "' — manifest failed to load.")); return; } string key = ResolveSpawnGroup(setEntry.SpawnGroup); SpawnGroupEntry setSpawnGroup = _spawnGroups[key]; Texture2D val = null; if (!string.IsNullOrEmpty(setManifest.CardBackTexturePath)) { val = LoadTexture(Path.Combine("Shared", setManifest.CardBackTexturePath)); if ((Object)(object)val == (Object)null) { _logger.LogWarning((object)("Card back texture not found for set '" + setEntry.Key + "'.")); } } _logger.LogInfo((object)$"Loading set '{setEntry.Key}' ({setManifest.Cards.Count} cards)."); foreach (CardEntry card in setManifest.Cards) { RegisterCard(setEntry.Key, card, val, setSpawnGroup, setManifest.Number); } foreach (PackEntry pack in setManifest.Packs) { RegisterPack(setEntry.Key, pack, setSpawnGroup); } } private void RegisterCard(string setKey, CardEntry cardEntry, Texture2D cardBackTexture, SpawnGroupEntry setSpawnGroup, int totalInSet) { if (!_rarities.TryGetValue(cardEntry.Rarity, out var value)) { _logger.LogWarning((object)("Card '" + cardEntry.Name + "' has unknown rarity '" + cardEntry.Rarity + "', skipping.")); return; } cardEntry.SpawnGroup = ResolveSpawnGroup(cardEntry.SpawnGroup, cardEntry.Rarity); Dictionary<string, double> moonSpawnWeights = BuildMoonSpawnWeights(cardEntry.SpawnGroup, value.SpawnWeight, setSpawnGroup); Texture2D val = LoadTexture(Path.Combine(setKey, "Cards", cardEntry.ItemTexturePath)); Item item = CreateCardItem(cardEntry, val, totalInSet); int num = (int)(cardEntry.ValueMultiplier * (double)value.Value); int maxValue = (int)(1.5 * (double)num); ModCardDatabase.CardInfo card = new ModCardDatabase.CardInfo { SetKey = setKey, Number = cardEntry.Number, Name = cardEntry.Name, Rarity = cardEntry.Rarity, Enabled = cardEntry.Enabled, Metallic = cardEntry.Metallic, MinValue = num, MaxValue = maxValue, ItemTexture = val, CardBackTexture = cardBackTexture, Item = item, MoonSpawnWeights = moonSpawnWeights }; ModCardDatabase.RegisterCard(setKey, card); } private void RegisterPack(string setKey, PackEntry packEntry, SpawnGroupEntry setSpawnGroup) { Texture2D val = LoadTexture(Path.Combine("Shared", packEntry.ItemTexturePath)); Item item = CreateCardPackItem(packEntry, val); packEntry.SpawnGroup = ResolveSpawnGroup(packEntry.SpawnGroup); Dictionary<string, double> moonSpawnWeights = BuildMoonSpawnWeights(packEntry.SpawnGroup, 1, setSpawnGroup); ModCardDatabase.PackInfo pack = new ModCardDatabase.PackInfo { SetKey = setKey, Key = packEntry.Key, Name = packEntry.Name, BlacklistedCardIds = packEntry.BlacklistedCardIds, ItemTexture = val, Item = item, MoonSpawnWeights = moonSpawnWeights }; ModCardDatabase.RegisterPack(setKey, pack); } private string ResolveSpawnGroup(string spawnGroup, string rarity = null) { if (!string.IsNullOrEmpty(spawnGroup)) { if (_spawnGroups.ContainsKey(spawnGroup)) { return spawnGroup; } _logger.LogWarning((object)("SpawnGroup '" + spawnGroup + "' not found, falling back.")); } if (rarity != null && _spawnGroups.ContainsKey(rarity)) { return rarity; } if (_spawnGroups.ContainsKey("Default")) { return "Default"; } _logger.LogWarning((object)"No resolvable SpawnGroup."); return null; } private Dictionary<string, double> BuildMoonSpawnWeights(string spawnGroupName, int spawnWeight, SpawnGroupEntry setSpawnGroup) { Dictionary<string, double> dictionary = new Dictionary<string, double>(); if (spawnGroupName == null || !_spawnGroups.TryGetValue(spawnGroupName, out var value)) { return dictionary; } foreach (var (key, num2) in value.MoonWeightOverrides) { if (setSpawnGroup.MoonWeightOverrides.TryGetValue(key, out var value2)) { dictionary[key] = (float)spawnWeight * num2 * value2; } } return dictionary; } private Item CreateCardItem(CardEntry cardEntry, Texture2D texture, int totalInSet) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) Item val = Object.Instantiate<Item>(_cardBaseItem); val.itemName = cardEntry.Name; val.isConductiveMetal = cardEntry.Metallic; val.toolTips = new string[4] { cardEntry.Name ?? "", $"({cardEntry.Number} of {totalInSet})", cardEntry.Rarity ?? "", "Inspect: [Z]" }; if ((Object)(object)texture != (Object)null) { val.itemIcon = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f)); } Items.RegisterItem(val); return val; } private Item CreateCardPackItem(PackEntry packEntry, Texture2D texture) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) Item val = Object.Instantiate<Item>(_cardPackBaseItem); val.itemName = packEntry.Name; val.isConductiveMetal = true; if ((Object)(object)texture != (Object)null) { val.itemIcon = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f)); } Items.RegisterItem(val); return val; } private Texture2D LoadTexture(string relativePath) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown string text = Path.Combine(_contentDir, relativePath); if (!File.Exists(text)) { Plugin.logger.LogWarning((object)("Card texture not found at: " + text)); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, array); return val; } private T LoadJson<T>(string path) where T : class { if (!File.Exists(path)) { _logger.LogError((object)("JSON file not found: " + path)); return null; } try { T val = JsonConvert.DeserializeObject<T>(File.ReadAllText(path)); if (val == null) { _logger.LogError((object)("Deserialization returned null for " + typeof(T).Name + " from " + path)); } return val; } catch (Exception arg) { _logger.LogError((object)$"Failed to deserialize {path} into {typeof(T).Name}: {arg}"); return null; } } } public static class CollectionTracker { private static string _saveFilePath; private static bool _initialised; private static ManualLogSource Log => Plugin.logger; public static void Initialise() { if (_initialised) { Log.LogWarning((object)"[CollectionTracker] Already initialised — skipping."); return; } string text = GameNetworkManager.Instance?.currentSaveFileName; if (string.IsNullOrWhiteSpace(text)) { Log.LogError((object)"[CollectionTracker] Could not retrieve save file name — collection tracking unavailable."); return; } _saveFilePath = text + "_LethalCardLoader.es3"; _initialised = true; Log.LogInfo((object)("[CollectionTracker] Initialised — save file: " + _saveFilePath)); } public static int GetOwned(int cardId) { return Object.FindObjectsOfType<BaseCardProp>().Count((BaseCardProp c) => c.TemplateId == cardId && ((GrabbableObject)c).isInShipRoom); } public static int GetSold(int cardId) { return ES3.Load<int>($"sold_{cardId}", _saveFilePath, 0); } public static void IncrementSold(int cardId) { int sold = GetSold(cardId); ES3.Save<int>($"sold_{cardId}", sold + 1, _saveFilePath); Log.LogInfo((object)$"[CollectionTracker] Card {cardId} Sold → {sold + 1}"); } public static (int owned, int sold) GetTotalsForSet(IEnumerable<int> cardIds) { int num = 0; int num2 = 0; foreach (int cardId in cardIds) { num += ((GetOwned(cardId) > 0) ? 1 : 0); num2 += GetSold(cardId); } return (num, num2); } } public static class ModCardDatabase { public class CardInfo { public int Id; public string SetKey; public int Number; public string Name; public string Rarity; public Dictionary<string, double> MoonSpawnWeights; public int MinValue; public int MaxValue; public bool Metallic; public Texture2D ItemTexture; public Texture2D CardBackTexture; public Item Item; public bool Enabled; } public class PackInfo { public int Id; public string SetKey; public string Key; public string Name; public Dictionary<string, double> MoonSpawnWeights; public List<int> BlacklistedCardIds = new List<int>(); public Texture2D ItemTexture; public Item Item; } public class SetInfo { public string Key; public Dictionary<int, CardInfo> Cards = new Dictionary<int, CardInfo>(); public Dictionary<string, PackInfo> Packs = new Dictionary<string, PackInfo>(); } public class CardLocator { public string SetKey; public int CardNumber; } public class PackLocator { public string SetKey; public string PackKey; } private static readonly Random _rng = new Random(); public static readonly Dictionary<string, SetInfo> Sets = new Dictionary<string, SetInfo>(StringComparer.OrdinalIgnoreCase); public static readonly Dictionary<int, CardLocator> Cards = new Dictionary<int, CardLocator>(); public static readonly Dictionary<int, PackLocator> Packs = new Dictionary<int, PackLocator>(); private static Dictionary<int, Dictionary<int, double>> packSpawnWeights = new Dictionary<int, Dictionary<int, double>>(); private static Dictionary<string, Dictionary<int, double>> moonCardSpawnWeights = new Dictionary<string, Dictionary<int, double>>(StringComparer.OrdinalIgnoreCase); private static Dictionary<string, Dictionary<int, double>> moonPackSpawnWeights = new Dictionary<string, Dictionary<int, double>>(StringComparer.OrdinalIgnoreCase); public static void RegisterCard(string setKey, CardInfo card) { if (!Sets.TryGetValue(setKey, out var value)) { Plugin.logger.LogInfo((object)("Registering new set '" + setKey + "'.")); value = new SetInfo { Key = setKey }; Sets[setKey] = value; } card.Id = Cards.Count + 1; Cards[card.Id] = new CardLocator { CardNumber = card.Number, SetKey = setKey }; value.Cards[card.Number] = card; } public static void RegisterPack(string setKey, PackInfo pack) { if (!Sets.TryGetValue(setKey, out var value)) { Plugin.logger.LogInfo((object)("Registering new set '" + setKey + "'.")); value = new SetInfo { Key = setKey }; Sets[setKey] = value; } pack.Id = Packs.Count + 1; Packs[pack.Id] = new PackLocator { PackKey = pack.Key, SetKey = setKey }; value.Packs[pack.Key] = pack; } public static void CalculateMoonSpawnWeightsForCards() { moonCardSpawnWeights.Clear(); foreach (CardLocator value2 in Cards.Values) { CardInfo cardInfo = Sets[value2.SetKey].Cards[value2.CardNumber]; if (!cardInfo.Enabled) { continue; } foreach (var (key, num2) in cardInfo.MoonSpawnWeights) { if (!(num2 <= 0.0)) { if (!moonCardSpawnWeights.TryGetValue(key, out var value)) { value = new Dictionary<int, double>(); moonCardSpawnWeights[key] = value; } value[cardInfo.Id] = num2; } } } Plugin.logger.LogInfo((object)$"Moon spawn weights calculated: {moonCardSpawnWeights.Count} moons, {Cards.Count} cards registered."); } public static void CalculateMoonSpawnWeightsForPacks() { moonPackSpawnWeights.Clear(); foreach (PackLocator value2 in Packs.Values) { PackInfo packInfo = Sets[value2.SetKey].Packs[value2.PackKey]; foreach (var (key, num2) in packInfo.MoonSpawnWeights) { if (!(num2 <= 0.0)) { if (!moonPackSpawnWeights.TryGetValue(key, out var value)) { value = new Dictionary<int, double>(); moonPackSpawnWeights[key] = value; } value[packInfo.Id] = num2; } } } Plugin.logger.LogInfo((object)$"Moon spawn weights calculated: {moonPackSpawnWeights.Count} moons, {Packs.Count} packs registered."); } public static void CalculatePackDropRates(Dictionary<string, RarityEntry> rarities) { packSpawnWeights.Clear(); foreach (PackLocator value2 in Packs.Values) { SetInfo setInfo = Sets[value2.SetKey]; PackInfo packInfo = setInfo.Packs[value2.PackKey]; Dictionary<int, double> dictionary = new Dictionary<int, double>(); foreach (CardInfo value3 in setInfo.Cards.Values) { if (value3.Enabled && !packInfo.BlacklistedCardIds.Contains(value3.Number) && rarities.TryGetValue(value3.Rarity ?? "", out var value) && value.CardPackWeight > 0) { dictionary[value3.Id] = value.CardPackWeight; } } packSpawnWeights[packInfo.Id] = dictionary; Plugin.logger.LogInfo((object)$"Pack '{packInfo.Key}': {dictionary.Count} eligible cards."); } } public static CardInfo RetrieveCardById(int cardId) { if (!Cards.TryGetValue(cardId, out var value)) { Plugin.logger.LogWarning((object)$"No card registered with id {cardId}"); return null; } return Sets[value.SetKey].Cards[value.CardNumber]; } public static SetInfo RetrieveSetByCardId(int cardId) { if (!Cards.TryGetValue(cardId, out var value)) { Plugin.logger.LogWarning((object)$"No card registered with id {cardId}"); return null; } return Sets[value.SetKey]; } public static PackInfo RetrievePackById(int packId) { if (!Packs.TryGetValue(packId, out var value)) { Plugin.logger.LogWarning((object)$"No pack registered with id {packId}"); return null; } return Sets[value.SetKey].Packs[value.PackKey]; } public static SetInfo RetrieveSetByPackId(int packId) { if (!Packs.TryGetValue(packId, out var value)) { Plugin.logger.LogWarning((object)$"No pack registered with id {packId}"); return null; } return Sets[value.SetKey]; } private static TKey WeightedRandom<TKey>(Dictionary<TKey, double> pool) { double num = pool.Values.Sum(); double num2 = _rng.NextDouble() * num; double num3 = 0.0; foreach (KeyValuePair<TKey, double> item in pool) { item.Deconstruct(out var key, out var value); TKey result = key; double num4 = value; num3 += num4; if (num2 < num3) { return result; } } return pool.Keys.Last(); } public static CardInfo SelectCardForMoon(string moonName) { string value; string key = (ConfigManager.LevelNamesMap.TryGetValue(moonName, out value) ? value : moonName); if (!moonCardSpawnWeights.TryGetValue(key, out var value2)) { Plugin.logger.LogWarning((object)("No spawn pool found for moon '" + moonName + "'.")); return null; } if (value2.Count == 0) { Plugin.logger.LogWarning((object)("Spawn pool for moon '" + moonName + "' is empty.")); return null; } return RetrieveCardById(WeightedRandom(value2)); } public static CardInfo SelectCardForPack(int packId) { if (!packSpawnWeights.TryGetValue(packId, out var value) || value.Count == 0) { Plugin.logger.LogWarning((object)$"No spawn pool for pack id {packId}."); return null; } return RetrieveCardById(WeightedRandom(value)); } public static PackInfo SelectPackForMoon(string moonName) { string value; string key = (ConfigManager.LevelNamesMap.TryGetValue(moonName, out value) ? value : moonName); if (!moonPackSpawnWeights.TryGetValue(key, out var value2)) { Plugin.logger.LogWarning((object)("No pack spawn pool found for moon '" + moonName + "'.")); return null; } if (value2.Count == 0) { Plugin.logger.LogWarning((object)("Spawn pool for moon '" + moonName + "' is empty.")); return null; } return RetrievePackById(WeightedRandom(value2)); } } } namespace LethalCardLoader.Models { public class SetManifest { public int Id { get; set; } public string Key { get; set; } public string Name { get; set; } public int Number { get; set; } public int CardSpawnWeight { get; set; } public string CardBackTexturePath { get; set; } public List<PackEntry> Packs { get; set; } public List<CardEntry> Cards { get; set; } } public class PackEntry { public string Key { get; set; } public string Name { get; set; } public List<int> BlacklistedCardIds { get; set; } = new List<int>(); public string ItemTexturePath { get; set; } public string SpawnGroup { get; set; } = string.Empty; } public class CardEntry { public int Number { get; set; } public string Name { get; set; } public string ItemTexturePath { get; set; } public string Rarity { get; set; } public bool Enabled { get; set; } = true; public bool Metallic { get; set; } = false; public string SpawnGroup { get; set; } = string.Empty; public double ValueMultiplier { get; set; } = 1.0; } } namespace LethalCardLoader.CustomProps { internal class BaseCardProp : TemplatableProp { public ModCardDatabase.CardInfo CardInfo; public bool hasBeenRecordedInCollection = false; public override void AssignTemplateData() { string planetName = StartOfRound.Instance.currentLevel.PlanetName; CardInfo = ModCardDatabase.SelectCardForMoon(planetName); if (CardInfo == null) { Plugin.logger.LogWarning((object)"No card could be selected for moon, aborting."); return; } ((GrabbableObject)this).SetScrapValue(Random.Range(CardInfo.MinValue, CardInfo.MaxValue)); base.TemplateId = CardInfo.Id; Plugin.logger.LogInfo((object)$"Assigned card '{CardInfo.Name}' (id: {base.TemplateId})"); } public override void ApplyProperties() { if (CardInfo == null) { CardInfo = ModCardDatabase.RetrieveCardById(base.TemplateId); } if (CardInfo == null) { Plugin.logger.LogWarning((object)$"No card found in database for id {base.TemplateId}."); return; } ((GrabbableObject)this).itemProperties = CardInfo.Item; ScanNodeProperties componentInChildren = ((Component)this).GetComponentInChildren<ScanNodeProperties>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.headerText = CardInfo.Name; componentInChildren.subText = $"Value: {((GrabbableObject)this).scrapValue}"; } if ((Object)(object)CardInfo.ItemTexture != (Object)null) { ApplyCardTexture(); } } private void ApplyCardTexture() { Transform val = ((Component)this).transform.Find("CardBase"); if ((Object)(object)val == (Object)null) { Plugin.logger.LogWarning((object)"Could not find 'CardBase' mesh on card."); return; } Renderer component = ((Component)val).GetComponent<Renderer>(); Material[] materials = component.materials; if ((Object)(object)CardInfo.CardBackTexture != (Object)null) { materials[0].mainTexture = (Texture)(object)CardInfo.CardBackTexture; } if ((Object)(object)CardInfo.ItemTexture != (Object)null) { materials[1].mainTexture = (Texture)(object)CardInfo.ItemTexture; } component.materials = materials; } protected override void __initializeVariables() { base.__initializeVariables(); } protected override void __initializeRpcs() { base.__initializeRpcs(); } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "BaseCardProp"; } } internal class BoosterPackProp : TemplatableProp { [CompilerGenerated] private sealed class <SetObjectFallSFX>d__19 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public GrabbableObject gObject; public BoosterPackProp <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SetObjectFallSFX>d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)gObject != (Object)null) { gObject.reachedFloorTarget = false; gObject.hasHitGround = false; gObject.fallTime = 0f; } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForCardOnClient>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public NetworkObjectReference netObjectRef; public int cardValue; public Vector3 spawnPos; public BoosterPackProp <>4__this; private NetworkObject <netObject>5__1; private float <startTime>5__2; private BaseCardProp <card>5__3; private Transform <parent>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForCardOnClient>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <netObject>5__1 = null; <card>5__3 = null; <parent>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <netObject>5__1 = null; <startTime>5__2 = Time.realtimeSinceStartup; goto IL_0062; case 1: <>1__state = -1; goto IL_0062; case 2: { <>1__state = -1; <card>5__3 = ((Component)<netObject>5__1).GetComponent<BaseCardProp>(); if ((Object)(object)<card>5__3 == (Object)null) { return false; } <card>5__3.ApplyProperties(); RoundManager instance = RoundManager.Instance; instance.totalScrapValueInLevel -= (float)((GrabbableObject)<>4__this).scrapValue; RoundManager instance2 = RoundManager.Instance; instance2.totalScrapValueInLevel += (float)cardValue; <parent>5__4 = <>4__this.GetParentOfGiftObject(); ((Component)<card>5__3).transform.SetParent(<parent>5__4, true); ((GrabbableObject)<card>5__3).startFallingPosition = (((Object)(object)<parent>5__4 != (Object)null) ? <parent>5__4.InverseTransformPoint(spawnPos) : spawnPos); ((GrabbableObject)<card>5__3).targetFloorPosition = (((Object)(object)((Component)<card>5__3).transform.parent != (Object)null) ? ((Component)<card>5__3).transform.parent.InverseTransformPoint(((GrabbableObject)<card>5__3).GetItemFloorPosition(spawnPos)) : ((GrabbableObject)<card>5__3).GetItemFloorPosition(spawnPos)); ((GrabbableObject)<card>5__3).fallTime = 0f; ((GrabbableObject)<card>5__3).hasHitGround = false; ((GrabbableObject)<card>5__3).reachedFloorTarget = false; if ((Object)(object)<>4__this._previousPlayerHeldBy != (Object)null && <>4__this._previousPlayerHeldBy.isInHangarShipRoom) { <>4__this._previousPlayerHeldBy.SetItemInElevator(true, true, (GrabbableObject)(object)<card>5__3); } return false; } IL_0062: if (Time.realtimeSinceStartup - <startTime>5__2 < 8f && !((NetworkObjectReference)(ref netObjectRef)).TryGet(ref <netObject>5__1, (NetworkManager)null)) { <>2__current = (object)new WaitForSeconds(0.03f); <>1__state = 1; return true; } if ((Object)(object)<netObject>5__1 == (Object)null) { Plugin.logger.LogWarning((object)"BoosterPack: card NetworkObject not found on client."); return false; } <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public ParticleSystem PoofParticle; public AudioSource presentAudio; public AudioClip openGiftAudio; private PlayerControllerB _previousPlayerHeldBy; private bool _hasOpened; public ModCardDatabase.PackInfo PackInfo { get; private set; } public override void AssignTemplateData() { string planetName = StartOfRound.Instance.currentLevel.PlanetName; PackInfo = ModCardDatabase.SelectPackForMoon(planetName); if (PackInfo == null) { Plugin.logger.LogWarning((object)"No pack could be selected for moon, aborting."); return; } base.TemplateId = PackInfo.Id; Plugin.logger.LogInfo((object)$"Assigned pack '{PackInfo.Name}' (id: {base.TemplateId})"); } public override void ApplyProperties() { if (PackInfo == null) { PackInfo = ModCardDatabase.RetrievePackById(base.TemplateId); } if (PackInfo == null) { Plugin.logger.LogWarning((object)$"No pack found in database for id {base.TemplateId}."); return; } ((GrabbableObject)this).itemProperties = PackInfo.Item; ScanNodeProperties componentInChildren = ((Component)this).GetComponentInChildren<ScanNodeProperties>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.headerText = PackInfo.Name; componentInChildren.subText = $"Value: {((GrabbableObject)this).scrapValue}"; } if ((Object)(object)PackInfo.ItemTexture != (Object)null) { ApplyPackTexture(); } } private void ApplyPackTexture() { Transform val = ((Component)this).transform.Find("CardPackBase"); if ((Object)(object)val == (Object)null) { Plugin.logger.LogWarning((object)"Could not find 'CardPackBase' mesh on pack."); return; } Renderer component = ((Component)val).GetComponent<Renderer>(); Material[] materials = component.materials; if ((Object)(object)PackInfo.ItemTexture != (Object)null) { materials[0].mainTexture = (Texture)(object)PackInfo.ItemTexture; } component.materials = materials; } public override void EquipItem() { ((PhysicsProp)this).EquipItem(); _previousPlayerHeldBy = ((GrabbableObject)this).playerHeldBy; } public override void PocketItem() { ((GrabbableObject)this).PocketItem(); if ((Object)(object)((GrabbableObject)this).playerHeldBy != (Object)null) { ((GrabbableObject)this).playerHeldBy.activatingItem = false; } } public override void ItemActivate(bool used, bool buttonDown = true) { ((GrabbableObject)this).ItemActivate(used, buttonDown); if (!((Object)(object)((GrabbableObject)this).playerHeldBy == (Object)null) && !_hasOpened) { _hasOpened = true; ((GrabbableObject)this).playerHeldBy.activatingItem = true; OpenBoosterServerRpc(); } } [ServerRpc(RequireOwnership = false)] public void OpenBoosterServerRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val = default(ServerRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(2302076414u, val, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendServerRpc(ref val2, 2302076414u, val, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost)) { return; } ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!((NetworkBehaviour)this).IsServer) { return; } ModCardDatabase.CardInfo cardInfo = ModCardDatabase.SelectCardForPack(base.TemplateId); if (cardInfo == null) { Plugin.logger.LogWarning((object)("Pack '" + PackInfo?.Name + "' could not select a card.")); OpenBoosterClientRpc(default(NetworkObjectReference), 0, ((Component)this).transform.position); return; } int num = Random.Range(cardInfo.MinValue, cardInfo.MaxValue); Vector3 val3 = ((Component)this).transform.position + Vector3.up * 0.25f; Transform parentOfGiftObject = GetParentOfGiftObject(); GameObject val4 = Object.Instantiate<GameObject>(cardInfo.Item.spawnPrefab, val3, Quaternion.identity, parentOfGiftObject); BaseCardProp component = val4.GetComponent<BaseCardProp>(); if ((Object)(object)component != (Object)null) { ((GrabbableObject)component).SetScrapValue(num); component.CardInfo = cardInfo; component.TemplateId = cardInfo.Id; } NetworkObject component2 = val4.GetComponent<NetworkObject>(); if ((Object)(object)component2 != (Object)null) { component2.Spawn(false); ((MonoBehaviour)this).StartCoroutine(SetObjectFallSFX((GrabbableObject)(object)component)); OpenBoosterClientRpc(new NetworkObjectReference(component2), num, val3); } else { Plugin.logger.LogWarning((object)"Spawned card has no NetworkObject."); OpenBoosterClientRpc(default(NetworkObjectReference), 0, val3); } } [ClientRpc] public void OpenBoosterClientRpc(NetworkObjectReference netObjectRef, int cardValue, Vector3 spawnPos) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(2979095893u, val, (RpcDelivery)0); ((FastBufferWriter)(ref val2)).WriteValueSafe<NetworkObjectReference>(ref netObjectRef, default(ForNetworkSerializable)); BytePacker.WriteValueBitPacked(val2, cardValue); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref spawnPos); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 2979095893u, val, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; PlayOpenEffects(); if ((Object)(object)((GrabbableObject)this).playerHeldBy != (Object)null) { ((GrabbableObject)this).playerHeldBy.activatingItem = false; ((GrabbableObject)this).DestroyObjectInHand(((GrabbableObject)this).playerHeldBy); } if (!((NetworkBehaviour)this).IsServer) { ((MonoBehaviour)this).StartCoroutine(WaitForCardOnClient(netObjectRef, cardValue, spawnPos)); } } } [IteratorStateMachine(typeof(<WaitForCardOnClient>d__17))] private IEnumerator WaitForCardOnClient(NetworkObjectReference netObjectRef, int cardValue, Vector3 spawnPos) { //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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForCardOnClient>d__17(0) { <>4__this = this, netObjectRef = netObjectRef, cardValue = cardValue, spawnPos = spawnPos }; } private void PlayOpenEffects() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)PoofParticle != (Object)null) { PoofParticle.Play(); } if ((Object)(object)presentAudio != (Object)null && (Object)(object)openGiftAudio != (Object)null) { presentAudio.PlayOneShot(openGiftAudio); WalkieTalkie.TransmitOneShotAudio(presentAudio, openGiftAudio, 1f); RoundManager.Instance.PlayAudibleNoise(((Component)presentAudio).transform.position, 8f, 0.5f, 0, ((GrabbableObject)this).isInShipRoom && StartOfRound.Instance.hangarDoorsClosed, 0); } } [IteratorStateMachine(typeof(<SetObjectFallSFX>d__19))] private IEnumerator SetObjectFallSFX(GrabbableObject gObject) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SetObjectFallSFX>d__19(0) { <>4__this = this, gObject = gObject }; } private Transform GetParentOfGiftObject() { if (((Object)(object)_previousPlayerHeldBy != (Object)null && _previousPlayerHeldBy.isInElevator) || StartOfRound.Instance.inShipPhase) { return StartOfRound.Instance.elevatorTransform; } return null; } protected override void __initializeVariables() { base.__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(2302076414u, new RpcReceiveHandler(__rpc_handler_2302076414), "OpenBoosterServerRpc"); ((NetworkBehaviour)this).__registerRpc(2979095893u, new RpcReceiveHandler(__rpc_handler_2979095893), "OpenBoosterClientRpc"); base.__initializeRpcs(); } private static void __rpc_handler_2302076414(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((BoosterPackProp)(object)target).OpenBoosterServerRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2979095893(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { NetworkObjectReference netObjectRef = default(NetworkObjectReference); ((FastBufferReader)(ref reader)).ReadValueSafe<NetworkObjectReference>(ref netObjectRef, default(ForNetworkSerializable)); int cardValue = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref cardValue); Vector3 spawnPos = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref spawnPos); target.__rpc_exec_stage = (__RpcExecStage)1; ((BoosterPackProp)(object)target).OpenBoosterClientRpc(netObjectRef, cardValue, spawnPos); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "BoosterPackProp"; } } internal abstract class TemplatableProp : PhysicsProp { public bool isSynced = false; public bool isLoaded = false; public int TemplateId { get; set; } public abstract void AssignTemplateData(); public abstract void ApplyProperties(); public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); if (((NetworkBehaviour)this).IsServer) { if (TemplateId == 0) { AssignTemplateData(); } SyncDataClientRpc(TemplateId, ((GrabbableObject)this).scrapValue); } } [ClientRpc] public void SyncDataClientRpc(int id, int value) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(796621470u, val, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val2, id); BytePacker.WriteValueBitPacked(val2, value); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 796621470u, val, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; ((GrabbableObject)this).SetScrapValue(value); TemplateId = id; if (TemplateId >= 0) { ApplyProperties(); } } } public override int GetItemDataToSave() { return TemplateId; } public override void LoadItemSaveData(int saveData) { if (saveData > 0) { TemplateId = saveData; isLoaded = true; if (((NetworkBehaviour)this).IsServer) { isSynced = true; } ApplyProperties(); } } protected override void __initializeVariables() { ((PhysicsProp)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(796621470u, new RpcReceiveHandler(__rpc_handler_796621470), "SyncDataClientRpc"); ((PhysicsProp)this).__initializeRpcs(); } private static void __rpc_handler_796621470(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int id = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref id); int value = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref value); target.__rpc_exec_stage = (__RpcExecStage)1; ((TemplatableProp)(object)target).SyncDataClientRpc(id, value); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "TemplatableProp"; } } } namespace LethalCardLoader.Config { public static class ConfigManager { public static List<MoonEntry> Moons = new List<MoonEntry>(); public static List<SetEntry> Sets = new List<SetEntry>(); public static List<SpawnGroupEntry> SpawnGroups = new List<SpawnGroupEntry>(); public static List<RarityEntry> RarityConfigs = new List<RarityEntry>(); private static Dictionary<string, string> _levelNamesMap = new Dictionary<string, string>(); private static bool _moonsLoaded = false; private static bool _setsLoaded = false; private static bool _spawnGroupsLoaded = false; private static bool _raritiesLoaded = false; private static bool _missingMoonsCreated = false; public static Dictionary<string, string> LevelNamesMap => _levelNamesMap; public static void LoadMoonConfigs() { if (_moonsLoaded) { Plugin.logger.LogWarning((object)"[ConfigManager] LoadMoonConfigs called more than once — skipping."); return; } _moonsLoaded = true; List<string> headerValues = GetHeaderValues("Moon"); foreach (string item in headerValues) { MoonEntry moonEntry = new MoonEntry(); moonEntry.Bind(item, string.Empty); Moons.Add(moonEntry); if (string.IsNullOrWhiteSpace(moonEntry.InternalName)) { Plugin.logger.LogWarning((object)("[ConfigManager] Moon '" + item + "' has no Internal Name — it will be populated on next game load.")); } } RebuildLevelNamesMap(); } public static void CreateDefaults() { new RarityEntry().Bind("Common", 30, 80, 70); new RarityEntry().Bind("Uncommon", 50, 15, 20); new RarityEntry().Bind("Rare", 80, 5, 10); new SpawnGroupEntry().Bind("Default", Moons); } public static void LoadSetConfigs() { if (_setsLoaded) { Plugin.logger.LogWarning((object)"[ConfigManager] LoadSetConfigs called more than once — skipping."); return; } _setsLoaded = true; List<string> headerValues = GetHeaderValues("Set"); foreach (string item in headerValues) { SetEntry setEntry = new SetEntry(); setEntry.Bind(item, Sets.Count + 1); Sets.Add(setEntry); } } public static void LoadSpawnGroupConfigs() { if (_spawnGroupsLoaded) { Plugin.logger.LogWarning((object)"[ConfigManager] LoadSpawnGroupConfigs called more than once — skipping."); return; } _spawnGroupsLoaded = true; List<string> headerValues = GetHeaderValues("Spawn Group"); foreach (string item in headerValues) { SpawnGroupEntry spawnGroupEntry = new SpawnGroupEntry(); spawnGroupEntry.Bind(item, Moons); SpawnGroups.Add(spawnGroupEntry); } } public static void LoadRarityConfigs() { if (_raritiesLoaded) { Plugin.logger.LogWarning((object)"[ConfigManager] LoadRarityConfigs called more than once — skipping."); return; } _raritiesLoaded = true; List<string> headerValues = GetHeaderValues("Rarity"); foreach (string item in headerValues) { RarityEntry rarityEntry = new RarityEntry(); rarityEntry.Bind(item); RarityConfigs.Add(rarityEntry); Plugin.logger.LogInfo((object)("[ConfigManager] Loaded rarity: " + item)); } Plugin.logger.LogInfo((object)$"[ConfigManager] Loaded {RarityConfigs.Count} rarity/rarities."); } private static void RebuildLevelNamesMap() { _levelNamesMap = Moons.ToDictionary((MoonEntry a) => a.PlanetName, (MoonEntry a) => a.InternalName); } public static void CreateMissingMoonConfigs(Dictionary<string, string> levelNameMap) { if (_missingMoonsCreated) { Plugin.logger.LogWarning((object)"[ConfigManager] CreateMissingMoonConfigs called more than once — skipping."); return; } _missingMoonsCreated = true; List<MoonEntry> list = new List<MoonEntry>(); foreach (KeyValuePair<string, string> levelName in levelNameMap) { if (Moons.Any((MoonEntry m) => m.PlanetName == levelName.Key)) { Plugin.logger.LogWarning((object)("[ConfigManager] Moon '" + levelName.Key + "' already exists — skipping.")); continue; } MoonEntry moonEntry = new MoonEntry(); moonEntry.Bind(levelName.Key, levelName.Value); Moons.Add(moonEntry); list.Add(moonEntry); Plugin.logger.LogInfo((object)("[ConfigManager] Registered new moon: " + levelName.Key + " (" + levelName.Value + ")")); } if (list.Count == 0) { return; } foreach (SpawnGroupEntry spawnGroup in SpawnGroups) { spawnGroup.AddMissingMoons(list); } RebuildLevelNamesMap(); } public static List<string> GetHeaderValues(string prefix) { string path = Path.Combine(Paths.ConfigPath, "com.sholiver.lethalcardloader.cfg"); List<string> list = new List<string>(); if (!File.Exists(path)) { Plugin.logger.LogWarning((object)("[ConfigManager] Config file not found when reading " + prefix + " names.")); return list; } foreach (string item in File.ReadLines(path)) { string text = item.Trim(); if (!text.StartsWith("[") || !text.EndsWith("]")) { continue; } string text2 = text.Substring(1, text.Length - 2).Trim(); if (text2.StartsWith(prefix + ":", StringComparison.OrdinalIgnoreCase)) { string text3 = text2.Substring(prefix.Length + 1).Trim(); if (!string.IsNullOrWhiteSpace(text3)) { list.Add(text3); } } } Plugin.logger.LogInfo((object)$"[ConfigManager] Found {list.Count} existing {prefix}(s) in config."); return list; } } public class MoonEntry { private ConfigEntry<string> _planetName; private ConfigEntry<string> _internalName; private ConfigEntry<int> _cardScrapRarity; private ConfigEntry<int> _packScrapRarity; public string PlanetName => _planetName.Value; public string InternalName => _internalName.Value; public int CardScrapRarity => _cardScrapRarity.Value; public int PackScrapRarity => _packScrapRarity.Value; public void Bind(string planetName, string internalName, int cardRarity = 100, int packRarity = 100) { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; string text = "Moon: " + planetName; _planetName = config.Bind<string>(text, "Planet Name", planetName, "Auto-managed — do not edit manually."); _internalName = config.Bind<string>(text, "Internal Name", internalName, "Auto-managed — do not edit manually."); _cardScrapRarity = config.Bind<int>(text, "Card Scrap Rarity", cardRarity, "Rarity of card scrap spawning on this moon (0-100)."); _packScrapRarity = config.Bind<int>(text, "Pack Scrap Rarity", packRarity, "Rarity of pack scrap spawning on this moon (0-100)."); } } public class RarityEntry { private ConfigEntry<string> _key; private ConfigEntry<int> _value; private ConfigEntry<int> _spawnWeight; private ConfigEntry<int> _cardPackWeight; public string Key => _key.Value; public int Value => _value.Value; public int SpawnWeight => _spawnWeight.Value; public int CardPackWeight => _cardPackWeight.Value; public void Bind(string key, int value = 100, int spawnWeight = 50, int cardPackWeight = 50) { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; string text = "Rarity: " + key; _key = config.Bind<string>(text, "Key", key, "The unique key for this rarity tier."); _value = config.Bind<int>(text, "Value", value, "The scrap value multiplier for this rarity tier."); _spawnWeight = config.Bind<int>(text, "Spawn Weight", spawnWeight, "The relative weight of this rarity tier when spawning scrap."); _cardPackWeight = config.Bind<int>(text, "Card Pack Weight", cardPackWeight, "The relative weight of this rarity tier when opening a card pack."); } } public class SetEntry { private ConfigEntry<string> _name; private ConfigEntry<string> _key; private ConfigEntry<int> _id; private ConfigEntry<string> _spawnGroup; public string Name => _name.Value; public string Key => _key.Value; public int Id => _id.Value; public string SpawnGroup => _spawnGroup.Value; public void Bind(string name, int id, string key = "", string spawnGroup = "Default") { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; string text = "Set: " + name; _name = config.Bind<string>(text, "Name", name, "The display name of this set."); _key = config.Bind<string>(text, "Key", string.IsNullOrEmpty(key) ? name.Replace(" ", "") : key, "Used to derive the manifest filename (e.g. \"BaseSet\" → \"BaseSet.json\")."); _id = config.Bind<int>(text, "Id", id, "Unique numeric identifier for this set."); _spawnGroup = config.Bind<string>(text, "Spawn Group", spawnGroup, "The spawn group this set belongs to."); } } public class SpawnGroupEntry { private ConfigEntry<string> _key; private List<ConfigEntry<float>> _moonWeights = new List<ConfigEntry<float>>(); private Dictionary<string, float> _moonWeightOverrides = new Dictionary<string, float>(); public string Key => _key.Value; public Dictionary<string, float> MoonWeightOverrides => _moonWeightOverrides; public void Bind(string key, List<MoonEntry> moons) { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; string text = "Spawn Group: " + key; _key = config.Bind<string>(text, "Key", key, "The unique key for this spawn group."); foreach (MoonEntry moon in moons) { _moonWeights.Add(config.Bind<float>(text, moon.InternalName, 1f, "Weight multiplier for this moon. (0.0 = never spawns, 1.0 = normal weight)")); } RebuildMoonWeightOverrides(); } public void AddMissingMoons(List<MoonEntry> newMoons) { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; string text = "Spawn Group: " + Key; foreach (MoonEntry moon in newMoons) { if (string.IsNullOrWhiteSpace(moon.InternalName)) { Plugin.logger.LogWarning((object)("[SpawnGroupEntry] Skipping moon '" + moon.PlanetName + "' — InternalName is empty.")); } else if (!_moonWeights.Any((ConfigEntry<float> e) => ((ConfigEntryBase)e).Definition.Key == moon.InternalName)) { _moonWeights.Add(config.Bind<float>(text, moon.InternalName, 1f, "Weight multiplier for this moon. (0.0 = never spawns, 1.0 = normal weight)")); } } RebuildMoonWeightOverrides(); } private void RebuildMoonWeightOverrides() { _moonWeightOverrides = _moonWeights.ToDictionary((ConfigEntry<float> e) => ((ConfigEntryBase)e).Definition.Key, (ConfigEntry<float> e) => e.Value); } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { } } } namespace LethalCardLoader.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }