macro structure data definitions
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-29 13:41:52 -04:00
parent a81e9e203d
commit a7ef1db485
14 changed files with 416 additions and 142 deletions

View File

@ -0,0 +1,16 @@
{
"data" : [
{
"id" : "test1",
"fabPath" : "Data/fab/disjointedroom1.block",
"dimensions" : {
"x" : 10,
"y" : 10,
"z" : 10
}
}
],
"files" : [
]
}

View File

@ -1795,8 +1795,6 @@ Upgrade terrain editing user experience further
Upgrade terrain generation algorithms Upgrade terrain generation algorithms
- This one should be an ongoing process in general as it is a matter of taste - This one should be an ongoing process in general as it is a matter of taste
- Make a route hard coded that throws you straight into a generated world
- This makes it easier to tweak algo and immediately get results
Documentation Documentation

View File

@ -19,6 +19,7 @@ import electrosphere.game.data.foliage.type.FoliageTypeLoader;
import electrosphere.game.data.foliage.type.model.FoliageTypeMap; import electrosphere.game.data.foliage.type.model.FoliageTypeMap;
import electrosphere.game.data.item.ItemDataMap; import electrosphere.game.data.item.ItemDataMap;
import electrosphere.game.data.projectile.ProjectileTypeHolder; import electrosphere.game.data.projectile.ProjectileTypeHolder;
import electrosphere.game.data.struct.StructureDataLoader;
import electrosphere.game.data.tutorial.HintDefinition; import electrosphere.game.data.tutorial.HintDefinition;
import electrosphere.game.data.units.UnitDefinitionFile; import electrosphere.game.data.units.UnitDefinitionFile;
import electrosphere.game.data.units.UnitLoader; import electrosphere.game.data.units.UnitLoader;
@ -89,6 +90,11 @@ public class Config {
* The list of sampler definitions * The list of sampler definitions
*/ */
List<SamplerFile> samplerDefinitions; List<SamplerFile> samplerDefinitions;
/**
* The structure data
*/
StructureDataLoader structureData;
/** /**
* Loads the default data * Loads the default data
@ -112,6 +118,7 @@ public class Config {
config.recipeMap = RecipeDataMap.loadRecipeFiles("Data/game/recipes.json"); config.recipeMap = RecipeDataMap.loadRecipeFiles("Data/game/recipes.json");
config.biomeMap = BiomeTypeMap.loadBiomeFile("Data/game/biomes.json"); config.biomeMap = BiomeTypeMap.loadBiomeFile("Data/game/biomes.json");
config.samplerDefinitions = SamplerFile.readSamplerDefinitionFiles("Data/game/voxel"); config.samplerDefinitions = SamplerFile.readSamplerDefinitionFiles("Data/game/voxel");
config.structureData = StructureDataLoader.loadStructureFiles("Data/game/structure.json");
//create procedural item types //create procedural item types
ItemDataMap.loadSpawnItems(config.itemMap, config.objectTypeLoader); ItemDataMap.loadSpawnItems(config.itemMap, config.objectTypeLoader);
@ -360,5 +367,13 @@ public class Config {
public List<SamplerFile> getSamplerFiles(){ public List<SamplerFile> getSamplerFiles(){
return this.samplerDefinitions; return this.samplerDefinitions;
} }
/**
* Gets the structure data
* @return The structure data
*/
public StructureDataLoader getStructureData(){
return this.structureData;
}
} }

View File

@ -0,0 +1,67 @@
package electrosphere.game.data.struct;
import org.joml.Vector3d;
/**
* Data about a structure
*/
public class StructureData {
/**
* The id of the structure
*/
String id;
/**
* The path to the fab for the structure
*/
String fabPath;
/**
* The dimensions of the structure
*/
Vector3d dimensions;
/**
* Sets the id of the structure
* @return The id
*/
public String getId() {
return id;
}
/**
* Gets the path to the fab for the structure
* @return The path
*/
public String getFabPath() {
return fabPath;
}
/**
* Sets the path to the fab for the struct
* @param fabPath The path
*/
public void setFabPath(String fabPath) {
this.fabPath = fabPath;
}
/**
* Gets the dimensions of the structure
* @return The dimensions
*/
public Vector3d getDimensions() {
return dimensions;
}
/**
* Sets the dimensions of the structure
* @param dimensions The dimensions
*/
public void setDimensions(Vector3d dimensions) {
this.dimensions = dimensions;
}
}

