recursive recipe solver
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-05-04 19:01:06 -04:00
parent d29f51c509
commit c0627bf3fb
6 changed files with 104 additions and 42 deletions

View File

@ -1675,6 +1675,7 @@ Terrain items
Digging produces terrain item form Digging produces terrain item form
Terrain items can be placed to place terrain Terrain items can be placed to place terrain
Recipe adjustment + voxel work Recipe adjustment + voxel work
Recursive recipe item sourcing solver that keeps searching if a recipe fails to source

View File

@ -81,49 +81,77 @@ public class ItemSourcingTree {
return this.itemSourceMap.get(this.rootItemId); return this.itemSourceMap.get(this.rootItemId);
} }
String currentRootId = this.rootItemId; String currentRootId = this.rootItemId;
while(currentRootId != null){ return this.getCurrentDependencyRecursive(entity,itemIds,currentRootId);
ItemSourcingData sourcingData = this.itemSourceMap.get(currentRootId); }
if(sourcingData == null){
throw new Error("Failed to find sourcing data for " + currentRootId);
}
if(sourcingData.harvestTargets.size() > 0){
return sourcingData;
}
if(sourcingData.trees.size() > 0){
//if we don't have an axe in inventory, consider it a dependency
if(!InventoryUtils.serverHasTool(entity, CommonEntityTokens.TOKEN_AXE)){
currentRootId = ItemIdStrings.ITEM_STONE_AXE;
continue;
}
//we have an axe, return this sourcing data
return sourcingData;
}
currentRootId = null; /**
if(sourcingData.recipes.size() > 0){ * Gets the sourcing data for the current dependency
boolean foundAllIngredients = true; * @param entity The entity to check
RecipeData craftableRecipe = null; * @param inventoryIds The contents of the entity's inventory
for(RecipeData recipeData : sourcingData.recipes){ * @param currentRoot The current root item to search for
//check if we have all the ingredients to craft this item * @return The sourcing data for the current dependency
foundAllIngredients = true; */
for(RecipeIngredientData ingredient : recipeData.getIngredients()){ private ItemSourcingData getCurrentDependencyRecursive(Entity entity, List<String> inventoryIds, String currentRoot){
if(!itemIds.contains(ingredient.getItemType())){ ItemSourcingData sourcingData = this.itemSourceMap.get(currentRoot);
//ingredient is not in inventory if(sourcingData == null){
foundAllIngredients = false; throw new Error("Failed to find sourcing data for " + currentRoot);
currentRootId = ingredient.getItemType(); }
break; if(sourcingData.harvestTargets.size() > 0){
} return sourcingData;
} }
if(foundAllIngredients){ if(sourcingData.trees.size() > 0){
craftableRecipe = recipeData; //if we don't have an axe in inventory, consider it a dependency
if(!InventoryUtils.serverHasTool(entity, CommonEntityTokens.TOKEN_AXE)){
ItemSourcingData axeSource = this.getCurrentDependencyRecursive(entity, inventoryIds, ItemIdStrings.ITEM_STONE_AXE);
return axeSource;
}
//we have an axe, return this sourcing data
return sourcingData;
}
if(sourcingData.recipes.size() > 0){
//the ingredient to source if we don't have all ingredients
ItemSourcingData ingredientToSource = null;
//whether we have all ingredients already or not
boolean foundAllIngredients = false;
//whether the recipe is source-able at all
boolean recipeIsSourceable = true;
//the recipe
RecipeData craftableRecipe = null;
for(RecipeData recipeData : sourcingData.recipes){
//check if we have all the ingredients to craft this item
foundAllIngredients = true;
recipeIsSourceable = true;
ingredientToSource = null;
for(RecipeIngredientData ingredient : recipeData.getIngredients()){
ItemSourcingData sourcingForCurrentReagent = this.getCurrentDependencyRecursive(entity, inventoryIds, ingredient.getItemType());
if(sourcingForCurrentReagent == null){
recipeIsSourceable = false;
break; break;
} }
if(!inventoryIds.contains(ingredient.getItemType())){
//ingredient is not in inventory
foundAllIngredients = false;
ingredientToSource = sourcingForCurrentReagent;
}
} }
if(craftableRecipe != null){ if(!recipeIsSourceable){
return sourcingData; continue;
}
if(foundAllIngredients){
craftableRecipe = recipeData;
break;
} else {
return ingredientToSource;
} }
} }
if(craftableRecipe != null){
return sourcingData;
}
} }
//unable to source this item
return null; return null;
} }

View File

