/// <summary> /// Checks recipe /// </summary> private JToken ProcessRecipeType(Recipe recipe) { JObject result = new JObject(); _usedSkill = null; bool first = true; Logger.Assert(recipe.Products.Length > 0, "Products array should be not empty"); foreach (var craftingElement in recipe.Products) { string name = craftingElement.Item.Type.Name; if (first) { first = false; result["result"] = name; result["quantity"] = EvaluateDynamicValue(craftingElement.Quantity); result["ingredients"] = new JObject(); continue; } result["ingredients"][name] = EvaluateDynamicValue(craftingElement.Quantity); } foreach (var craftingElement in recipe.Ingredients) { string name = craftingElement.Item.Type.Name; result["ingredients"][name] = EvaluateDynamicValue(craftingElement.Quantity); } if (_usedSkill != null) { result["skill"] = _usedSkill; } foreach (var tableType in CraftingComponent.TablesForRecipe(typeof(Recipe))) { Logger.Assert(tableType.IsSubclassOf(typeof(WorldObject)), $"{tableType} is not a world object"); foreach (RequireComponentAttribute attribute in tableType.GetCustomAttributes(typeof(RequireComponentAttribute), true)) { } } return(result); }
private static void UpdateRecipes(StreamWriter sw, TechTreeSimData data) { var numRemoved = 1; while (numRemoved != 0) { numRemoved = 0; var toRemove = new List <Recipe>(); foreach (var recipe in data.unusableRecipes) { if (data.craftableItems.Contains(recipe.Products.Select(x => x.Item.Type))) { toRemove.Add(recipe); } else if (data.craftableItems.Contains(recipe.Ingredients.Select(x => x.Item.Type)) && CraftingComponent.TablesForRecipe(recipe.GetType()).Intersect(data.craftingTables).Any()) { foreach (var product in recipe.Products.Select(x => x.Item)) { data.craftableItems.AddUnique(product.Type); sw.WriteLine(" - New Craftable Items: " + product); if (product is WorldObjectItem) { data.craftingTables.AddUnique((product as WorldObjectItem).WorldObjectType); //will need to specify power items } if (product is SkillBook) { data.AddSkill(sw, (product as SkillBook).Skill.Type); } } toRemove.Add(recipe); numRemoved++; } } toRemove.ForEach(x => { data.unusableRecipes.Remove(x); data.curRecipes.Add(x); }); } }
private static void UpdateRecipes(InfoBuilder info, TechTreeSimData data) { var numRemoved = 1; while (numRemoved != 0) { numRemoved = 0; var toRemove = new List <Recipe>(); foreach (var recipe in data.UnusableRecipes) { if (data.CraftableItems.ContainsAll(recipe.Items.Select(x => x.Item.Type))) { toRemove.Add(recipe); } else if (recipe.Ingredients.All(data.HasIngredient) && CraftingComponent.TablesForRecipe(recipe.Family.GetType()).Intersect(data.CraftingTables).Any()) { foreach (var product in recipe.Items.Select(x => x.Item)) { data.AddItem(product.Type); info.AppendLineLocStr(" - New Craftable Items: " + product); if (product is WorldObjectItem) { data.CraftingTables.AddUnique((product as WorldObjectItem).WorldObjectType); //will need to specify power items } if (product is SkillBook) { data.AddSkill((product as SkillBook).Skill.Type); } } toRemove.Add(recipe); numRemoved++; } } toRemove.ForEach(x => { data.UnusableRecipes.Remove(x); data.CurRecipes.Add(x); }); } }
public static void TechTreeSimulation(User user) { using (StreamWriter sw = new StreamWriter("TechTreeSimulation.txt")) { var data = new TechTreeSimData(); sw.WriteLine("Starting Tech Tree Sim"); sw.WriteLine("Getting Starting Skills..."); var introSkills = PlayerDefaults.GetDefaultSkills().ToList(); introSkills.ForEach(x => data.AddSkill(sw, x)); sw.WriteLine("Getting Initial Tables..."); data.craftingTables.Add(typeof(CampsiteObject)); sw.WriteLine("Getting Recipes with No Skills..."); var temp = Recipe.AllRecipes.Where(x => !x.RequiredSkills.Any() && x.Ingredients.Any()); data.unusableRecipes.AddRange(Recipe.AllRecipes.Where(x => !x.RequiredSkills.Any() && x.Ingredients.Any())); sw.WriteLine("Getting World Resources..."); //manually defined for now since theres no easy way of checking for these data.craftableItems.AddRange(new List <Type>() { typeof(DirtItem), typeof(SandItem), typeof(StoneItem), typeof(IronOreItem), typeof(CopperOreItem), typeof(GoldOreItem), typeof(CoalItem) }); sw.WriteLine("Getting Species Resources..."); var seedless = new List <Species>(); var resourceless = new List <Species>(); EcoSim.AllSpecies.ForEach(x => { sw.WriteLine("Adding Species: " + x.DisplayName); if (x is PlantSpecies) { if ((x as PlantSpecies).SeedItem.Type != null && (x as PlantSpecies).SeedRange.Max > 0 && (x as PlantSpecies).SeedRange.Min <= (x as PlantSpecies).SeedRange.Max) { var item = (x as PlantSpecies).SeedItem.Type; data.craftableItems.AddUnique(item); sw.WriteLine(" - New Resource: " + item.Name); } else { seedless.Add(x); } } if (x.ResourceItem.Type != null && x.ResourceRange.Max > 0 && x.ResourceRange.Min <= x.ResourceRange.Max) { var item = x.ResourceItem.Type; data.craftableItems.AddUnique(item); sw.WriteLine(" - New Resource: " + item.Name); } else { resourceless.Add(x); } }); sw.WriteLine("\nSimulating...\n"); UpdateRecipes(sw, data); UpdateRecipesFromSkills(sw, data); sw.WriteLine("\nTech Tree Sim Complete"); ChatManager.SendChat(CheckStatus(sw, data) ? "Tech Tree Complete" : "Tech Tree Failed, check the TechTreeSimulation.txt for more information.", user.Player.ID); //get issues with complete //PLANT DATA sw.WriteLine("\nPlants Missing Seeds"); sw.WriteLine(String.Join(",", seedless)); sw.WriteLine("Plants Missing Resources"); sw.WriteLine(String.Join(",", resourceless)); //CRAFTABLES sw.WriteLine("\nUncraftable Accessed"); foreach (var recipe in data.unusableRecipes) { sw.WriteLine(" " + recipe.DisplayName); recipe.Ingredients.ForEach(x => sw.WriteLine(" I: " + x.Item.DisplayName)); recipe.Products.ForEach(x => sw.WriteLine(" P: " + x.Item.DisplayName)); if (!data.craftableItems.Contains(recipe.Ingredients.Select(x => x.Item.Type))) { sw.WriteLine(" missing ingredients"); } if (!CraftingComponent.TablesForRecipe(recipe.GetType()).Intersect(data.craftingTables).Any()) { sw.WriteLine(" missing crafting table"); } } sw.WriteLine("\nUncraftable Unaccessed"); foreach (var recipe in Recipe.AllRecipes.Except(data.curRecipes)) { sw.WriteLine(" " + recipe.DisplayName); recipe.Ingredients.ForEach(x => sw.WriteLine(" I: " + x.Item.DisplayName)); recipe.Products.ForEach(x => sw.WriteLine(" P: " + x.Item.DisplayName)); if (!data.curSkills.Contains(recipe.RequiredSkills.Select(x => x.SkillType))) { sw.WriteLine(" missing skills"); } if (!data.craftableItems.Contains(recipe.Ingredients.Select(x => x.Item.Type))) { sw.WriteLine(" missing ingredients"); } if (!CraftingComponent.TablesForRecipe(recipe.GetType()).Intersect(data.craftingTables).Any()) { sw.WriteLine(" missing crafting table"); } } //ALL UNOBTAINABLE ITEMS sw.WriteLine("\nUnobtainable Items"); foreach (var item in Item.AllItems .Where(x => !(x is Skill) && !(x is ActionbarItem) && !(x is SkillScroll) && !(x.Category == "Hidden")) .Select(x => x.Type) .Except(data.craftableItems)) { sw.WriteLine(" " + item.Name); } } }
// Extracting Recipes is complex and requires collection and sorting. public static void RecipesDetails() { // dictionary of recipe properties Dictionary <string, string> recipeDetails = new Dictionary <string, string>() { // Legacy? Maybe OBSOLETE? { "dispCraftStn", "'1'" }, { "checkImage", "'1'" }, // Info { "untranslated", "nil" }, { "craftStn", "nil" }, { "skillNeeds", "nil" }, { "moduleNeeds", "nil" }, { "baseCraftTime", "nil" }, { "baseLaborCost", "nil" }, { "baseXPGain", "nil" }, // Variants { "defaultVariant", "nil" }, { "defaultVariantUntranslated", "nil" }, { "numberOfVariants", "nil" }, { "variants", "nil" }, }; Dictionary <string, string> variantDetails = new Dictionary <string, string>() { { "untranslated", "nil" }, { "ingredients", "nil" }, { "products", "nil" } }; // collect all the recipes var famalies = RecipeFamily.AllRecipes; foreach (RecipeFamily family in famalies) { string familyName = Localizer.DoStr(family.RecipeName); string familyNameUntrans = family.RecipeName; if (!EveryRecipe.ContainsKey(familyName)) { EveryRecipe.Add(familyName, new Dictionary <string, string>(recipeDetails)); EveryRecipe[familyName]["untranslated"] = $"'{familyNameUntrans}'"; // Crafting Stations. StringBuilder tables = new StringBuilder(); tables.Append("{"); foreach (Type type in CraftingComponent.TablesForRecipe(family.GetType())) { WorldObjectItem creatingItem = WorldObjectItem.GetCreatingItemTemplateFromType(type); string table = creatingItem.DisplayName; string untransTable = creatingItem.DisplayName.NotTranslated; tables.Append($"{{'{table}', '{untransTable}'}}"); AddTableRecipeRelation(table, familyName); if (type != CraftingComponent.TablesForRecipe(family.GetType()).Last()) { tables.Append(", "); } } tables.Append("}"); EveryRecipe[familyName]["craftStn"] = tables.ToString(); // Skills required StringBuilder skillNeeds = new StringBuilder(); skillNeeds.Append("{"); foreach (RequiresSkillAttribute req in family.RequiredSkills) { skillNeeds.Append("{'" + req.SkillItem.DisplayName + "','" + req.Level.ToString() + "','" + req.SkillItem.DisplayName.NotTranslated + "'}"); if (req != family.RequiredSkills.Last()) { skillNeeds.Append(", "); } } skillNeeds.Append("}"); EveryRecipe[familyName]["skillNeeds"] = skillNeeds.ToString(); // Modules Required StringBuilder moduleNeeds = new StringBuilder(); moduleNeeds.Append("{"); foreach (var module in family.RequiredModules) { moduleNeeds.Append("'" + module.ModuleName + "'"); if (module != family.RequiredModules.Last()) { moduleNeeds.Append(", "); } } moduleNeeds.Append("}"); EveryRecipe[familyName]["moduleNeeds"] = moduleNeeds.ToString(); // Base craft time. EveryRecipe[familyName]["baseCraftTime"] = (family.CraftMinutes != null) ? "'" + family.CraftMinutes.GetBaseValue.ToString() + "'" : "'0'"; // Base labor cost EveryRecipe[familyName]["baseLaborCost"] = "'" + family.Labor.ToString() + "'"; // Base XP gain EveryRecipe[familyName]["baseXPGain"] = "'" + family.ExperienceOnCraft.ToString() + "'"; // Default Recipe EveryRecipe[familyName]["defaultVariant"] = "'" + Localizer.DoStr(SplitName(family.DefaultRecipe.Name)) + "'"; EveryRecipe[familyName]["defaultVariantUntranslated"] = "'" + SplitName(family.DefaultRecipe.Name) + "'"; EveryRecipe[familyName]["numberOfVariants"] = "'" + family.Recipes.Count + "'"; SortedDictionary <string, Dictionary <string, string> > variant = new SortedDictionary <string, Dictionary <string, string> >(); foreach (Recipe r in family.Recipes) { var recipe = r.DisplayName; if (!variant.ContainsKey(recipe)) { variant.Add(recipe, new Dictionary <string, string>(variantDetails)); variant[recipe]["untranslated"] = $"'{r.DisplayName.NotTranslated}'"; // Ingredients required StringBuilder ingredients = new StringBuilder(); ingredients.Append("{"); foreach (var e in r.Ingredients) { ingredients.Append("{"); LocString element; if (e.IsSpecificItem) { ingredients.Append("'ITEM', "); element = e.Item.DisplayName; AddRecipeIngredientRelation(e.Item.DisplayName, r.DisplayName); } else { ingredients.Append("'TAG', "); element = Localizer.DoStr(SplitName(e.Tag.DisplayName)); } bool isStatic = false; if (e.Quantity is ConstantValue) { isStatic = true; } ingredients.Append("'" + element + "', '" + e.Quantity.GetBaseValue + "', '" + isStatic.ToString() + "', '" + element.NotTranslated + "'}"); if (e != r.Ingredients.Last()) { ingredients.Append(", "); } } ingredients.Append("}"); variant[recipe]["ingredients"] = ingredients.ToString(); // Products recieved StringBuilder products = new StringBuilder(); products.Append("{"); foreach (var e in r.Items) { products.Append("{"); products.Append("'" + e.Item.DisplayName + "', '" + e.Quantity.GetBaseValue + "', '" + e.Item.DisplayName.NotTranslated + "'}"); if (e != r.Items.Last()) { products.Append(", "); } AddRecipeProductRelation(e.Item.DisplayName, r.DisplayName); } products.Append("}"); variant[recipe]["products"] = products.ToString(); } } StringBuilder builder = new StringBuilder(); builder.AppendLine(" {"); string space = space2 + space2 + space3; foreach (string key in variant.Keys) { builder.AppendLine(string.Format("{0}['{1}'] = {{", space, key)); foreach (KeyValuePair <string, string> keyValuePair in variant[key]) { builder.AppendLine(string.Format("{0}{1}['{2}'] = {3},", space, space2, keyValuePair.Key, keyValuePair.Value)); } builder.Append(string.Format("{0}}}", space)); //if (key != variant.Keys.Last()) builder.AppendLine(","); } builder.Append(space2 + space3 + "}"); EveryRecipe[familyName]["variants"] = builder.ToString(); } } var lang = LocalizationPlugin.Config.Language; // writes to the Eco Server directory. if (!Directory.Exists(SaveLocation + $@"{lang}\")) { Directory.CreateDirectory(SaveLocation + $@"{lang}\"); } // writes to WikiItems.txt to the Eco Server directory. string path = SaveLocation + $@"{lang}\" + "Wiki_Module_CraftingRecipes.txt"; using (StreamWriter streamWriter = new StreamWriter(path, false)) { streamWriter.WriteLine("-- Eco Version : " + EcoVersion.Version); streamWriter.WriteLine(); streamWriter.WriteLine("return {\n recipes = {"); foreach (string key in EveryRecipe.Keys) { streamWriter.WriteLine(string.Format("{0}['{1}'] = {{", space2, key)); foreach (KeyValuePair <string, string> keyValuePair in EveryRecipe[key]) { streamWriter.WriteLine(string.Format("{0}{1}['{2}'] = {3},", space2, space3, keyValuePair.Key, keyValuePair.Value)); } streamWriter.WriteLine(string.Format("{0}}},", space2)); } // write the recipe ingredients to recipe variant data streamWriter.WriteLine(" },\n ingredients = {"); foreach (string key1 in RecipeIngedientVariantDic.Keys) { streamWriter.Write(string.Format("{0}['{1}'] = {{ ", space2, key1)); foreach (string key2 in RecipeIngedientVariantDic[key1].Keys) { if (key2 != RecipeIngedientVariantDic[key1].Keys.Last()) { streamWriter.Write(string.Format("'{0}', ", key2)); } else { streamWriter.Write(string.Format("'{0}'", key2)); } } streamWriter.WriteLine("},"); } // write the recipe products to recipe variant data streamWriter.WriteLine(" },\n products = {"); foreach (string key1 in RecipeProductVariantDic.Keys) { streamWriter.Write(string.Format("{0}['{1}'] = {{ ", space2, key1)); foreach (string key2 in RecipeProductVariantDic[key1].Keys) { if (key2 != RecipeProductVariantDic[key1].Keys.Last()) { streamWriter.Write(string.Format("'{0}', ", key2)); } else { streamWriter.Write(string.Format("'{0}'", key2)); } } streamWriter.WriteLine("},"); } // write the table to recipe family data streamWriter.WriteLine(" },\n tables = {"); foreach (string key1 in tableRecipeFamilyDic.Keys) { streamWriter.Write(string.Format("{0}['{1}'] = {{ ", space2, key1)); foreach (string key2 in tableRecipeFamilyDic[key1].Keys) { if (key2 != tableRecipeFamilyDic[key1].Keys.Last()) { streamWriter.Write(string.Format("'{0}', ", key2)); } else { streamWriter.Write(string.Format("'{0}'", key2)); } } streamWriter.WriteLine("},"); } /* * // write the group(tag) to recipe data * streamWriter.WriteLine(" },\n groups = {"); * foreach (string key1 in groupRecipeDic.Keys) * { * streamWriter.Write(string.Format("{0}['{1}'] = {{ ", space2, key1)); * foreach (string key2 in groupRecipeDic[key1].Keys) * streamWriter.Write(string.Format("'{0}', ", key2)); * streamWriter.WriteLine("},"); * } */ streamWriter.Write(" },\n}"); streamWriter.Close(); } }
public static List <string> GetTablesForRecipe(RecipeFamily recipe) { return(CraftingComponent.TablesForRecipe(recipe.GetType()).Select(type => GetTableNameFromUILink(WorldObject.UILink(type, false))).ToList()); }
public static void RemoveRecipe(Type targetRecipeType) { Console.Write("Removing" + string.Concat(targetRecipeType.ToString().Split('.').Last().Select(x => Char.IsUpper(x) ? " " + x : x.ToString()))); // Get all the existing recipe Dictionary <Type, Recipe[]> staticRecipes = (Dictionary <Type, Recipe[]>) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("staticRecipes")).GetValue(Activator.CreateInstance(typeof(CraftingComponent))); // Get all the recipe to table dicationary Dictionary <Type, List <Type> > recipeToTable = (Dictionary <Type, List <Type> >) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("recipeToTable")).GetValue(Activator.CreateInstance(typeof(CraftingComponent))); // Get all item to recipe dictionary Dictionary <Type, List <Recipe> > itemToRecipe = (Dictionary <Type, List <Recipe> >) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("itemToRecipe")).GetValue(Activator.CreateInstance(typeof(CraftingComponent))); lock (staticRecipes) { Type targetTable = CraftingComponent.TablesForRecipe(targetRecipeType).First(); Console.WriteLine(" from" + string.Concat(targetTable.ToString().Split('.').Last().Select(x => Char.IsUpper(x) ? " " + x : x.ToString()))); Recipe targetRecipe = null; Recipe[] recipes; // Get all the recipe inside the table if (staticRecipes.TryGetValue(targetTable, out recipes)) { // Get the recipe targetRecipe = recipes.First(x => x.GetType() == targetRecipeType); // Remove the target recipe from the recipe list recipes = recipes.Where(x => x.GetType() != targetRecipeType).ToArray(); } // Set back the recipe inside the static recipe dictionnary staticRecipes[targetTable] = recipes; // Remove the recipe from the recipe to table dictionary recipeToTable[targetRecipeType].Remove(targetTable); // Remove the recipe from the item to recipe dictionary targetRecipe?.Products.ForEach(product => itemToRecipe[product.Item.Type].Remove(targetRecipe)); // Remove the table from the list of table // Only if there is no more recipe inside the table if (recipes.Length == 0) { CraftingComponent.AllTableWorldObjects.Remove(targetTable); } // After removing the recipe we need to update the skill unlock // Get all the skillunlock tooltips Dictionary <Type, Dictionary <int, List <LocString> > > skillUnlocksTooltips = (Dictionary <Type, Dictionary <int, List <LocString> > >) typeof(Skill).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("skillUnlocksTooltips")).GetValue(null); // Get all the skillbenefit tooltips Dictionary <Type, Dictionary <LocString, List <SkillModifiedValue> > > skillBenefitsTooltips = (Dictionary <Type, Dictionary <LocString, List <SkillModifiedValue> > >) typeof(SkillModifiedValueManager).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("skillBenefits")).GetValue(null); // Get the skill that unlock the recipe Type skillType = RequiresSkillAttribute.Cache.Get(targetRecipeType).FirstOrDefault()?.SkillItem.Type; // Get the level that unlock the recipe int?recipeUnlockLevel = RequiresSkillAttribute.Cache.Get(targetRecipeType).FirstOrDefault()?.Level; // Get the loc string for the recipe LocString locStr = new LocString(Text.Indent(targetRecipe.UILink())); // If there is a require skill if (skillType != null) { // Get the list of unlock for the skill for the unlock level List <LocString> unlocks = skillUnlocksTooltips[skillType][recipeUnlockLevel.Value]; // Search the correct unlock for (int i = 0; i < unlocks.Count; i++) { if (unlocks[i] == locStr) { // remove the loc string from the list unlocks.RemoveAt(i); break; } } // Set the new unlock list skillUnlocksTooltips[skillType][recipeUnlockLevel.Value] = unlocks; // For testing //List<Type> KeyA = new List<Type>(); //List<LocString> KeyB = new List<LocString>(); // Search all skill that benefit by the removed recipe foreach (var benefit in skillBenefitsTooltips) { for (int i = 0; i < benefit.Value.Count; i++) { var b = benefit.Value.ElementAt(i); // if the benefit is for a recipe if (b.Key == targetRecipe.UILink()) { //KeyA.Add(benefit.Key); //KeyB.Add(b.Key); b.Value.Clear(); // Update benefit list benefit.Value[b.Key] = b.Value; continue; } //if not we try to found benefit for an item foreach (var item in targetRecipe.Products) { LocString itemLocString = item.Item.UILink(); // if this benefit is benefit for an item on the recipe product if (b.Key == itemLocString) { //KeyA.Add(benefit.Key); //KeyB.Add(b.Key); // clear all the benefit for this recipe b.Value.Clear(); // Update benefit list benefit.Value[b.Key] = b.Value; break; } } } } /* * for (int i = 0; i < KeyA.Count; i++) * { * Console.WriteLine(KeyA[i]); * Console.WriteLine(KeyA[i]); * skillBenefitsTooltips[KeyA[i]][KeyB[i]].ForEach(x => Console.WriteLine(x)); * } */ } } }
public static void RemoveRecipe(Type pTargetRecipeType) { // Get all the existing recipe Dictionary <Type, Recipe[]> staticRecipes = (Dictionary <Type, Recipe[]>) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("staticRecipes")).GetValue(null); // Get all the recipe to table dicationary Dictionary <Type, List <Type> > recipeToTable = (Dictionary <Type, List <Type> >) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("recipeToTable")).GetValue(null); // Get all item to recipe dictionary Dictionary <Type, List <Recipe> > itemToRecipe = (Dictionary <Type, List <Recipe> >) typeof(CraftingComponent).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("itemToRecipe")).GetValue(null); lock (staticRecipes) { Type targetTable = CraftingComponent.TablesForRecipe(pTargetRecipeType).First(); Recipe targetRecipe = null; Recipe[] recipes; // Get all the recipe inside the table if (staticRecipes.TryGetValue(targetTable, out recipes)) { // Get the recipe targetRecipe = recipes.First(x => x.GetType() == pTargetRecipeType); // Remove the target recipe from the recipe list recipes = recipes.Where(x => x.GetType() != pTargetRecipeType).ToArray(); } // Set back the recipe inside the static recipe dictionnary staticRecipes[targetTable] = recipes; // Remove the recipe from the recipe to table dictionary recipeToTable[pTargetRecipeType].Remove(targetTable); // Remove the recipe from the item to recipe dictionary targetRecipe?.Products.ForEach(product => itemToRecipe[product.Item.Type].Remove(targetRecipe)); // Remove the table from the list of table // Only if there is no more recipe inside the table if (recipes.Length == 0) { CraftingComponent.AllTableWorldObjects.Remove(targetTable); } // After removing the recipe we need to update the skill unlock // Get all the skillunlock tooltips Dictionary <Type, Dictionary <int, List <LocString> > > skillUnlocksTooltips = (Dictionary <Type, Dictionary <int, List <LocString> > >) typeof(Skill).GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(x => x.Name.Contains("skillUnlocksTooltips")).GetValue(null); // Get the skill that unlock the recipe Type skillType = RequiresSkillAttribute.Cache.Get(pTargetRecipeType).FirstOrDefault()?.SkillItem.Type; // Get the level that unlock the recipe int?recipeUnlockLevel = RequiresSkillAttribute.Cache.Get(pTargetRecipeType).FirstOrDefault()?.Level; // If there is a require skill if (skillType != null && skillUnlocksTooltips.ContainsKey(skillType)) { // Get the list of unlock for the skill for the unlock level List <LocString> unlocks = skillUnlocksTooltips[skillType][recipeUnlockLevel.Value]; // Search the correct unlock for (int i = 0; i < unlocks.Count; i++) { if (unlocks[i] == new LocString(Text.Indent(targetRecipe.UILink()))) { // remove the loc string from the list unlocks.RemoveAt(i); break; } } // Set the new unlock list skillUnlocksTooltips[skillType][recipeUnlockLevel.Value] = unlocks; } FieldInfo fi = typeof(SkillModifiedValueManager).GetField("skillBenefits", BindingFlags.Static | BindingFlags.NonPublic); Dictionary <Type, Dictionary <LocString, List <SkillModifiedValue> > > benefits = (Dictionary <Type, Dictionary <LocString, List <SkillModifiedValue> > >)fi.GetValue(null); foreach (var benefitSkillEntry in benefits) { foreach (var entry in benefitSkillEntry.Value.ToArray()) { if (entry.Key.ToString().Contains("Recipe:" + pTargetRecipeType.FullName)) { benefitSkillEntry.Value.Remove(entry.Key); } } } } var allRecipes = Recipe.AllRecipes.ToList(); allRecipes.RemoveAll(r => r.GetType() == pTargetRecipeType); typeof(Recipe).GetProperty("AllRecipes", BindingFlags.Static | BindingFlags.Public).SetValue(null, allRecipes.ToArray()); RemoveFromDictionary("itemToRecipesWithProduct", pTargetRecipeType); RemoveFromDictionary("itemToRecipesWithIngredient", pTargetRecipeType); RemoveFromDictionary("skillToRecipes", pTargetRecipeType); RemoveFromDictionaryRecipeName(pTargetRecipeType); }
public static void TechTreeSimulation(User user) { var info = new InfoBuilder(); var data = new TechTreeSimData(); info.AppendLineLocStr("Starting Tech Tree Sim"); info.AppendLineLocStr("Getting Starting Skills..."); var introSkills = PlayerDefaults.GetDefaultSkills().ToList(); introSkills.ForEach(x => data.AddSkill(x)); info.AppendLineLocStr("Getting Initial Tables..."); data.CraftingTables.Add(typeof(CampsiteObject)); info.AppendLineLocStr("Getting Recipes with No Skills..."); data.UnusableRecipes.AddRange(RecipeFamily.AllRecipes.SelectMany(x => x.Recipes).Where(x => !x.Family.RequiredSkills.Any() && x.Ingredients.Any())); info.AppendLineLocStr("Getting World Resources..."); //manually defined for now since theres no easy way of checking for these data.AddItems(new List <Type> { typeof(DirtItem), typeof(SandItem), typeof(IronOreItem), typeof(CopperOreItem), typeof(GoldOreItem), typeof(CoalItem), typeof(ClayItem) }); // Add all items with "Rock" tag data.AddItems(TagManager.TagToTypes[TagManager.Tag("Rock")]); info.AppendLineLocStr("Getting Species Resources..."); var resourceless = new List <Species>(); EcoSim.AllSpecies.ForEach(x => { var speciesInfo = new InfoBuilder(); AddNewResources(speciesInfo, x.ResourceList.Select(x => x.ResourceType), data); if (x is TreeSpecies treeSpecies) { AddNewResources(speciesInfo, treeSpecies.TrunkResources.Keys, data); AddNewResources(speciesInfo, treeSpecies.DebrisResources.Keys, data); } if (speciesInfo.IsEmpty) { resourceless.Add(x); speciesInfo.AppendLineLocStr("No resources"); } info.AddSectionLoc($"Adding Species: {x.DisplayName}", speciesInfo); }); info.AppendLine(); info.AppendLineLocStr("Simulating..."); info.AppendLine(); UpdateRecipes(info, data); UpdateRecipesFromSkills(info, data); info.AppendLine(); info.AppendLineLocStr("Tech Tree Sim Complete"); ChatManager.SendChat(CheckStatus(info, data) ? "Tech Tree Complete" : "Tech Tree Failed, check the TechTreeSimulation.txt for more information.", user); //get issues with complete //PLANT DATA info.AppendLineLocStr("Plants Missing Resources"); info.AppendLine(Localizer.NotLocalizedStr(string.Join(",", resourceless))); //CRAFTABLES var uncraftableAccessed = new InfoBuilder(); foreach (var recipe in data.UnusableRecipes) { var recipeInfo = new InfoBuilder(); ReportMissingIngredients(recipeInfo, recipe, data); if (!CraftingComponent.TablesForRecipe(recipe.Family.GetType()).Intersect(data.CraftingTables).Any()) { recipeInfo.AppendLineLocStr("- missing crafting table"); } uncraftableAccessed.AddSection(recipe.DisplayName, recipeInfo); } info.AppendLine(); info.AddSectionLocStr("Uncraftable Accessed", uncraftableAccessed); var uncraftableUnaccessed = new InfoBuilder(); foreach (var recipe in RecipeFamily.AllRecipes.SelectMany(x => x.Recipes).Except(data.CurRecipes)) { var recipeInfo = new InfoBuilder(); var missingSkillsInfo = new InfoBuilder(); foreach (var skill in recipe.Family.RequiredSkills) { if (!data.CurSkills.Contains(skill.SkillType)) { missingSkillsInfo.AppendLine(skill.SkillItem.DisplayName); } } recipeInfo.AddSectionLocStr("- missing skills:", missingSkillsInfo); ReportMissingIngredients(recipeInfo, recipe, data); // notify about missing crafting table if (!CraftingComponent.TablesForRecipe(recipe.Family.GetType()).Intersect(data.CraftingTables).Any()) { recipeInfo.AppendLineLocStr("- missing crafting table"); } uncraftableUnaccessed.AddSection(recipe.DisplayName, recipeInfo); } info.AppendLine(); info.AddSectionLocStr("Uncraftable Unaccessed", uncraftableUnaccessed); //ALL UNOBTAINABLE ITEMS info.AppendLine(); info.AppendLineLocStr("Unobtainable Items"); foreach (var item in Item.AllItems .Where(x => !(x is Skill) && !(x is ActionbarItem) && !(x is SkillScroll) && !x.Hidden) .Select(x => x.Type) .Except(data.CraftableItems)) { info.AppendLineLocStr(" " + item.Name); } using var sw = new StreamWriter("TechTreeSimulation.txt"); sw.Write(info.ToLocString()); }