View File

@ -0,0 +1,52 @@
package electrosphere.game.data.struct;
import java.util.List;
/**
* A file that stores structure data
*/
public class StructureDataFile {
/**
* The list of structures
*/
List<StructureData> data;
/**
* All child files of this one
*/
List<String> files;
/**
* Gets the structure data in this file
* @return The structure data in this file
*/
public List<StructureData> getData() {
return data;
}
/**
* Sets the structure data in this file
* @param structure The structure data in this file
*/
public void setData(List<StructureData> data) {
this.data = data;
}
/**
* Gets all child files of this one
* @return All child files of this one
*/
public List<String> getFiles() {
return files;
}
/**
* Sets all child files of this one
* @param files All child files of this one
*/
public void setFiles(List<String> files) {
this.files = files;
}
}

View File

@ -0,0 +1,94 @@
package electrosphere.game.data.struct;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import electrosphere.util.FileUtils;
/**
* The structure type loader
*/
public class StructureDataLoader {
/**
* The map of structure id -> structure data
*/
Map<String,StructureData> idTypeMap = new HashMap<String,StructureData>();
/**
* Adds structure data to the loader
* @param name The id of the structure
* @param type The structure data
*/
public void putType(String name, StructureData type){
idTypeMap.put(name,type);
}
/**
* Gets structure data from the id of the type
* @param id The id of the type
* @return The structure data if it exists, null otherwise
*/
public StructureData getType(String id){
return idTypeMap.get(id);
}
/**
* Gets the collection of all structure data
* @return the collection of all structure data
*/
public Collection<StructureData> getTypes(){
return idTypeMap.values();
}
/**
* Gets the set of all structure data id's stored in the loader
* @return the set of all structure data ids
*/
public Set<String> getTypeIds(){
return idTypeMap.keySet();
}
/**
* Reads a child structure defintion file
* @param filename The filename
* @return The list of structure in the file
*/
static List<StructureData> recursiveReadStructureLoader(String filename){
List<StructureData> typeList = new LinkedList<StructureData>();
StructureDataFile loaderFile = FileUtils.loadObjectFromAssetPath(filename, StructureDataFile.class);
//push the types from this file
for(StructureData type : loaderFile.getData()){
typeList.add(type);
}
//push types from any other files
if(loaderFile.getFiles() != null){
for(String filepath : loaderFile.getFiles()){
List<StructureData> parsedTypeList = StructureDataLoader.recursiveReadStructureLoader(filepath);
for(StructureData type : parsedTypeList){
typeList.add(type);
}
}
}
return typeList;
}
/**
* Loads all structure definition files recursively
* @param initialPath The initial path to recurse from
* @return The structure defintion interface
*/
public static StructureDataLoader loadStructureFiles(String initialPath) {
StructureDataLoader rVal = new StructureDataLoader();
List<StructureData> typeList = StructureDataLoader.recursiveReadStructureLoader(initialPath);
for(StructureData type : typeList){
rVal.putType(type.getId(), type);
}
return rVal;
}
}

View File

