fix lotta bugs

This commit is contained in:
austin 2025-05-11 15:25:11 -04:00
parent 3df3beafba
commit d733b3c46f
14 changed files with 291 additions and 173 deletions

View File

@ -1727,6 +1727,10 @@ Fix viewport loading
Database warning handling Database warning handling
In memory database support In memory database support
Fix test utils creating characters Fix test utils creating characters
Fix server simulation starting prior to database connection
Scaffolding macro character simulation
Fix block generation thread filtering repairable structures
Catch errors in pathfinding threads

View File

@ -73,14 +73,14 @@ public class MacroCharacterGoalNode implements AITreeNode {
case BUILD_STRUCTURE: { case BUILD_STRUCTURE: {
Object targetRaw = goal.getTarget(); Object targetRaw = goal.getTarget();
if(!(targetRaw instanceof Structure)){ if(!(targetRaw instanceof Structure)){
throw new Error("Target is not a structure " + targetRaw); return AITreeNodeResult.FAILURE;
} }
BeginStructureNode.setStructureTarget(blackboard, (Structure)goal.getTarget()); BeginStructureNode.setStructureTarget(blackboard, (Structure)goal.getTarget());
} break; } break;
case ACQUIRE_ITEM: { case ACQUIRE_ITEM: {
Object targetRaw = goal.getTarget(); Object targetRaw = goal.getTarget();
if(!(targetRaw instanceof String)){ if(!(targetRaw instanceof String)){
throw new Error("Target is not a string " + targetRaw); return AITreeNodeResult.FAILURE;
} }
blackboard.put(BlackboardKeys.GOAL_ITEM_ACQUISITION_TARGET, targetRaw); blackboard.put(BlackboardKeys.GOAL_ITEM_ACQUISITION_TARGET, targetRaw);
} break; } break;

View File

@ -32,10 +32,16 @@ public class PathfindingService implements AIService {
public PathingProgressiveData queuePathfinding(Vector3d start, Vector3d end, VoxelPathfinder pathfinder, VoxelCellManager voxelCellManager){ public PathingProgressiveData queuePathfinding(Vector3d start, Vector3d end, VoxelPathfinder pathfinder, VoxelCellManager voxelCellManager){
PathingProgressiveData rVal = new PathingProgressiveData(end); PathingProgressiveData rVal = new PathingProgressiveData(end);
executorService.submit(() -> { executorService.submit(() -> {
List<Vector3d> points = pathfinder.findPath(voxelCellManager, start, end, VoxelPathfinder.DEFAULT_MAX_COST); try {
points.add(end); List<Vector3d> points = pathfinder.findPath(voxelCellManager, start, end, VoxelPathfinder.DEFAULT_MAX_COST);
rVal.setPoints(points); points.add(end);
rVal.setReady(true); rVal.setPoints(points);
rVal.setReady(true);
} catch(Error e){
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}); });
return rVal; return rVal;
} }

View File

@ -257,7 +257,7 @@ public class Realm {
// //
//macro data simulation //macro data simulation
if(this.macroData != null){ if(this.macroData != null && Globals.dbController != null && Globals.dbController.isConnected()){
MacroSimulation.simulate(this); MacroSimulation.simulate(this);
} }

View File

@ -1233,4 +1233,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
return this.groundDataCells.values().contains(cell); return this.groundDataCells.values().contains(cell);
} }
@Override
public boolean hasBlocksAtPosition(Vector3i worldPosition) {
return this.serverWorldData.getServerBlockManager().hasChunk(worldPosition.x, worldPosition.y, worldPosition.z);
}
} }

View File

