diff --git a/LethalLevelLoader/Components/LLLSaveFile.cs b/LethalLevelLoader/Components/LLLSaveFile.cs index 4b32e7b..1d0e845 100644 --- a/LethalLevelLoader/Components/LLLSaveFile.cs +++ b/LethalLevelLoader/Components/LLLSaveFile.cs @@ -9,32 +9,45 @@ public class LLLSaveFile : ModDataContainer { public string CurrentLevelName { get; internal set; } = string.Empty; - public Dictionary customItemDictionary = new Dictionary(); - - public List allItemsList = new List(); - - public List itemSaveDataList = new List(); + public int parityStepsTaken; public Dictionary itemSaveData = new Dictionary(); - public LLLSaveFile(string name) + public LLLSaveFile() + { + //OptionalPrefixSuffix = name; + } + + public void Reset() { - OptionalPrefixSuffix = name; + CurrentLevelName = string.Empty; + parityStepsTaken = 0; + itemSaveData = new Dictionary(); } } public struct AllItemsListItemData { + public string itemObjectName; public string itemName; - public string itemDisplayName; public string modName; + public string modAuthor; public int allItemsListIndex; + public int modItemsListIndex; + public int itemNameDuplicateIndex; + public bool isScrap; + public bool saveItemVariable; - public AllItemsListItemData(string newItemName, string newItemDisplayName, string newModName, int newAllItemsListIndex) + public AllItemsListItemData(string newItemObjectName, string newItemName, string newModName, string newModAuthor, int newAllItemsListIndex, int newModItemsListIndex, int newItemNameDuplicateIndex, bool newIsScrap, bool newSaveItemVariable) { + itemObjectName = newItemObjectName; itemName = newItemName; - itemDisplayName = newItemDisplayName; modName = newModName; + modAuthor = newModAuthor; allItemsListIndex = newAllItemsListIndex; + modItemsListIndex = newModItemsListIndex; + itemNameDuplicateIndex = newItemNameDuplicateIndex; + isScrap = newIsScrap; + saveItemVariable = newSaveItemVariable; } } } diff --git a/LethalLevelLoader/General/Patches.cs b/LethalLevelLoader/General/Patches.cs index 4dbb2c9..2b78d2f 100644 --- a/LethalLevelLoader/General/Patches.cs +++ b/LethalLevelLoader/General/Patches.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Reflection.Emit; using System.Text; using TMPro; @@ -132,6 +133,18 @@ internal static void GameNetworkManagerStart_Prefix(GameNetworkManager __instanc } } + [HarmonyPriority(harmonyPriority)] + [HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")] + [HarmonyPostfix] + internal static void GameNetworkManagerSaveGameValues_Postfix(GameNetworkManager __instance) + { + // Vanilla checks + if (!__instance.isHostingGame || !StartOfRound.Instance.inShipPhase || StartOfRound.Instance.isChallengeFile) + return; + + SaveManager.SaveGameValues(); + } + [HarmonyPriority(harmonyPriority)] [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] @@ -151,12 +164,10 @@ internal static void StartOfRoundAwake_Prefix(StartOfRound __instance) SceneManager.sceneLoaded += EventPatches.OnSceneLoaded; //Removing the broken cardboard box item please understand - //Scrape Vanilla For Content References if (Plugin.IsSetupComplete == false) { StartOfRound.allItemsList.itemsList.RemoveAt(2); - SaveManager.defaultCachedItemsList = new List(StartOfRound.allItemsList.itemsList); DebugStopwatch.StartStopWatch("Scrape Vanilla Content"); ContentExtractor.TryScrapeVanillaItems(StartOfRound); @@ -308,7 +319,6 @@ internal static void StartOfRoundAwake_Prefix(StartOfRound __instance) if (LethalLevelLoaderNetworkManager.networkManager.IsServer) { SaveManager.InitializeSave(); - SaveManager.RefreshSaveItemInfo(); } DebugStopwatch.StopStopWatch("Initalize Save"); @@ -385,7 +395,8 @@ public static void StartOfRoundChangeLevel_Postfix(int levelID) if (RoundManager.currentLevel != null && SaveManager.currentSaveFile.CurrentLevelName != RoundManager.currentLevel.PlanetName) { DebugHelper.Log("Saving Current SelectableLevel: " + RoundManager.currentLevel.PlanetName, DebugType.User); - SaveManager.SaveCurrentSelectableLevel(RoundManager.currentLevel); + SaveManager.currentSaveFile.CurrentLevelName = RoundManager.currentLevel.PlanetName; + //SaveManager.SaveCurrentSelectableLevel(RoundManager.currentLevel); //LevelLoader.RefreshShipAnimatorClips(LevelManager.CurrentExtendedLevel); } @@ -394,11 +405,9 @@ public static void StartOfRoundChangeLevel_Postfix(int levelID) [HarmonyPriority(harmonyPriority)] [HarmonyPatch(typeof(StartOfRound), "LoadShipGrabbableItems")] [HarmonyPrefix] - internal static bool StartOfRoundLoadShipGrabbableItems_Prefix() + internal static void StartOfRoundLoadShipGrabbableItems_Prefix() { - //SaveManager.LoadShipGrabbableItems(); - //return (false); - return (true); + SaveManager.LoadShipGrabbableItems(); } diff --git a/LethalLevelLoader/Patches/SaveManager.cs b/LethalLevelLoader/Patches/SaveManager.cs index 5c56375..384ee93 100644 --- a/LethalLevelLoader/Patches/SaveManager.cs +++ b/LethalLevelLoader/Patches/SaveManager.cs @@ -1,28 +1,26 @@ -using System; +using LethalLib.Modules; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using Unity.Netcode; using UnityEngine; -using static LethalLevelLoader.SaveManager; namespace LethalLevelLoader { internal static class SaveManager { public static LLLSaveFile currentSaveFile; - public static List defaultCachedItemsList = new List(); + public static bool parityCheck; internal static void InitializeSave() { if (LethalLevelLoaderNetworkManager.networkManager.IsServer == false) return; - if (GameNetworkManager.Instance.currentSaveFileName.Contains("LC")) - currentSaveFile = new LLLSaveFile(GameNetworkManager.Instance.currentSaveFileName.Replace("LC", "LLL")); - else - currentSaveFile = new LLLSaveFile("LLLSaveFile"); + currentSaveFile = new LLLSaveFile(); currentSaveFile.Load(); + if (currentSaveFile.CurrentLevelName != null) DebugHelper.Log("Initialized LLL Save File, Current Level Was: " + currentSaveFile.CurrentLevelName + ", Current Vanilla Save Is: " + GameNetworkManager.Instance.currentSaveFileName, DebugType.User); else @@ -30,255 +28,367 @@ internal static void InitializeSave() if (ES3.KeyExists("CurrentPlanetID", GameNetworkManager.Instance.currentSaveFileName)) DebugHelper.Log("Vanilla CurrentSaveFileName Has Saved Current Planet ID: " + ES3.Load("CurrentPlanetID", GameNetworkManager.Instance.currentSaveFileName), DebugType.Developer); + + // Compare saved "Steps Taken" statistic, to try to check whether the Vanilla and LethalLevelLoader saves are the same + int originalStepsTaken = ES3.Load("Stats_StepsTaken", GameNetworkManager.Instance.currentSaveFileName, 0); + + if (originalStepsTaken == currentSaveFile.parityStepsTaken) + parityCheck = true; else { - currentSaveFile.customItemDictionary = new Dictionary(); - currentSaveFile.allItemsList = new List(); - currentSaveFile.itemSaveDataList = new List(); - currentSaveFile.itemSaveData = new Dictionary(); - currentSaveFile.CurrentLevelName = string.Empty; - } - - if (currentSaveFile.customItemDictionary == null) - currentSaveFile.customItemDictionary = new Dictionary(); - if (currentSaveFile.allItemsList == null) - currentSaveFile.allItemsList = new List(); - if (currentSaveFile.itemSaveDataList == null) - currentSaveFile.itemSaveDataList = new List(); - if (currentSaveFile.itemSaveData == null) - currentSaveFile.itemSaveData = new Dictionary(); - if (currentSaveFile.CurrentLevelName == null) - currentSaveFile.CurrentLevelName = string.Empty; + DebugHelper.Log("Vanilla Save File Mismatch, LLL Steps Taken: " + currentSaveFile.parityStepsTaken + ", Vanilla Steps Taken: " + originalStepsTaken, DebugType.Developer); - /*foreach (string item in currentSaveFile.allItemsList) - DebugHelper.Log("Saved AllItemsList: " + item); + currentSaveFile.Reset(); + currentSaveFile.parityStepsTaken = originalStepsTaken; - foreach (KeyValuePair extendedItemSaveInfo in currentSaveFile.customItemDictionary) - DebugHelper.Log("Save Item Info: " + extendedItemSaveInfo.Key + " from " + extendedItemSaveInfo.Value);*/ + parityCheck = false; + } + } - //foreach (AllItemsListItemData itemSaveData in currentSaveFile.itemSaveDataList) - //DebugHelper.Log("Item Save Data: " + itemSaveData.itemName + ", " + itemSaveData.itemDisplayName + ", " + itemSaveData.modName + ", " + itemSaveData.allItemsListIndex, DebugType.Developer); + internal static void SaveGameValues() + { + currentSaveFile.itemSaveData = GetAllItemsListItemDataDict(); + currentSaveFile.parityStepsTaken = Patches.StartOfRound.gameStats.allStepsTaken; + currentSaveFile.Save(); + } - //ValidateSaveData(); + internal static void SaveCurrentSelectableLevel(SelectableLevel selectableLevel) + { + /* + if (LethalLevelLoaderNetworkManager.networkManager.IsServer == false) + return; + currentSaveFile.CurrentLevelName = selectableLevel.name; + currentSaveFile.Save(); + */ } - internal static ProcessedData ValidateSaveData() + internal static void LoadShipGrabbableItems() { - List savedAllItemsListIndices = null; - if (ES3.KeyExists("shipGrabbableItemIDs", GameNetworkManager.Instance.currentSaveFileName)) - savedAllItemsListIndices = ES3.Load("shipGrabbableItemIDs", GameNetworkManager.Instance.currentSaveFileName).ToList(); + if (!parityCheck) + return; + + // TODO: Config option to disable this process preferably - List savedItems = new List(); - List liveItems = GetItemSaveData(); + List loadedShipItemData = GetConstructedSavedShipItemData(currentSaveFile.itemSaveData); + FixMismatchedSavedItemData(loadedShipItemData); + OverrideCurrentSaveFileItemData(loadedShipItemData); + } - List validIndicies = new List(); - Dictionary recoveredIndicies = new Dictionary(); - List invalidIndicies = new List(); + internal static void OverrideCurrentSaveFileItemData(List savedShipItemDatas) + { + List shipGrabbableItemIDs = new List(); + List shipGrabbableItemPos = new List(); + List shipScrapValues = new List(); + List shipItemSaveData = new List(); - if (savedAllItemsListIndices != null) - foreach (int itemIndex in savedAllItemsListIndices) - savedItems.Add(currentSaveFile.itemSaveData[itemIndex]); + string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; - foreach (AllItemsListItemData savedItem in savedItems) + foreach (SavedShipItemData savedShipItemData in savedShipItemDatas) { - if (savedItem.allItemsListIndex < liveItems.Count && savedItem.allItemsListIndex > -1 && liveItems[savedItem.allItemsListIndex].itemName == savedItem.itemName) - validIndicies.Add(savedItem.allItemsListIndex); - else - { - int recoveredItemIndex = -1; - foreach (AllItemsListItemData liveItem in liveItems) - { - int compareCount = 0; - if (savedItem.itemName == liveItem.itemName) - compareCount++; - if (savedItem.itemDisplayName == liveItem.itemDisplayName) - compareCount++; - if (savedItem.modName == liveItem.modName) - compareCount++; - if (compareCount >= 2) - recoveredItemIndex = liveItems.IndexOf(liveItem); - } - if (recoveredItemIndex != -1) - recoveredIndicies.Add(savedItem.allItemsListIndex, recoveredItemIndex); - else - invalidIndicies.Add(savedItem.allItemsListIndex); - } + shipGrabbableItemIDs.Add(savedShipItemData.itemAllItemsListIndex); + shipGrabbableItemPos.Add(savedShipItemData.itemPosition); + if (savedShipItemData.itemScrapValue != -1) + shipScrapValues.Add(savedShipItemData.itemScrapValue); + if (savedShipItemData.itemAdditionalSavedData != -1) + shipItemSaveData.Add(savedShipItemData.itemAdditionalSavedData); } - return (new ProcessedData(validIndicies, recoveredIndicies, invalidIndicies)); - } + if (ES3.KeyExists("shipGrabbableItemIDs", currentSaveFileName)) + ES3.DeleteKey("shipGrabbableItemIDs", currentSaveFileName); + if (ES3.KeyExists("shipGrabbableItemPos", currentSaveFileName)) + ES3.DeleteKey("shipGrabbableItemPos", currentSaveFileName); + if (ES3.KeyExists("shipScrapValues", currentSaveFileName)) + ES3.DeleteKey("shipScrapValues", currentSaveFileName); + if (ES3.KeyExists("shipItemSaveData", currentSaveFileName)) + ES3.DeleteKey("shipItemSaveData", currentSaveFileName); - internal static List ProcessSavedItemIndicies(ProcessedData processedData) - { - return (ProcessSavedItemIndicies(processedData.validIndicies, processedData.recoveredIndicies, processedData.invalidIndicies)); + if (shipGrabbableItemIDs.Count > 0) + ES3.Save("shipGrabbableItemIDs", shipGrabbableItemIDs.ToArray(), currentSaveFileName); + if (shipGrabbableItemPos.Count > 0) + ES3.Save("shipGrabbableItemPos", shipGrabbableItemPos.ToArray(), currentSaveFileName); + if (shipScrapValues.Count > 0) + ES3.Save("shipScrapValues", shipScrapValues.ToArray(), currentSaveFileName); + if (shipItemSaveData.Count > 0) + ES3.Save("shipItemSaveData", shipItemSaveData.ToArray(), currentSaveFileName); } - internal static List ProcessSavedItemIndicies(List validIndices, Dictionary recoveredIndicies, List invalidIndicies) + internal static void FixMismatchedSavedItemData(List savedShipItemDatas) { - AllItemsList patchedItemsList = Patches.StartOfRound.allItemsList; - List validatedSavedShipItemDataList = new List(); - Dictionary constructedSavedShipItemDataDict = GetConstructedSavedShipItemData(); + Dictionary itemDataDict = GetAllItemsListItemDataDict(); - DebugHelper.Log("Processed Saved Items In: " + GameNetworkManager.Instance.currentSaveFileName, DebugType.User); - if (validIndices.Count > 0) - { - string validItemsLog = "Valid Saved Items: "; - foreach (int validIndex in validIndices) - validItemsLog += patchedItemsList.itemsList[validIndex].itemName + ", "; - DebugHelper.Log(validItemsLog, DebugType.User); - } - if (recoveredIndicies.Count > 0) + int firstMismatch = 0; + + foreach (SavedShipItemData savedShipItemData in savedShipItemDatas) { - string recoveredItemsLog = "Recovered Saved Items: "; - foreach (KeyValuePair recoveredIndexPair in recoveredIndicies) - recoveredItemsLog += patchedItemsList.itemsList[recoveredIndexPair.Value].itemName + ", "; - DebugHelper.LogWarning(recoveredItemsLog, DebugType.User); + int allitemsListIndex = savedShipItemData.itemAllItemsListIndex; + if (!itemDataDict.ContainsKey(savedShipItemData.itemAllItemsListIndex)) + break; + + AllItemsListItemData itemData = savedShipItemData.itemAllItemsListData; + AllItemsListItemData newItemData = itemDataDict[allitemsListIndex]; + + if (newItemData.itemName != itemData.itemName) + break; + + firstMismatch++; } - if (invalidIndicies.Count > 0) + + if (firstMismatch >= savedShipItemDatas.Count) + return; + + for (int i = firstMismatch; i < savedShipItemDatas.Count; i++) { - string invalidItemsLog = "Corrupted Saved Items: "; - foreach (int invalidIndex in invalidIndicies) - invalidItemsLog += "Invalid ID: (" + invalidIndex + ")" + ", "; - DebugHelper.LogError(invalidItemsLog, DebugType.User); - } + SavedShipItemData savedShipItemData = savedShipItemDatas[i]; + int oldIndex = savedShipItemData.itemAllItemsListIndex; - foreach (SavedShipItemData savedShipItemData in constructedSavedShipItemDataDict.Values) - DebugHelper.Log("Constructed SavedShipItemData: " + savedShipItemData.itemAllItemsListIndex + " | " + savedShipItemData.itemPosition + " | " + savedShipItemData.itemScrapValue + " | " + savedShipItemData.itemAdditionalSavedData, DebugType.User); + int newIndex = FixAllItemsListIndex(savedShipItemData.itemAllItemsListData, itemDataDict); + savedShipItemData.itemAllItemsListIndex = newIndex; + if (itemDataDict.ContainsKey(newIndex)) + { + AllItemsListItemData newItemData = itemDataDict[newIndex]; - foreach (int validIndex in validIndices) - validatedSavedShipItemDataList.Add(constructedSavedShipItemDataDict[validIndex]); + if (oldIndex != newIndex) + { + DebugHelper.Log($"Fixing Item ┌ {savedShipItemData.itemAllItemsListData.modName} ┬ {savedShipItemData.itemAllItemsListData.itemName} ┬ {savedShipItemData.itemAllItemsListData.itemObjectName} ┬ #{oldIndex}", DebugType.User); + DebugHelper.Log($" -----> └ {newItemData.modName } ┴ {newItemData.itemName } ┴ {newItemData.itemObjectName } ┴ #{newIndex}", DebugType.User); + } - foreach (KeyValuePair recoveredIndex in recoveredIndicies) - { - constructedSavedShipItemDataDict[recoveredIndex.Key].itemAllItemsListIndex = recoveredIndex.Value; - validatedSavedShipItemDataList.Add(constructedSavedShipItemDataDict[recoveredIndex.Key]); - } + savedShipItemData.itemAllItemsListData = newItemData; - validatedSavedShipItemDataList = validatedSavedShipItemDataList.OrderBy(s => s.itemAllItemsListIndex).ToList(); + if (!newItemData.isScrap && savedShipItemData.itemScrapValue >= 0) + savedShipItemData.itemScrapValue = -1; + else if (newItemData.isScrap && savedShipItemData.itemScrapValue == -1) + savedShipItemData.itemScrapValue = 0; // Could generate a fitting scrap value here if desired - foreach (SavedShipItemData savedShipItemData in validatedSavedShipItemDataList) - DebugHelper.Log("Validated SavedShipItemData: " + savedShipItemData.itemAllItemsListIndex + " | " + savedShipItemData.itemPosition + " | " + savedShipItemData.itemScrapValue + " | " + savedShipItemData.itemAdditionalSavedData, DebugType.User); + if (!newItemData.saveItemVariable && savedShipItemData.itemAdditionalSavedData >= 0) + savedShipItemData.itemAdditionalSavedData = -1; + else if (newItemData.saveItemVariable && savedShipItemData.itemAdditionalSavedData == -1) + savedShipItemData.itemAdditionalSavedData = 0; // Might cause problems with some items but what are you gonna do + } + else + { + DebugHelper.Log($"Removing Item: [ {savedShipItemData.itemAllItemsListData.modName} ][ {savedShipItemData.itemAllItemsListData.itemName} ][ {savedShipItemData.itemAllItemsListData.itemObjectName} ][ #{oldIndex}", DebugType.User); - //OverrideCurrentSaveFileItemData(validatedSavedShipItemDataList); - return (validatedSavedShipItemDataList); + savedShipItemData.itemScrapValue = -1; + savedShipItemData.itemAdditionalSavedData = -1; + } + } } - internal static void RefreshSaveItemInfo() + internal static int FixAllItemsListIndex(AllItemsListItemData itemData, Dictionary itemDataDict) { - /* - currentSaveFile.customItemDictionary = new Dictionary(); + // Priorities (higher number = higher priority) + + // Variable definitions: + // itemObjectName : The name of the item's asset file. + // itemName : The name of the item (field set in the item's ScriptableObject). + // modName : The name of the mod the item is from. + // allItemsListIndex : The items list index of this item. + // modItemsListIndex : The items list index of this item relative to the modName. + // itemNameDuplicateIndex : The duplicate index of the item's itemName relative to the modName, e.g. if a mod has two items named "Item A" this will be 1 for the second. + + // Formulas (matching variables): + // 64 -> modAuthor (Only if priority is >= 4) + // 32 -> modName (Only if priority is >= 4) + // 16 -> itemName & itemNameDuplicateIndex (Exclusive with below) + // 8 -> itemName (Exclusive with above) + // 4 -> itemObjectName (Minimum to not be removed) + // 2 -> modItemsListIndex & modName (Only if priority is < 4) + // 1 -> allItemsListIndex (Only if priority is < 4) + + // Possible values: + // 116 -> modAuthor & modName & itemName & itemNameDuplicateIndex & itemObjectName + // 112 -> modAuthor & modName & itemName & itemNameDuplicateIndex + // 108 -> modAuthor & modName & itemName & itemObjectName + // 104 -> modAuthor & modName & itemName + // 100 -> modAuthor & modName & itemObjectName + // 84 -> modAuthor & itemName & itemNameDuplicateIndex & itemObjectName + // 80 -> modAuthor & itemName & itemNameDuplicateIndex + // 76 -> modAuthor & itemName & itemObjectName + // 72 -> modAuthor & itemName + // 68 -> modAuthor & itemObjectName + // 52 -> modName & itemName & itemNameDuplicateIndex & itemObjectName + // 48 -> modName & itemName & itemNameDuplicateIndex + // 44 -> modName & itemName & itemObjectName + // 40 -> modName & itemName + // 36 -> modName & itemObjectName + // 20 -> itemName & itemNameDuplicateIndex & itemObjectName + // 16 -> itemName & itemNameDuplicateIndex + // 12 -> itemName & itemObjectName + // 8 -> itemName + // 4 -> itemObjectName + // Low values (removed by default): + // 3 -> modItemsListIndex & modName & allitemsListIndex + // 2 -> modItemsListIndex & modName + // 1 -> allItemsListIndex + + List allItemsList = Patches.StartOfRound.allItemsList.itemsList; + + int matchedPriority = 0; + int matchedIndex = -1; + + for (int newIndex = 0; newIndex < allItemsList.Count; newIndex++) + { + if (!itemDataDict.ContainsKey(newIndex)) + break; - currentSaveFile.allItemsList = new List(); - foreach (Item item in Patches.StartOfRound.allItemsList.itemsList) - currentSaveFile.allItemsList.Add(item.name); + int currentPriority = 0; + AllItemsListItemData newItemData = itemDataDict[newIndex]; - currentSaveFile.itemSaveDataList = GetItemSaveData(); - currentSaveFile.itemSaveData.Clear(); - foreach (AllItemsListItemData itemSaveData in GetItemSaveData()) - if (!currentSaveFile.itemSaveData.ContainsKey(itemSaveData.allItemsListIndex)) - currentSaveFile.itemSaveData.Add(itemSaveData.allItemsListIndex, itemSaveData); + if (newItemData.itemName == itemData.itemName) + if (newItemData.itemNameDuplicateIndex == itemData.itemNameDuplicateIndex) + currentPriority += 16; + else + currentPriority += 8; - currentSaveFile.customItemDictionary.Clear(); - foreach (ExtendedItem extendedItem in PatchedContent.ExtendedItems) - if (!currentSaveFile.customItemDictionary.ContainsKey(extendedItem.ModName + "_" + extendedItem.name)) - currentSaveFile.customItemDictionary.Add(extendedItem.ModName + "_" + extendedItem.name, extendedItem.ModName); + if (newItemData.itemObjectName == itemData.itemObjectName) + currentPriority += 4; + if (currentPriority >= 4) + { + if (newItemData.modAuthor == itemData.modAuthor) + currentPriority += 64; - currentSaveFile.Save();*/ - } + if (CompareModNames(newItemData.modName, itemData.modName)) + currentPriority += 32; + } + else + { + if (newItemData.modItemsListIndex == itemData.modItemsListIndex && CompareModNames(newItemData.modName, itemData.modName)) + currentPriority += 2; - internal static void SaveCurrentSelectableLevel(SelectableLevel selectableLevel) - { - if (LethalLevelLoaderNetworkManager.networkManager.IsServer == false) - return; - currentSaveFile.CurrentLevelName = selectableLevel.name; - currentSaveFile.Save(); - + if (newItemData.allItemsListIndex == itemData.allItemsListIndex) + currentPriority += 1; + } + + if (currentPriority > matchedPriority) + { + matchedPriority = currentPriority; + matchedIndex = newIndex; + + if (matchedPriority == 64 + 32 + 16 + 4) // Max value + return matchedIndex; + } + } + + // TODO: Config option to disable removing items that aren't name matched? + if (matchedPriority >= 4) + return matchedIndex; + else + return int.MaxValue; // Use MaxValue since vanilla loading code checks upper bounds } - internal static List GetItemSaveData() + internal static Dictionary GetAllItemsListItemDataDict() { - List items = new List(); - List itemsList = new List(); + Dictionary items = new Dictionary(); int counter = 0; foreach (Item item in Patches.StartOfRound.allItemsList.itemsList) { - foreach (ExtendedItem extendedItem in PatchedContent.ExtendedItems) - if (extendedItem.Item == item && !itemsList.Contains(item)) - { - itemsList.Add(item); - items.Add(new AllItemsListItemData(item.name, item.itemName, extendedItem.ModName, counter)); - break; - } + TryGetExtendedItemInfo(item, out string modName, out string modAuthor, out int modItemIndex); + int itemNameDuplicateIndex = GetItemNameDuplicateIndex(item, modName); + + items.Add(counter, new AllItemsListItemData(item.name, item.itemName, modName, modAuthor, counter, modItemIndex, itemNameDuplicateIndex, item.isScrap, item.saveItemVariable)); counter++; } return (items); } - internal static void LoadShipGrabbableItems() + internal static bool TryGetExtendedItemInfo(Item item, out string modName, out string modAuthor, out int modItemIndex) { - List shipGrabbableItemIDs = new List(); - List shipGrabbableItemPos = new List(); - List shipScrapValues = new List(); - List shipItemSaveData = new List(); + int lowestNameAliases = int.MaxValue; + modName = ""; + modAuthor = ""; + modItemIndex = -1; - foreach (SavedShipItemData savedShipItemData in ProcessSavedItemIndicies(ValidateSaveData())) + foreach (ExtendedMod extendedMod in PatchedContent.ExtendedMods) { - shipGrabbableItemIDs.Add(savedShipItemData.itemAllItemsListIndex); - if (savedShipItemData.itemPosition != new Vector3(-1, -1, -1)) - shipGrabbableItemPos.Add(savedShipItemData.itemPosition); - if (savedShipItemData.itemScrapValue != -1) - shipScrapValues.Add(savedShipItemData.itemScrapValue); - if (savedShipItemData.itemAdditionalSavedData != -1) - shipItemSaveData.Add(savedShipItemData.itemAdditionalSavedData); + if (lowestNameAliases <= extendedMod.ModNameAliases.Count) + continue; + + int modCounter = 0; + + foreach (ExtendedItem extendedItem in extendedMod.ExtendedItems) + { + if (extendedItem.Item == item) + { + modName = string.Join(';', extendedMod.ModNameAliases); + modAuthor = extendedMod.AuthorName; + modItemIndex = modCounter; + + lowestNameAliases = extendedMod.ModNameAliases.Count; + break; + } + modCounter++; + } } + + return modItemIndex > -1; } - internal static void OverrideCurrentSaveFileItemData(List savedShipItemDatas) + internal static int GetItemNameDuplicateIndex(Item item, string modName) { - List shipGrabbableItemIDs = new List(); - List shipGrabbableItemPos = new List(); - List shipScrapValues = new List(); - List shipItemSaveData = new List(); + if (modName != "") + { + foreach (ExtendedMod extendedMod in PatchedContent.ExtendedMods) + if (CompareModNames(extendedMod.ModName, modName)) + { + int modCounter = 0; - string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; + foreach (ExtendedItem extendedItem in extendedMod.ExtendedItems) + if (extendedItem.Item == item) + break; + else if (extendedItem.Item.itemName == item.itemName) + modCounter++; - foreach (SavedShipItemData savedShipItemData in savedShipItemDatas) + return modCounter; + } + + return 0; + } + else { - shipGrabbableItemIDs.Add(savedShipItemData.itemAllItemsListIndex); - if (savedShipItemData.itemPosition != new Vector3(-1,-1,-1)) - shipGrabbableItemPos.Add(savedShipItemData.itemPosition); - if (savedShipItemData.itemScrapValue != -1) - shipScrapValues.Add(savedShipItemData.itemScrapValue); - if (savedShipItemData.itemAdditionalSavedData != -1) - shipItemSaveData.Add(savedShipItemData.itemAdditionalSavedData); + int counter = 0; + + foreach (Item newItem in Patches.StartOfRound.allItemsList.itemsList) + if (newItem == item) + break; + else if (newItem.itemName == item.itemName && !TryGetExtendedItemInfo(item, out _, out _, out _)) + counter++; + + return counter; } + } - if (ES3.KeyExists("shipGrabbableItemIDs", currentSaveFileName)) - ES3.DeleteKey("shipGrabbableItemIDs", currentSaveFileName); - if (ES3.KeyExists("shipGrabbableItemPos", currentSaveFileName)) - ES3.DeleteKey("shipGrabbableItemPos", currentSaveFileName); - if (ES3.KeyExists("shipScrapValues", currentSaveFileName)) - ES3.DeleteKey("shipScrapValues", currentSaveFileName); - if (ES3.KeyExists("shipItemSaveData", currentSaveFileName)) - ES3.DeleteKey("shipItemSaveData", currentSaveFileName); + internal static bool CompareModNames(string modNameA, string modNameB) + { + var modNamesA = modNameA.Split(';'); + var modNamesB = modNameB.Split(';'); - if (shipGrabbableItemIDs.Count > 0) - ES3.Save("shipGrabbableItemIDs", shipGrabbableItemIDs.ToArray(), currentSaveFileName); - if (shipGrabbableItemPos.Count > 0) - ES3.Save("shipGrabbableItemPos", shipGrabbableItemPos.ToArray(), currentSaveFileName); - if (shipScrapValues.Count > 0) - ES3.Save("shipScrapValues", shipScrapValues.ToArray(), currentSaveFileName); - if (shipItemSaveData.Count > 0) - ES3.Save("shipItemSaveData", shipItemSaveData.ToArray(), currentSaveFileName); + return modNamesA.Intersect(modNamesB).Any(); + } + + internal static List GetAllItemsListItemDatas(List itemIDs, Dictionary itemDataDict) + { + List result = new List(); + + foreach (int id in itemIDs) + { + if (itemDataDict.ContainsKey(id)) + result.Add(itemDataDict[id]); + else + // Don't know this item somehow? Add empty junk + result.Add(new AllItemsListItemData("", "", "", "", id, -1, 0, false, false)); + } + + return (result); } - internal static Dictionary GetConstructedSavedShipItemData() + internal static List GetConstructedSavedShipItemData(Dictionary itemDataDict) { - Dictionary returnDict = new Dictionary(); + List result = new List(); string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; @@ -307,27 +417,46 @@ internal static Dictionary GetConstructedSavedShipItemDa else shipItemSaveData = new List(); + List shipGrabbableItemData = GetAllItemsListItemDatas(shipGrabbableItemIDs, itemDataDict); + + int scrapValueIndex = 0; + int saveDataIndex = 0; + for (int i = 0; i < shipGrabbableItemIDs.Count; i++) { int newGrabbableItemID = shipGrabbableItemIDs[i]; - Vector3 newGrabbableItemPos = new Vector3(-1, -1, -1); + Vector3 newGrabbableItemPos = Vector3.zero; int newShipScrapValue = -1; int newShipItemSaveData = -1; + AllItemsListItemData newGrabbableItemData = shipGrabbableItemData[i]; if (shipGrabbableItemPos.Count > i) newGrabbableItemPos = shipGrabbableItemPos[i]; - if (shipScrapValues.Count > i) - newShipScrapValue = shipScrapValues[i]; - if (shipItemSaveData.Count > i) - newShipItemSaveData = shipItemSaveData[i]; - returnDict.Add(newGrabbableItemID, new SavedShipItemData(newGrabbableItemID, newGrabbableItemPos, newShipScrapValue, newShipItemSaveData)); - } + if (newGrabbableItemData.isScrap) + { + if (shipScrapValues.Count > scrapValueIndex) + newShipScrapValue = shipScrapValues[scrapValueIndex]; + else + newShipScrapValue = 0; + + scrapValueIndex++; + } - if (returnDict.Count == 0) - DebugHelper.LogWarning("GetConstructedSavedShipItemData() Returning Empty Dict!", DebugType.User); + if (newGrabbableItemData.saveItemVariable) + { + if (shipItemSaveData.Count > saveDataIndex) + newShipItemSaveData = shipItemSaveData[saveDataIndex]; + else + newShipItemSaveData = 0; + + saveDataIndex++; + } + + result.Add(new SavedShipItemData(newGrabbableItemID, newGrabbableItemPos, newShipScrapValue, newShipItemSaveData, newGrabbableItemData)); + } - return (returnDict); + return (result); } } @@ -337,27 +466,15 @@ public class SavedShipItemData public Vector3 itemPosition; public int itemScrapValue; public int itemAdditionalSavedData; + public AllItemsListItemData itemAllItemsListData; - public SavedShipItemData(int newItemAllItemsListIndex, Vector3 newItemPosition, int newItemScrapValue, int newItemAdditionalSavedData) + public SavedShipItemData(int newItemAllItemsListIndex, Vector3 newItemPosition, int newItemScrapValue, int newItemAdditionalSavedData, AllItemsListItemData newItemAllItemsListData) { itemAllItemsListIndex = newItemAllItemsListIndex; itemPosition = newItemPosition; itemScrapValue = newItemScrapValue; itemAdditionalSavedData = newItemAdditionalSavedData; + itemAllItemsListData = newItemAllItemsListData; } } - - public struct ProcessedData - { - public List validIndicies; - public Dictionary recoveredIndicies; - public List invalidIndicies; - - public ProcessedData(List newValidIndicies, Dictionary newRecoveredIndicies, List newInvalidIndicies) - { - validIndicies = newValidIndicies; - recoveredIndicies = newRecoveredIndicies; - invalidIndicies = newInvalidIndicies; - } - } } diff --git a/LethalLevelLoader/Patches/TerminalManager.cs b/LethalLevelLoader/Patches/TerminalManager.cs index 4d104b3..dc76e1a 100644 --- a/LethalLevelLoader/Patches/TerminalManager.cs +++ b/LethalLevelLoader/Patches/TerminalManager.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Net.Http.Headers; using Unity.Netcode; -using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.InputSystem; diff --git a/LethalLevelLoader/Plugin.cs b/LethalLevelLoader/Plugin.cs index f22ce7b..295607e 100644 --- a/LethalLevelLoader/Plugin.cs +++ b/LethalLevelLoader/Plugin.cs @@ -60,7 +60,8 @@ private void Awake() GameObject test = new GameObject("LethalLevelLoader AssetBundleLoader"); test.AddComponent().LoadBundles(); - test.hideFlags = HideFlags.HideAndDontSave; + //test.hideFlags = HideFlags.HideAndDontSave; + DontDestroyOnLoad(test); AssetBundleLoader.onBundlesFinishedLoading += AssetBundleLoader.LoadContentInBundles; ConfigLoader.BindGeneralConfigs(); diff --git a/LethalLevelLoader/Tools/Validators.cs b/LethalLevelLoader/Tools/Validators.cs index 84f7b81..06311fb 100644 --- a/LethalLevelLoader/Tools/Validators.cs +++ b/LethalLevelLoader/Tools/Validators.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Text; using Unity.Netcode; -using UnityEditor.ShaderKeywordFilter; using UnityEngine; namespace LethalLevelLoader diff --git a/Thunderstore/plugins/LethalLevelLoader.dll b/Thunderstore/plugins/LethalLevelLoader.dll index 93fdcb3..2bc00db 100644 Binary files a/Thunderstore/plugins/LethalLevelLoader.dll and b/Thunderstore/plugins/LethalLevelLoader.dll differ