@ -39,7 +39,7 @@ public class SolveSourcingTreeNode implements AITreeNode {
ItemSourcingTree sourcingTree = SolveSourcingTreeNode.getItemSourcingTree(blackboard); ItemSourcingTree sourcingTree = SolveSourcingTreeNode.getItemSourcingTree(blackboard);
ItemSourcingData sourcingData = sourcingTree.getCurrentDependency(entity); ItemSourcingData sourcingData = sourcingTree.getCurrentDependency(entity);
if(sourcingData == null){ if(sourcingData == null){
throw new Error("Source data is null!"); throw new Error("Source data is null! " + itemId);
} }
//set the type to harvest if this is a harvest type //set the type to harvest if this is a harvest type
if(sourcingData.getHarvestTargets().size() > 0){ if(sourcingData.getHarvestTargets().size() > 0){

View File

@ -48,10 +48,9 @@ public class CharacterService {
public static CreatureTemplate getTemplate(int playerId, int characterId){ public static CreatureTemplate getTemplate(int playerId, int characterId){
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=? AND id=?;",playerId, characterId); DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=? AND id=?;",playerId, characterId);
if(result.hasResult()){ if(result.hasResult()){
Gson gson = new Gson();
//if we get a valid response from the database, check that it actually matches hashes //if we get a valid response from the database, check that it actually matches hashes
for(DatabaseResultRow row : result){ for(DatabaseResultRow row : result){
CreatureTemplate template = gson.fromJson(row.getAsString("dataVal"),CreatureTemplate.class); CreatureTemplate template = SerializationUtils.deserialize(row.getAsString("dataVal"),CreatureTemplate.class);
return template; return template;
} }
} }
@ -66,13 +65,12 @@ public class CharacterService {
*/ */
public static List<CharacterDescription> getCharacters(int playerId){ public static List<CharacterDescription> getCharacters(int playerId){
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=?;",playerId); DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData WHERE playerId=?;",playerId);
Gson gson = new Gson();
List<CharacterDescription> rVal = new LinkedList<CharacterDescription>(); List<CharacterDescription> rVal = new LinkedList<CharacterDescription>();
if(result.hasResult()){ if(result.hasResult()){
//if we get a valid response from the database, check that it actually matches hashes //if we get a valid response from the database, check that it actually matches hashes
for(DatabaseResultRow row : result){ for(DatabaseResultRow row : result){
CharacterDescription description = new CharacterDescription(); CharacterDescription description = new CharacterDescription();
CreatureTemplate template = gson.fromJson(row.getAsString("dataVal"),CreatureTemplate.class); CreatureTemplate template = SerializationUtils.deserialize(row.getAsString("dataVal"),CreatureTemplate.class);
description.setTemplate(template); description.setTemplate(template);
description.setId(row.getAsInteger("id") + ""); description.setId(row.getAsInteger("id") + "");
rVal.add(description); rVal.add(description);
@ -150,4 +148,24 @@ public class CharacterService {
); );
} }
/**
* Gets all characters
* @return The list of all characters
*/
public static List<CharacterDescription> getAllCharacters(){
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, dataVal FROM charaData");
List<CharacterDescription> rVal = new LinkedList<CharacterDescription>();
if(result.hasResult()){
//if we get a valid response from the database, check that it actually matches hashes
for(DatabaseResultRow row : result){
CharacterDescription description = new CharacterDescription();
CreatureTemplate template = SerializationUtils.deserialize(row.getAsString("dataVal"),CreatureTemplate.class);
description.setTemplate(template);
description.setId(row.getAsInteger("id") + "");
rVal.add(description);
}
}
return rVal;
}
} }

View File

@ -21,7 +21,6 @@ import electrosphere.util.FileUtils;
import java.util.Random; import java.util.Random;
import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
/** /**

View File

@ -1,8 +1,12 @@
package electrosphere.server.macro; package electrosphere.server.macro;
import java.io.File; import java.io.File;
import java.util.List;
import electrosphere.client.entity.character.CharacterDescription;
import electrosphere.game.data.block.BlockFab; import electrosphere.game.data.block.BlockFab;
import electrosphere.server.character.CharacterService;
import electrosphere.server.macro.character.Character;
import electrosphere.server.macro.structure.Structure; import electrosphere.server.macro.structure.Structure;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
@ -33,6 +37,18 @@ public class MacroDataLoader {
structure.setFab(fab); structure.setFab(fab);
} }
//inject characters from character service
List<CharacterDescription> characters = CharacterService.getAllCharacters();
for(CharacterDescription desc : characters){
int targetId = Integer.parseInt(desc.getId());
Character macroCharacter = rVal.getCharacter(targetId);
if(macroCharacter == null){
macroCharacter = new Character();
macroCharacter.setId(targetId);
rVal.characters.add(macroCharacter);
}
}
return rVal; return rVal;
} }