@ -59,6 +59,13 @@ public interface VoxelCellManager {
*/ */
public BlockChunkData getBlocksAtPosition(Vector3i worldPosition); public BlockChunkData getBlocksAtPosition(Vector3i worldPosition);
/**
* Checks if the manager has already-generated blocks at a given position
* @param worldPosition The position
* @return true if there are blocks at the position, false otherwise
*/
public boolean hasBlocksAtPosition(Vector3i worldPosition);
/** /**
* Edits a single block voxel * Edits a single block voxel
* @param worldPosition The world position of the block to edit * @param worldPosition The world position of the block to edit

View File

@ -10,6 +10,7 @@ import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
import electrosphere.server.macro.character.diety.Diety; import electrosphere.server.macro.character.diety.Diety;
import electrosphere.server.macro.character.goal.CharacterGoal;
import electrosphere.server.macro.race.Race; import electrosphere.server.macro.race.Race;
import electrosphere.server.macro.town.Town; import electrosphere.server.macro.town.Town;
@ -34,10 +35,16 @@ public class CharacterDataSerializer implements JsonDeserializer<CharacterData>,
} }
//a structure //a structure
case CharacterDataStrings.STRUCTURE_ID: { case CharacterDataStrings.STRUCTURE_ID:
case CharacterDataStrings.SHELTER: {
return context.deserialize(json, CharacterAssociatedId.class); return context.deserialize(json, CharacterAssociatedId.class);
} }
//goal
case CharacterDataStrings.ENTITY_GOAL: {
return context.deserialize(json, CharacterGoal.class);
}
//a town //a town
case CharacterDataStrings.TOWN: { case CharacterDataStrings.TOWN: {
return context.deserialize(json, Town.class); return context.deserialize(json, Town.class);
@ -64,11 +71,7 @@ public class CharacterDataSerializer implements JsonDeserializer<CharacterData>,
} }
//a structure //a structure
case CharacterDataStrings.STRUCTURE_ID: { case CharacterDataStrings.STRUCTURE_ID:
return context.serialize((CharacterAssociatedId)src);
}
//a structure
case CharacterDataStrings.SHELTER: { case CharacterDataStrings.SHELTER: {
return context.serialize((CharacterAssociatedId)src); return context.serialize((CharacterAssociatedId)src);
} }
@ -78,6 +81,11 @@ public class CharacterDataSerializer implements JsonDeserializer<CharacterData>,
return context.serialize((Town)src); return context.serialize((Town)src);
} }
//goal
case CharacterDataStrings.ENTITY_GOAL: {
return context.serialize((CharacterGoal)src);
}
default: { default: {
throw new Error("Failed to serialize datatype: " + src.getDataType()); throw new Error("Failed to serialize datatype: " + src.getDataType());
} }

View File

@ -64,6 +64,10 @@ public class StructureRepairUtils {
public static String getNextRepairMat(Realm realm, Structure struct){ public static String getNextRepairMat(Realm realm, Structure struct){
Vector3i repairPos = StructureRepairUtils.getRepairablePosition(realm, struct); Vector3i repairPos = StructureRepairUtils.getRepairablePosition(realm, struct);
if(repairPos == null){
return null;
}
//get the id of item entity type for the block we need //get the id of item entity type for the block we need
BlockFab fab = struct.getFab(); BlockFab fab = struct.getFab();
short blockTypeId = fab.getType(repairPos.x, repairPos.y, repairPos.z); short blockTypeId = fab.getType(repairPos.x, repairPos.y, repairPos.z);
@ -131,6 +135,8 @@ public class StructureRepairUtils {
); );
Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(offsetPos); Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(offsetPos);
Vector3i blockPos = ServerWorldData.convertRealToLocalBlockSpace(offsetPos); Vector3i blockPos = ServerWorldData.convertRealToLocalBlockSpace(offsetPos);
//check existing blocks
BlockChunkData blockChunkData = griddedDataCellManager.getBlocksAtPosition(chunkPos); BlockChunkData blockChunkData = griddedDataCellManager.getBlocksAtPosition(chunkPos);
short existingBlockType = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z); short existingBlockType = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
short desiredType = fab.getType(x, y, z); short desiredType = fab.getType(x, y, z);

View File

@ -164,7 +164,7 @@ public class ServerBlockChunkGenerationThread implements Runnable {
} }
//check if this chunk intersects any macro data //check if this chunk intersects any macro data
AABBd localAABB = new AABBd(ServerWorldData.convertChunkToRealSpace(worldX,worldY,worldZ),ServerWorldData.convertChunkToRealSpace(worldX+1,worldY+1,worldZ+1)); AABBd localAABB = new AABBd(ServerWorldData.convertChunkToRealSpace(worldX,worldY,worldZ),ServerWorldData.convertChunkToRealSpace(worldX+1,worldY+1,worldZ+1));
List<Structure> filtered = macroData.getStructures().stream().filter((Structure struct) -> {return struct.isRepairable() || struct.getAABB().testAABB(localAABB);}).collect(Collectors.toList()); List<Structure> filtered = macroData.getStructures().stream().filter((Structure struct) -> {return !struct.isRepairable() && struct.getAABB().testAABB(localAABB);}).collect(Collectors.toList());
if(filtered.size() > 0){ if(filtered.size() > 0){
Vector3i chunkPos = new Vector3i(worldX, worldY, worldZ); Vector3i chunkPos = new Vector3i(worldX, worldY, worldZ);
Vector3i blockPos = new Vector3i(0,0,0); Vector3i blockPos = new Vector3i(0,0,0);

View File

@ -147,6 +147,17 @@ public class ServerBlockManager {
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
/**
* Checks if there is an already-generated chunk at the position
* @param worldX The world x coordinate
* @param worldY The world y coordinate
* @param worldZ The world z coordinate
* @return true if the chunk exists, false otherwise
*/
public boolean hasChunk(int worldX, int worldY, int worldZ){
return chunkDiskMap.containsBlocksAtPosition(worldX, worldY, worldZ) || chunkCache.containsChunk(worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES);
}
/** /**
* Saves a given position's chunk to disk. * Saves a given position's chunk to disk.
* Uses the current global save name * Uses the current global save name

View File

@ -165,6 +165,9 @@ public class SaveUtils {
//write server structures //write server structures
Globals.realmManager.save(saveName); Globals.realmManager.save(saveName);
//store character service
Globals.characterService.saveAll();
LoggerInterface.loggerEngine.WARNING("Finished saving " + saveName); LoggerInterface.loggerEngine.WARNING("Finished saving " + saveName);
} }

View File

@ -248,4 +248,31 @@ public class CharacterService extends SignalServiceImpl {
lock.unlock(); lock.unlock();
} }
/**
* Saves the character service
*/
public void saveAll(){
lock.lock();
for(Character chara : this.loadedCharacterMap.values()){
CreatureTemplate template = chara.getCreatureTemplate();
if(this.characterEntityMap.containsKey(chara)){
Entity characterEntity = this.characterEntityMap.get(chara);
template = CreatureUtils.getCreatureTemplate(characterEntity);
chara.setCreatureTemplate(template);
chara.setPos(EntityUtils.getPosition(characterEntity));
}
//serialize
String toStore = SerializationUtils.serialize(chara);
//store a serialization to associate with the character
Globals.dbController.executePreparedStatement(
"UPDATE charaData SET dataVal=? WHERE id=?;",
toStore,
chara.getId()
);
}
lock.unlock();
}
} }