@ -11,6 +11,7 @@ import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeFoliageDescription; import electrosphere.game.data.biome.BiomeFoliageDescription;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.macro.MacroData;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
import io.github.studiorailgun.NoiseUtils; import io.github.studiorailgun.NoiseUtils;
@ -33,11 +34,12 @@ public class ServerContentGenerator {
/** /**
* Generates content for a given data cell * Generates content for a given data cell
* @param realm The realm * @param realm The realm
* @param macroData The macro data
* @param cell The cell * @param cell The cell
* @param worldPos The world position of the cell * @param worldPos The world position of the cell
* @param randomizer The randomizer * @param randomizer The randomizer
*/ */
public static void generateContent(Realm realm, ServerDataCell cell, Vector3i worldPos, long randomizer){ public static void generateContent(Realm realm, MacroData macroData, ServerDataCell cell, Vector3i worldPos, long randomizer){
//verify we have everything for chunk content gen //verify we have everything for chunk content gen
if(realm.getServerWorldData() == null && realm.getServerWorldData().getServerTerrainManager() == null && realm.getServerWorldData().getServerTerrainManager().getModel() == null){ if(realm.getServerWorldData() == null && realm.getServerWorldData().getServerTerrainManager() == null && realm.getServerWorldData().getServerTerrainManager().getModel() == null){
throw new Error( throw new Error(

View File

@ -19,9 +19,14 @@ import electrosphere.util.math.HashUtils;
import electrosphere.server.macro.character.Character; import electrosphere.server.macro.character.Character;
import electrosphere.server.macro.race.Race; import electrosphere.server.macro.race.Race;
/**
* Manages creating/saving/loading/destroying content (ie entities) on the server
*/
public class ServerContentManager { public class ServerContentManager {
//controls whether the manager should generate content on loading a new scene /**
* controls whether the manager should generate content on loading a new scene
*/
boolean generateContent = false; boolean generateContent = false;
/** /**
@ -64,7 +69,7 @@ public class ServerContentManager {
contentRaw.hydrateRawContent(realm,cell); contentRaw.hydrateRawContent(realm,cell);
} else { } else {
//else create from scratch //else create from scratch
ServerContentGenerator.generateContent(realm, cell, worldPos, HashUtils.hashIVec(worldPos.x, worldPos.y, worldPos.z)); ServerContentGenerator.generateContent(realm, this.macroData, cell, worldPos, HashUtils.hashIVec(worldPos.x, worldPos.y, worldPos.z));
} }
} else { } else {
//just because content wasn't generated doesn't mean there isn't data saved under that key //just because content wasn't generated doesn't mean there isn't data saved under that key

View File

@ -108,6 +108,12 @@ public class MacroData {
Race.setRace(testChar, Race.create("human", "human")); Race.setRace(testChar, Race.create("human", "human"));
rVal.characters.add(testChar); rVal.characters.add(testChar);
//add a test character
// Structure struct = Structure.
// testChar.setPos(new Vector3d(ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 1, 32770))));
// Race.setRace(testChar, Race.create("human", "human"));
// rVal.characters.add(testChar);
//spawn initial characters in each race //spawn initial characters in each race
//find initial positions to place characters at per race //find initial positions to place characters at per race
//generate initial characters //generate initial characters

View File

@ -0,0 +1,23 @@
package electrosphere.server.macro.spatial;
import org.joml.Vector3d;
/**
* A macro object that takes up an area of space instead of just a point
*/
public interface MacroAreaObject extends MacroObject {
/**
* Gets the start position of the AABB for the object
* @return The start position
*/
public Vector3d getStartPos();
/**
* Gets the end position of the AABB for the object
* @return The end position
*/
public Vector3d getEndPos();
}

View File

@ -4,61 +4,87 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.joml.AABBd;
import org.joml.Vector3d;
import electrosphere.server.macro.character.CharacterData; import electrosphere.server.macro.character.CharacterData;
import electrosphere.server.macro.character.CharacterDataStrings; import electrosphere.server.macro.character.CharacterDataStrings;
import electrosphere.server.macro.spatial.MacroAreaObject;
/** /**
* Server representation of a structure * Server representation of a structure
*/ */
public class Structure extends CharacterData { public class Structure extends CharacterData implements MacroAreaObject {
int worldX;
int worldY; /**
float locationX; * The position of the structure
float locationY; */
Vector3d position;
/**
* The bounding box for the structure
*/
AABBd aabb;
/**
* The path to the block fab for the structure
*/
String fabPath;
/**
* The type of the structure
*/
String type; String type;
/**
* Data associated with the structure
*/
HashMap<String,Object> data = new HashMap<String,Object>(); HashMap<String,Object> data = new HashMap<String,Object>();
/**
* Data keys associated with the structure
*/
LinkedList<String> dataKeys = new LinkedList<String>(); LinkedList<String> dataKeys = new LinkedList<String>();
public Structure(int worldX, int worldY, float locationX, float locationY, String type) { /**
* Constructor
* @param dataType The data type of the structure
*/
public Structure(){
super(CharacterDataStrings.STRUCTURE); super(CharacterDataStrings.STRUCTURE);
this.worldX = worldX;
this.worldY = worldY;
this.locationX = locationX;
this.locationY = locationY;
this.type = type;
} }
/**
* Puts some data in the structure
* @param key The key for the data
* @param o The data
*/
public void putData(String key, Object o){ public void putData(String key, Object o){
data.put(key,o); data.put(key,o);
dataKeys.add(key); dataKeys.add(key);
} }
/**
* Gets the data keys for the structure
* @return
*/
public List<String> getDataKeys(){ public List<String> getDataKeys(){
return dataKeys; return dataKeys;
} }
/**
* Gets a piece of data on the structure
* @param key The key of the data
* @return The data if it exists, null otherwise
*/
public Object getData(String key){ public Object getData(String key){
return data.get(key); return data.get(key);
} }
public int getWorldX() { /**
return worldX; * Gets the type of the structure
} * @return The type
*/
public int getWorldY() {
return worldY;
}
public float getLocationX() {
return locationX;
}
public float getLocationY() {
return locationY;
}
public String getType() { public String getType() {
return type; return type;
} }
@ -67,6 +93,26 @@ public class Structure extends CharacterData {
public String getDataType() { public String getDataType() {
return CharacterDataStrings.HOMETOWN; return CharacterDataStrings.HOMETOWN;
} }
@Override
public Vector3d getPos() {
return this.position;
}
@Override
public void setPos(Vector3d pos) {
this.position = pos;
}
@Override
public Vector3d getStartPos() {
return new Vector3d(aabb.minX,aabb.minY,aabb.minZ);
}
@Override
public Vector3d getEndPos() {
return new Vector3d(aabb.maxX,aabb.maxY,aabb.maxZ);
}

View File

@ -1,60 +1,10 @@
package electrosphere.server.macro.structure; package electrosphere.server.macro.structure;
import com.google.gson.Gson;
import electrosphere.engine.Globals;
import electrosphere.server.db.DatabaseResult;
import electrosphere.server.db.DatabaseResultRow;
import java.util.LinkedList;
import java.util.List;
/** /**
* Manages all server views of structures * Manages all server views of structures
*/ */
public class StructureManager { public class StructureManager {
static Gson serializer;
static {
serializer = new Gson();
}
static int structIDIterator = 0; static int structIDIterator = 0;
public static Structure createStructure(int worldX, int worldY, float localX, float localY, String type){
structIDIterator++;
Structure rVal = new Structure(worldX, worldY, localX, localY, type);
Globals.dbController.executePreparedStatement("INSERT INTO structWorldPositions (structID,posX,posY) VALUES (?,?,?);",structIDIterator,worldX,worldY);
Globals.dbController.executePreparedStatement("INSERT INTO structData(structID,propName,propValue) VALUES(?,'localX','?');",structIDIterator,localX);
Globals.dbController.executePreparedStatement("INSERT INTO structData(structID,propName,propValue) VALUES(?,'localY','?');",structIDIterator,localY);
return rVal;
}
public static List<Structure> getStructuresInChunk(int worldX, int worldY){
List<Structure> rVal = new LinkedList<Structure>();
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT * FROM structWorldPositions WHERE posX = ? AND posY = ?;",worldX,worldY);
List<Integer> returnedIDs = new LinkedList<Integer>();
if(result.success() && result.hasResult()){
for(DatabaseResultRow row : result){
returnedIDs.add(row.getAsInteger("structID"));
}
}
if(returnedIDs.size() > 0){
String ids = "";
for(int ID : returnedIDs){
ids = ids + ID + ",";
}
ids = ids.substring(0, ids.length() - 1);
result = Globals.dbController.executePreparedQuery("SELECT * FROM structData WHERE structID IN (?);",ids);
if(result.success() && result.hasResult()){
for(DatabaseResultRow row : result){
Structure newStruct = serializer.fromJson(row.getAsString("dataVal"), Structure.class);
rVal.add(newStruct);
}
}
}
return rVal;
}
} }

View File

@ -14,30 +14,30 @@ import org.joml.Vector2f;
public class VirtualStructureUtils { public class VirtualStructureUtils {
public static Structure placeStructureAtPoint(float posX, float posY, float posZ, String type){ // public static Structure placeStructureAtPoint(float posX, float posY, float posZ, String type){
Realm realm = Globals.realmManager.getRealms().iterator().next(); // Realm realm = Globals.realmManager.getRealms().iterator().next();
int worldX = realm.getServerWorldData().convertRealToChunkSpace(posX); // int worldX = realm.getServerWorldData().convertRealToChunkSpace(posX);
int worldY = realm.getServerWorldData().convertRealToChunkSpace(posY); // int worldY = realm.getServerWorldData().convertRealToChunkSpace(posY);
Structure rVal = new Structure(worldX,worldY,posX,posY,type); // Structure rVal = new Structure(worldX,worldY,posX,posY,type);
Globals.macroData.addStructure(rVal); // Globals.macroData.addStructure(rVal);
// double centerHeight = Globals.serverTerrainManager.getHeightAtPosition(posX, posY, posZ); // // double centerHeight = Globals.serverTerrainManager.getHeightAtPosition(posX, posY, posZ);
// StructureType currentTypeObject = Globals.gameConfigCurrent.getStructureTypeMap().getType(type); // // StructureType currentTypeObject = Globals.gameConfigCurrent.getStructureTypeMap().getType(type);
// float radius = currentTypeObject.getRadius(); // // float radius = currentTypeObject.getRadius();
// for(int x = -(int)radius; x < radius; x++){ // // for(int x = -(int)radius; x < radius; x++){
// for(int y = -(int)radius; y < radius; y++){ // // for(int y = -(int)radius; y < radius; y++){
// int newWorldX = Globals.serverWorldData.convertRealToChunkSpace(posX + x); // // int newWorldX = Globals.serverWorldData.convertRealToChunkSpace(posX + x);
// int newWorldY = Globals.serverWorldData.convertRealToChunkSpace(posY + y); // // int newWorldY = Globals.serverWorldData.convertRealToChunkSpace(posY + y);
// double newLocationX = Globals.serverWorldData.getRelativeLocation(posX + x, newWorldX); // // double newLocationX = Globals.serverWorldData.getRelativeLocation(posX + x, newWorldX);
// double newLocationY = Globals.serverWorldData.getRelativeLocation(posY + y, newWorldY); // // double newLocationY = Globals.serverWorldData.getRelativeLocation(posY + y, newWorldY);
// // System.out.println("Set height: " + centerHeight); // // // System.out.println("Set height: " + centerHeight);
// // System.out.println("Deform in chunk: " + newWorldX + "," + newWorldY); // // // System.out.println("Deform in chunk: " + newWorldX + "," + newWorldY);
// Globals.serverTerrainManager.deformTerrainAtLocationToValue(newWorldX, newWorldY, (int)(newLocationX), (int)(newLocationY), (float)centerHeight); // // Globals.serverTerrainManager.deformTerrainAtLocationToValue(newWorldX, newWorldY, (int)(newLocationX), (int)(newLocationY), (float)centerHeight);
// } // // }
// } // // }
// StructureUtils.serverSpawnBasicStructure(type, realm, new Vector3d(posX,(float)centerHeight + 2.4f,posY), new Quaternionf()); // // StructureUtils.serverSpawnBasicStructure(type, realm, new Vector3d(posX,(float)centerHeight + 2.4f,posY), new Quaternionf());
return rVal; // return rVal;
} // }
public static boolean validStructurePlacementPosition(float posX, float posY, String type){ public static boolean validStructurePlacementPosition(float posX, float posY, String type){
// StructureType toPlaceType = Globals.gameConfigCurrent.getStructureTypeMap().getType(type); // StructureType toPlaceType = Globals.gameConfigCurrent.getStructureTypeMap().getType(type);

View File

@ -115,43 +115,43 @@ public class MacroSimulation {
if(!hasHometown && hasShelter){ if(!hasHometown && hasShelter){
Structure shelter = CharacterUtils.getShelter(chara); Structure shelter = CharacterUtils.getShelter(chara);
//if there's at least one other structure nearby //if there's at least one other structure nearby
Vector2i shelterDiscretePos = new Vector2i(shelter.getWorldX(),shelter.getWorldY()); // Vector2i shelterDiscretePos = new Vector2i(shelter.getWorldX(),shelter.getWorldY());
List<Structure> nearbyPopulatedStructures = new LinkedList<Structure>(); // List<Structure> nearbyPopulatedStructures = new LinkedList<Structure>();
for(Structure currentStruct : Globals.macroData.getStructures()){ // for(Structure currentStruct : Globals.macroData.getStructures()){
if(currentStruct.getWorldX() == shelterDiscretePos.x && currentStruct.getWorldY() == shelterDiscretePos.y && currentStruct != shelter){ // if(currentStruct.getWorldX() == shelterDiscretePos.x && currentStruct.getWorldY() == shelterDiscretePos.y && currentStruct != shelter){
//if has a resident // //if has a resident
if(shelter.getDataKeys().contains(StructureDataStrings.RESIDENTS) && VirtualStructureUtils.getResidents(shelter).size() > 0){ // if(shelter.getDataKeys().contains(StructureDataStrings.RESIDENTS) && VirtualStructureUtils.getResidents(shelter).size() > 0){
boolean noTown = true; // boolean noTown = true;
for(Town town : Globals.macroData.getTowns()){ // for(Town town : Globals.macroData.getTowns()){
if(town.getStructures().contains(currentStruct)){ // if(town.getStructures().contains(currentStruct)){
noTown = false; // noTown = false;
} // }
} // }
if(noTown){ // if(noTown){
nearbyPopulatedStructures.add(currentStruct); // nearbyPopulatedStructures.add(currentStruct);
} // }
} // }
} // }
} // }
if(nearbyPopulatedStructures.size() > 0){ // if(nearbyPopulatedStructures.size() > 0){
int numStructures = 0; // int numStructures = 0;
int numResidents = 0; // int numResidents = 0;
//form town // //form town
Town newTown = Town.createTown(shelterDiscretePos.x, shelterDiscretePos.y); // Town newTown = Town.createTown(shelterDiscretePos.x, shelterDiscretePos.y);
for(Structure structure : nearbyPopulatedStructures){ // for(Structure structure : nearbyPopulatedStructures){
numStructures++; // numStructures++;
newTown.addStructure(structure); // newTown.addStructure(structure);
for(Character resident : VirtualStructureUtils.getResidents(structure)){ // for(Character resident : VirtualStructureUtils.getResidents(structure)){
numResidents++; // numResidents++;
newTown.addResident(resident); // newTown.addResident(resident);
CharacterUtils.addHometown(resident, newTown); // CharacterUtils.addHometown(resident, newTown);
} // }
} // }
newTown.addStructure(shelter); // newTown.addStructure(shelter);
newTown.addResident(chara); // newTown.addResident(chara);
CharacterUtils.addHometown(chara, newTown); // CharacterUtils.addHometown(chara, newTown);
System.out.println("Formed town with " + numStructures + " structures and " + numResidents + " residents"); // System.out.println("Formed town with " + numStructures + " structures and " + numResidents + " residents");
} // }
} }
// } // }
} }