internal static void Setup(Mod ZZLocalizationMod) { // Save format: /* * .. hmm, vanilla item drops...do I have to recalculate each time? New Set of mods => complete refresh? * * ZZLocalizationModVersion // So if we add more features we can ignore this file * [ of Mod Info * -> ModName * -> Version * -> [ of npc drop info? or item info? * --> Tuple<JSONNPC, LootItem[]> or * --> JSONNPC<T> * --> * ---> OR * --> Item Info * ---> ["NPCInfo" with droprate] * --> * -> ] * ] * * hmm, instead of mod info, just a list of npc? just a list of Item? * * <Mod, Version>[] --> For knowing which have updated....for now, any update or unaccounted mod, recalculate allll * ItemInfo[] JSONNPC and array of JSONNPC that drop it. (forget droprates for now?) * * * item to npc or npc to item.... */ string json; string filename = "zzmodLootCache.json"; string folder = Path.Combine(Main.SavePath, "Mods", "Cache"); string path = Path.Combine(folder, filename); LootCache li = new LootCache(); bool needsRecalculate = true; LootCacheManagerActive = true; List <string> modsThatNeedRecalculate = new List <string>(); if (File.Exists(path)) { using (StreamReader r = new StreamReader(path)) { json = r.ReadToEnd(); li = JsonConvert.DeserializeObject <LootCache>(json, new JsonSerializerSettings { Converters = { new Newtonsoft.Json.Converters.VersionConverter() } }); needsRecalculate = false; if (li == null) // Investigate why some people get LootCache.json with only 0s in it. { li = new LootCache(); } } } // New Recipe Browser version, assume total reset needed (adjust this logic next update.) if (li.ZZLocalizationModVersion != ZZLocalizationMod.Version) { li.lootInfos.Clear(); li.cachedMods.Clear(); li.ZZLocalizationModVersion = ZZLocalizationMod.Version; needsRecalculate = true; } // If we aren't up to date on each mod... foreach (var m in ModLoader.Mods) { if (/*mod == "ModLoader" || */ m.Name == "ZZLocalizationMod") { continue; } string modName = m.Name == "ModLoader" ? "Terraria" : m.Name; if (!li.cachedMods.Any(x => x.Key == modName && x.Value == m.Version)) // if this mod is either updated or doesn't exist yet //if (li.cachedMods.ContainsKey(modName) && li.cachedMods[modName] == m.Version) { if (m.Version >= new Version(0, 6, 3)) { needsRecalculate = true; } // Remove mod from list li.cachedMods.Remove(modName); // Remove items from this mod var toRemove = li.lootInfos.Where(pair => pair.Key.mod == modName) // Can't detect if a vanilla npc dropping a vanilla is because of mod. It's fine .Select(pair => pair.Key) .ToList(); foreach (var key in toRemove) { li.lootInfos.Remove(key); } // Remove npc from items. foreach (var itemToNPCs in li.lootInfos) { itemToNPCs.Value.RemoveAll(x => x.mod == modName); } modsThatNeedRecalculate.Add(modName); modsThatNeedRecalculate.Add("Terraria"); li.cachedMods[modName] = m.Version; // (new Tuple<string, Version>(modName, m.Version)); } } //li.cachedMods.Add(new Tuple<string, Version>(m.Name, m.Version)); if (needsRecalculate) { // Temp variables float soundVolume = Main.soundVolume; Main.soundVolume = 0f; if (!Main.dedServ) { try { Reflect(); } catch { } } setLoadProgressText?.Invoke("正在重新计算掉落物品,时间较长请稍等"); setLoadProgressProgress?.Invoke(0f); // expert drops? for (int playernum = 0; playernum < 256; playernum++) { Main.player[playernum] = new Player(); for (int i = 0; i < 50; i++) { Main.player[playernum].inventory[i].type = 3507; } } //Main.player[0].active = true; // Fix Terraria Overhaul bug if (Main.maxTilesY < 600 || Main.maxTilesX < 2100) { Main.maxTilesX = 8400; Main.maxTilesY = 2400; Main.tile = new Tile[Main.maxTilesX + 1, Main.maxTilesY + 1]; } int oldMx = Main.maxTilesX; Main.maxTilesX = 2100; int oldMy = Main.maxTilesY; Main.maxTilesY = 600; for (int x = 0; x < Main.maxTilesX; x++) { for (int y = 0; y < Main.maxTilesY; y++) { Main.tile[x, y] = new Tile(); Main.tile[x, y].type = 0; if (y > Main.maxTilesY * 0.3f) { Main.tile[x, y].active(true); } } } Main.worldSurface = 200; //Main.netMode = 1; // hope this doesn't do anything weird NPC npc = new NPC(); Item item = new Item(); loots = new HashSet <int>(); string lastMod = ""; var watch = Stopwatch.StartNew(); var oldRand = Main.rand; if (Main.rand == null) { Main.rand = new Terraria.Utilities.UnifiedRandom(); } Main.hardMode = true; Main.expertMode = true; CalamitySupport.CalamityCalculateLootLoad(); ThoriumSupport.ThoriumCalculateLootLoad(); AASupport.AACalculateLootLoad(); SacredtoolsSupport.SacredtoolsCalculateLootLoad(); ModRedemption.ModRedemptionCalculateLootLoad(); for (int i = 1; i < NPCLoader.NPCCount; i++) // for every npc... { npc.SetDefaults(i); npc.value = 0; // Causes some drops to be missed, why is this here? string currentMod = npc.modNPC?.mod.Name ?? "Terraria"; if (!modsThatNeedRecalculate.Contains(currentMod)) { continue; } if (lastMod != currentMod) { lastMod = currentMod; setLoadSubProgressText?.Invoke(lastMod); } setLoadProgressProgress?.Invoke((float)i / NPCLoader.NPCCount); JSONNPC jsonNPC = new JSONNPC(npc.modNPC?.mod.Name ?? "Terraria", npc.modNPC?.Name ?? npc.TypeName, npc.modNPC != null ? 0 : i); loots.Clear(); CalculateLoot(npc, Main.player[0]); // ...calculate drops foreach (var loot in loots) { if (ignoreItemIDS.Contains(loot)) { continue; } item.SetDefaults(loot, true); //JSONItem jsonitem = new JSONItem(item.modItem?.mod.Name ?? "Terraria", Lang.GetItemNameValue(loot), item.modItem != null ? 0 : loot); JSONItem jsonitem = new JSONItem(item.modItem?.mod.Name ?? "Terraria", item.modItem?.Name ?? Lang.GetItemNameValue(loot), item.modItem != null ? 0 : loot); if (!li.lootInfos.TryGetValue(jsonitem, out LootInfo.npcsthatdropme)) { li.lootInfos.Add(jsonitem, LootInfo.npcsthatdropme = new List <JSONNPC>()); } LootInfo.npcsthatdropme.Add(jsonNPC); } } loots.Clear(); // Reset temp values Main.rand = oldRand; // value 8 seconds. // don't value to 0 and ignore.contains: 5 seconds. // value to 0, contains, 4 seconds. .6 seconds without contains. Main.maxTilesX = oldMx; Main.maxTilesY = oldMy; Main.soundVolume = soundVolume; // Save json: watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; //li.iterations = MaxNumberLootExperiments; li.lastUpdateTime = elapsedMs; Directory.CreateDirectory(folder); json = JsonConvert.SerializeObject(li, Formatting.Indented, new JsonSerializerSettings { Converters = { new Newtonsoft.Json.Converters.VersionConverter() } }); File.WriteAllText(path, json); // Reset Load Mods Progress bar setLoadSubProgressText?.Invoke(""); setLoadProgressText?.Invoke("添加合成"); setLoadProgressProgress?.Invoke(0f); } LootCacheManagerActive = false; LootCache.instance = li; }