View File

@ -2,24 +2,11 @@ package electrosphere.server.simulation;
import java.util.List; import java.util.List;
import org.joml.Vector3d;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.game.data.block.BlockFab;
import electrosphere.game.data.struct.StructureData;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.character.Character; import electrosphere.server.macro.character.Character;
import electrosphere.server.macro.character.CharacterUtils;
import electrosphere.server.macro.character.data.CharacterDataStrings;
import electrosphere.server.macro.character.goal.CharacterGoal;
import electrosphere.server.macro.character.goal.CharacterGoal.CharacterGoalType;
import electrosphere.server.macro.structure.Structure;
import electrosphere.server.macro.utils.StructurePlacementUtils;
import electrosphere.server.macro.utils.StructureRepairUtils;
import electrosphere.server.service.CharacterService; import electrosphere.server.service.CharacterService;
import electrosphere.server.simulation.chara.CharaInventoryUtils; import electrosphere.server.simulation.chara.CharaSimulation;
import electrosphere.util.FileUtils;
/** /**
* Performs the macro-level (ie virtual, non-physics based) simulation * Performs the macro-level (ie virtual, non-physics based) simulation
@ -41,9 +28,12 @@ public class MacroSimulation {
if(character.getPlayerId() != CharacterService.NO_PLAYER){ if(character.getPlayerId() != CharacterService.NO_PLAYER){
continue; continue;
} }
//do something //update the goal of the character
MacroSimulation.checkForShelter(realm, character); CharaSimulation.setGoal(realm, character);
MacroSimulation.checkTownMembership(character); //if the character doesn't have an entity, simulate it at the macro level
if(Globals.characterService.getEntity(character) == null){
CharaSimulation.performGoal(realm, character);
}
} }
} }
} }
@ -64,146 +54,4 @@ public class MacroSimulation {
return isReady; return isReady;
} }
/**
* Maximum attempts to place a structure
*/
static final int MAX_PLACE_ATTEMPTS = 10;
protected static void checkForShelter(Realm realm, Character chara){
MacroData macroData = realm.getMacroData();
// for(Character chara : Globals.macroData.getAliveCharacters()){
/*
If doesnt have shelter, check if in town
If in town,
check if theres an inn/church/friendly family
if so, try to stay there
if cant find place to stay, fashion makeshift shelter
If no town
fashion makeshift shelter
*/
if(CharacterUtils.getShelter(macroData,chara) != null){
Structure shelter = CharacterUtils.getShelter(macroData,chara);
if(shelter.isRepairable()){
if(StructureRepairUtils.validateRepairable(realm, shelter)){
String repairMat = StructureRepairUtils.getNextRepairMat(realm, shelter);
if(CharaInventoryUtils.containsItem(chara, repairMat)){
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.BUILD_STRUCTURE, shelter));
} else {
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.ACQUIRE_ITEM, repairMat));
}
} else {
shelter.setRepairable(false);
}
}
// Vector2i charPos = CharacterUtils.getDiscretePosition(chara);
// Town nearbyTown = Town.getTownAtPosition(charPos.x,charPos.y);
// if(nearbyTown != null){
// //if town has a place to stay
// if(false){
// } else {
// //try to find a place to put down a structure
// }
} else {
Vector3d position = chara.getPos();
StructureData structureData = Globals.gameConfigCurrent.getStructureData().getTypes().iterator().next();
//solve where to place
Vector3d placementPos = StructurePlacementUtils.getPlacementPosition(macroData, structureData, position);
//add to macro data
Structure struct = Structure.createStructure(macroData, structureData, placementPos);
struct.setRepairable(true);
struct.setFab(BlockFab.read(FileUtils.getAssetFile(struct.getFabPath())));
CharacterUtils.addShelter(chara, struct);
//target the struct
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.BUILD_STRUCTURE, struct));
// //cry
// //TODO: Get building type to place
// String buildingTypeToPlace = "building1";
// //try to find a place to put down a structure
// // int dynamicInterpRatio = Globals.serverTerrainManager.getDynamicInterpolationRatio();
// // Vector2f placementPos = new Vector2f(
// // (float)(charPos.x * dynamicInterpRatio + Math.random() * dynamicInterpRatio),
// // (float)(charPos.y * dynamicInterpRatio + Math.random() * dynamicInterpRatio)
// // );
// // int attempts = 0;
// // while(!VirtualStructureUtils.validStructurePlacementPosition(placementPos.x, placementPos.y, buildingTypeToPlace)){
// // placementPos = new Vector2f(
// // (float)(charPos.x * dynamicInterpRatio + Math.random() * dynamicInterpRatio),
// // (float)(charPos.y * dynamicInterpRatio + Math.random() * dynamicInterpRatio)
// // );
// // attempts++;
// // if(attempts > MAX_PLACE_ATTEMPTS){
// // placementPos = null;
// // break;
// // }
// // }
// // if(placementPos != null){
// // // Structure placedStructure = VirtualStructureUtils.placeStructureAtPoint(placementPos.x, placementPos.y, buildingTypeToPlace);
// // // CharacterUtils.addShelter(chara, placedStructure);
// // // VirtualStructureUtils.addResident(placedStructure, chara);
// // }
// }
}
// }
}
protected static void checkTownMembership(Character chara){
//TODO: eventually exclude people who shouldn't belong to a town (traders, bandits, etc)
// for(Character chara : Globals.macroData.getAliveCharacters()){
boolean hasHometown = chara.containsKey(CharacterDataStrings.HOMETOWN);
boolean hasShelter = chara.containsKey(CharacterDataStrings.SHELTER);
//if has structure & no hometown
if(!hasHometown && hasShelter){
// Structure shelter = CharacterUtils.getShelter(chara);
//if there's at least one other structure nearby
// Vector2i shelterDiscretePos = new Vector2i(shelter.getWorldX(),shelter.getWorldY());
// List<Structure> nearbyPopulatedStructures = new LinkedList<Structure>();
// for(Structure currentStruct : Globals.macroData.getStructures()){
// if(currentStruct.getWorldX() == shelterDiscretePos.x && currentStruct.getWorldY() == shelterDiscretePos.y && currentStruct != shelter){
// //if has a resident
// if(shelter.getDataKeys().contains(StructureDataStrings.RESIDENTS) && VirtualStructureUtils.getResidents(shelter).size() > 0){
// boolean noTown = true;
// for(Town town : Globals.macroData.getTowns()){
// if(town.getStructures().contains(currentStruct)){
// noTown = false;
// }
// }
// if(noTown){
// nearbyPopulatedStructures.add(currentStruct);
// }
// }
// }
// }
// if(nearbyPopulatedStructures.size() > 0){
// int numStructures = 0;
// int numResidents = 0;
// //form town
// Town newTown = Town.createTown(shelterDiscretePos.x, shelterDiscretePos.y);
// for(Structure structure : nearbyPopulatedStructures){
// numStructures++;
// newTown.addStructure(structure);
// for(Character resident : VirtualStructureUtils.getResidents(structure)){
// numResidents++;
// newTown.addResident(resident);
// CharacterUtils.addHometown(resident, newTown);
// }
// }
// newTown.addStructure(shelter);
// newTown.addResident(chara);
// CharacterUtils.addHometown(chara, newTown);
// System.out.println("Formed town with " + numStructures + " structures and " + numResidents + " residents");
// }
}
// }
}
// private static void checkInitCombat(){
// for(Character chara : Globals.macroData.getAliveCharacters()){
// // Vector2i position = CharacterUtils.getDiscretePosition(chara);
// }
// }
} }

View File

@ -0,0 +1,193 @@
package electrosphere.server.simulation.chara;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.game.data.block.BlockFab;
import electrosphere.game.data.struct.StructureData;
import electrosphere.server.datacell.Realm;
import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.character.Character;
import electrosphere.server.macro.character.CharacterUtils;
import electrosphere.server.macro.character.data.CharacterDataStrings;
import electrosphere.server.macro.character.goal.CharacterGoal;
import electrosphere.server.macro.character.goal.CharacterGoal.CharacterGoalType;
import electrosphere.server.macro.structure.Structure;
import electrosphere.server.macro.utils.StructurePlacementUtils;
import electrosphere.server.macro.utils.StructureRepairUtils;
import electrosphere.util.FileUtils;
/**
* Methods for simulating characters
*/
public class CharaSimulation {
/**
* Sets the goal of the character
* @param realm The realm
* @param chara The character
*/
public static void setGoal(Realm realm, Character chara){
CharaSimulation.checkForShelter(realm, chara);
}
/**
* Maximum attempts to place a structure
*/
static final int MAX_PLACE_ATTEMPTS = 10;
/**
* Checks if the character has shelter
* @param realm The realm
* @param chara The character
*/
protected static void checkForShelter(Realm realm, Character chara){
MacroData macroData = realm.getMacroData();
// for(Character chara : Globals.macroData.getAliveCharacters()){
/*
If doesnt have shelter, check if in town
If in town,
check if theres an inn/church/friendly family
if so, try to stay there
if cant find place to stay, fashion makeshift shelter
If no town
fashion makeshift shelter
*/
if(CharacterUtils.getShelter(macroData,chara) != null){
Structure shelter = CharacterUtils.getShelter(macroData,chara);
if(shelter.isRepairable()){
if(StructureRepairUtils.validateRepairable(realm, shelter)){
String repairMat = StructureRepairUtils.getNextRepairMat(realm, shelter);
if(CharaInventoryUtils.containsItem(chara, repairMat)){
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.BUILD_STRUCTURE, shelter));
} else {
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.ACQUIRE_ITEM, repairMat));
}
} else {
shelter.setRepairable(false);
}
}
// Vector2i charPos = CharacterUtils.getDiscretePosition(chara);
// Town nearbyTown = Town.getTownAtPosition(charPos.x,charPos.y);
// if(nearbyTown != null){
// //if town has a place to stay
// if(false){
// } else {
// //try to find a place to put down a structure
// }
} else {
Vector3d position = chara.getPos();
StructureData structureData = Globals.gameConfigCurrent.getStructureData().getTypes().iterator().next();
//solve where to place
Vector3d placementPos = StructurePlacementUtils.getPlacementPosition(macroData, structureData, position);
//add to macro data
Structure struct = Structure.createStructure(macroData, structureData, placementPos);
struct.setRepairable(true);
struct.setFab(BlockFab.read(FileUtils.getAssetFile(struct.getFabPath())));
CharacterUtils.addShelter(chara, struct);
//target the struct
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.BUILD_STRUCTURE, struct));
// //cry
// //TODO: Get building type to place
// String buildingTypeToPlace = "building1";
// //try to find a place to put down a structure
// // int dynamicInterpRatio = Globals.serverTerrainManager.getDynamicInterpolationRatio();
// // Vector2f placementPos = new Vector2f(
// // (float)(charPos.x * dynamicInterpRatio + Math.random() * dynamicInterpRatio),
// // (float)(charPos.y * dynamicInterpRatio + Math.random() * dynamicInterpRatio)
// // );
// // int attempts = 0;
// // while(!VirtualStructureUtils.validStructurePlacementPosition(placementPos.x, placementPos.y, buildingTypeToPlace)){
// // placementPos = new Vector2f(
// // (float)(charPos.x * dynamicInterpRatio + Math.random() * dynamicInterpRatio),
// // (float)(charPos.y * dynamicInterpRatio + Math.random() * dynamicInterpRatio)
// // );
// // attempts++;
// // if(attempts > MAX_PLACE_ATTEMPTS){
// // placementPos = null;
// // break;
// // }
// // }
// // if(placementPos != null){
// // // Structure placedStructure = VirtualStructureUtils.placeStructureAtPoint(placementPos.x, placementPos.y, buildingTypeToPlace);
// // // CharacterUtils.addShelter(chara, placedStructure);
// // // VirtualStructureUtils.addResident(placedStructure, chara);
// // }
// }
}
// }
}
protected static void checkTownMembership(Character chara){
//TODO: eventually exclude people who shouldn't belong to a town (traders, bandits, etc)
// for(Character chara : Globals.macroData.getAliveCharacters()){
boolean hasHometown = chara.containsKey(CharacterDataStrings.HOMETOWN);
boolean hasShelter = chara.containsKey(CharacterDataStrings.SHELTER);
//if has structure & no hometown
if(!hasHometown && hasShelter){
// Structure shelter = CharacterUtils.getShelter(chara);
//if there's at least one other structure nearby
// Vector2i shelterDiscretePos = new Vector2i(shelter.getWorldX(),shelter.getWorldY());
// List<Structure> nearbyPopulatedStructures = new LinkedList<Structure>();
// for(Structure currentStruct : Globals.macroData.getStructures()){
// if(currentStruct.getWorldX() == shelterDiscretePos.x && currentStruct.getWorldY() == shelterDiscretePos.y && currentStruct != shelter){
// //if has a resident
// if(shelter.getDataKeys().contains(StructureDataStrings.RESIDENTS) && VirtualStructureUtils.getResidents(shelter).size() > 0){
// boolean noTown = true;
// for(Town town : Globals.macroData.getTowns()){
// if(town.getStructures().contains(currentStruct)){
// noTown = false;
// }
// }
// if(noTown){
// nearbyPopulatedStructures.add(currentStruct);
// }
// }
// }
// }
// if(nearbyPopulatedStructures.size() > 0){
// int numStructures = 0;
// int numResidents = 0;
// //form town
// Town newTown = Town.createTown(shelterDiscretePos.x, shelterDiscretePos.y);
// for(Structure structure : nearbyPopulatedStructures){
// numStructures++;
// newTown.addStructure(structure);
// for(Character resident : VirtualStructureUtils.getResidents(structure)){
// numResidents++;
// newTown.addResident(resident);
// CharacterUtils.addHometown(resident, newTown);
// }
// }
// newTown.addStructure(shelter);
// newTown.addResident(chara);
// CharacterUtils.addHometown(chara, newTown);
// System.out.println("Formed town with " + numStructures + " structures and " + numResidents + " residents");
// }
}
// }
}
// private static void checkInitCombat(){
// for(Character chara : Globals.macroData.getAliveCharacters()){
// // Vector2i position = CharacterUtils.getDiscretePosition(chara);
// }
// }
/**
* Performs whatever the current goal of the character is
* @param realm The realm
* @param chara The character
*/
public static void performGoal(Realm realm, Character chara){
//todo -- acquire item logic
}
}