Initial macro simulation work

This commit is contained in:
austin 2021-10-16 16:10:10 -04:00
parent 581de4f58a
commit 78ac717283
15 changed files with 331 additions and 14 deletions

View File

@ -17,7 +17,7 @@ CREATE INDEX charaDataIDIndex ON charaData (charID);
--towns
--positions
CREATE TABLE townWorldPositions (id INTEGER PRIMARY KEY, townID INTEGER, posX INTEGER, posY INTEGER, bbRadiusX INTEGER, bbRadiusY INTEGER);
CREATE TABLE townWorldPositions (id INTEGER PRIMARY KEY, townID INTEGER, posX INTEGER, posY INTEGER);
CREATE INDEX townWorldPositionsIDIndex ON townWorldPositions (townID);
CREATE INDEX townWorldPositionsPosIndex ON townWorldPositions (posX, posY);

View File

@ -1,6 +1,6 @@
--positions
INSERT INTO townWorldPositions (townID,posX,posY,bbRadiusX,bbRadiusY) VALUES (0,10,10,1,1);
INSERT INTO townWorldPositions (townID,posX,posY) VALUES (0,10,10);
--data
INSERT INTO townData(townID,propName,propValue) VALUES(0,"name","someTown");

View File

@ -1 +1,2 @@
SELECT * FROM townWorldPositions WHERE posX = 10 AND posY = 10;
--given x=10, y=11
SELECT townID FROM townWorldPositions WHERE posX = 10 AND posY = 11;

View File

@ -349,7 +349,7 @@ public class LoadingThread extends Thread {
int chunkSize = Globals.serverTerrainManager.getChunkWidth();
Globals.spawnPoint = new Vector3f(townLoc.x * chunkSize, (float)Globals.serverTerrainManager.getHeightAtPosition(townLoc.x * chunkSize,townLoc.y * chunkSize), townLoc.y * chunkSize);
// System.out.println("Setting spawn point @ " + Globals.spawnPoint);
Town.createTown(townLoc.x,townLoc.y);
// Town.createTown(townLoc.x,townLoc.y);
}
}

View File

@ -6,7 +6,7 @@ import java.util.LinkedList;
import java.util.List;
public class Character {
static int entity_id_iterator = 0;
static int character_id_iterator = 0;
int id;

View File

@ -11,5 +11,7 @@ public class CharacterDataStrings {
public static final String PERSONALTIY_BASIC = "personalityBasic";
public static final String PERSONALITY_ADVANCED = "personalityAdvanced";
public static final String RACE = "race";
public static final String SHELTER = "shelter";
public static final String HOMETOWN = "hometown";
}

View File

@ -3,6 +3,8 @@ package electrosphere.game.server.character;
import electrosphere.game.server.character.Character;
import electrosphere.game.server.character.diety.Diety;
import electrosphere.game.server.race.model.Race;
import electrosphere.game.server.structure.virtual.Structure;
import electrosphere.game.server.town.Town;
import org.joml.Vector2i;
/**
@ -35,4 +37,20 @@ public class CharacterUtils {
return (Race)character.getData(CharacterDataStrings.RACE);
}
public static void addShelter(Character character, Structure shelter){
character.putData(CharacterDataStrings.SHELTER, shelter);
}
public static Structure getShelter(Character character){
return (Structure)character.getData(CharacterDataStrings.SHELTER);
}
public static void addHometown(Character character, Town town){
character.putData(CharacterDataStrings.HOMETOWN, town);
}
public static Town getHometown(Character character){
return (Town)character.getData(CharacterDataStrings.HOMETOWN);
}
}

View File

@ -1,5 +1,9 @@
package electrosphere.game.server.structure.virtual;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author amaterasu
@ -10,6 +14,10 @@ public class Structure {
float locationX;
float locationY;
String type;
HashMap<String,Object> data = new HashMap();
LinkedList<String> dataKeys = new LinkedList();
public Structure(int worldX, int worldY, float locationX, float locationY, String type) {
this.worldX = worldX;
@ -18,6 +26,19 @@ public class Structure {
this.locationY = locationY;
this.type = type;
}
public void putData(String key, Object o){
data.put(key,o);
dataKeys.add(key);
}
public List<String> getDataKeys(){
return dataKeys;
}
public Object getData(String key){
return data.get(key);
}
public int getWorldX() {
return worldX;
@ -40,4 +61,5 @@ public class Structure {
}
}

View File

@ -0,0 +1,11 @@
package electrosphere.game.server.structure.virtual;
/**
*
* @author satellite
*/
public class StructureDataStrings {
public static final String RESIDENTS = "residents";
}

View File

@ -3,20 +3,25 @@ package electrosphere.game.server.structure.virtual;
import electrosphere.entity.types.structure.StructureUtils;
import electrosphere.game.config.structure.type.model.StructureType;
import electrosphere.main.Globals;
import electrosphere.game.server.character.Character;
import java.util.LinkedList;
import java.util.List;
import org.joml.Quaternionf;
import org.joml.Vector2f;
import org.joml.Vector3f;
/**
*
* @author amaterasu
*/
public class StructurePlacer {
public class VirtualStructureUtils {
public static Structure placeStructureAtPoint(float posX, float posY, String type){
int worldX = Globals.serverWorldData.convertRealToChunkSpace(posX);
int worldY = Globals.serverWorldData.convertRealToChunkSpace(posY);
Structure rVal = new Structure(worldX,worldY,posX,posY,type);
Globals.macroData.addStructure(rVal);
double centerHeight = Globals.serverTerrainManager.getHeightAtPosition(posX, posY);
StructureType currentTypeObject = Globals.gameConfigCurrent.getStructureTypeMap().getType(type);
@ -35,4 +40,33 @@ public class StructurePlacer {
StructureUtils.spawnBasicStructure(type, new Vector3f(posX,(float)centerHeight + 2.4f,posY), new Quaternionf());
return rVal;
}
public static boolean validStructurePlacementPosition(float posX, float posY, String type){
StructureType toPlaceType = Globals.gameConfigCurrent.getStructureTypeMap().getType(type);
Vector2f toPlacePos = new Vector2f(posX, posY);
for(Structure virtualStruct : Globals.macroData.getStructures()){
StructureType existantType = Globals.gameConfigCurrent.getStructureTypeMap().getType(virtualStruct.getType());
Vector2f existantPos = new Vector2f(virtualStruct.getLocationX(),virtualStruct.getLocationY());
if(existantPos.distance(toPlacePos) < toPlaceType.getRadius() + existantType.getRadius()){
return false;
}
}
return true;
}
public static void addResident(Structure structure, Character character){
List<Character> residents = null;
if(structure.getDataKeys().contains(StructureDataStrings.RESIDENTS)){
residents = (List)structure.getData(StructureDataStrings.RESIDENTS);
} else {
residents = new LinkedList();
structure.putData(StructureDataStrings.RESIDENTS, residents);
}
residents.add(character);
}
public static List<Character> getResidents(Structure structure){
return (List)structure.getData(StructureDataStrings.RESIDENTS);
}
}

View File

@ -1,9 +1,19 @@
package electrosphere.game.server.town;
import electrosphere.game.server.structure.virtual.StructurePlacer;
import electrosphere.game.server.db.DatabaseResult;
import electrosphere.game.server.structure.virtual.Structure;
import electrosphere.game.server.structure.virtual.VirtualStructureUtils;
import electrosphere.game.server.terrain.manager.ServerTerrainChunk;
import electrosphere.game.server.character.Character;
import electrosphere.logger.LoggerInterface;
import electrosphere.main.Globals;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.joml.Vector2i;
/**
@ -15,7 +25,13 @@ public class Town {
int id;
static int idIncrementer = 0;
List<Vector2i> positions = new LinkedList();
List<Structure> structures = new LinkedList();
List<Character> residents = new LinkedList();
final static int avgDiffThreshold = 10;
public static Vector2i findValidTownLocation(){
for(int x = 0; x < Globals.serverTerrainManager.getWorldDiscreteSize(); x++){
for(int y = 0; y < Globals.serverTerrainManager.getWorldDiscreteSize(); y++){
@ -54,13 +70,58 @@ public class Town {
public static Town createTown(int x, int y){
Town rVal = new Town();
Random rand = new Random();
int structCount = (rand.nextInt(3) + 2);
int chunkSize = Globals.serverTerrainManager.getChunkWidth();
for(int i = 0; i < structCount; i++){
StructurePlacer.placeStructureAtPoint(x * chunkSize + rand.nextFloat() * 100, y * chunkSize + rand.nextFloat() * 100, "building1");
rVal.positions.add(new Vector2i(x,y));
Globals.macroData.addTown(rVal);
// Random rand = new Random();
// int structCount = (rand.nextInt(3) + 2);
// int chunkSize = Globals.serverTerrainManager.getChunkWidth();
// for(int i = 0; i < structCount; i++){
// StructurePlacer.placeStructureAtPoint(x * chunkSize + rand.nextFloat() * 100, y * chunkSize + rand.nextFloat() * 100, "building1");
// }
return rVal;
}
public static Town getTownAtPosition(int x, int y){
Town rVal = null;
// DatabaseResult locationLookupResult = Globals.dbController.executeQuery("SELECT townID FROM townWorldPositions WHERE posX = " + x + " AND posY = " + y + ";");
// if(locationLookupResult.hasResultSet()){
// ResultSet rs = locationLookupResult.getResultSet();
// int townID = -1;
// try {
// if(rs.next()){
// townID = rs.getInt("townID");
// }
// } catch (SQLException ex) {
// LoggerInterface.loggerEngine.ERROR("Error reading result set from getTownAtPosition", ex);
// }
// if(townID != -1){
//
// }
// }
for(Town town : Globals.macroData.getTowns()){
for(Vector2i position : town.positions){
if(position.x == x && position.y == y){
return town;
}
}
}
return rVal;
}
public void addStructure(Structure structure){
structures.add(structure);
}
public List<Structure> getStructures(){
return structures;
}
public void addResident(Character resident){
residents.add(resident);
}
public List<Character> getResidents(){
return residents;
}
}

View File

@ -0,0 +1,9 @@
package electrosphere.game.server.town;
/**
*
* @author satellite
*/
public class TownUtils {
}

View File

@ -6,9 +6,12 @@ import electrosphere.game.server.character.Character;
import electrosphere.game.server.character.CharacterDataStrings;
import electrosphere.game.server.character.CharacterUtils;
import electrosphere.game.server.character.diety.Diety;
import electrosphere.game.server.civilization.Civilization;
import electrosphere.game.server.race.model.Race;
import electrosphere.game.server.race.model.RaceMap;
import electrosphere.game.server.structure.virtual.Structure;
import electrosphere.game.server.symbolism.model.Symbol;
import electrosphere.game.server.town.Town;
import electrosphere.main.Globals;
import java.util.Random;
import org.joml.Vector2i;
@ -23,6 +26,9 @@ public class MacroData {
List<Race> races = new LinkedList();
List<Character> characters = new LinkedList();
List<Character> aliveCharacters = new LinkedList();
List<Civilization> civilizations = new LinkedList();
List<Town> towns = new LinkedList();
List<Structure> structures = new LinkedList();
static Character generateInitialDiety(long seed){
@ -109,6 +115,30 @@ public class MacroData {
return aliveCharacters;
}
public List<Civilization> getCivilizations(){
return civilizations;
}
public void addCivilization(Civilization civilization){
civilizations.add(civilization);
}
public List<Town> getTowns(){
return towns;
}
public void addTown(Town town){
towns.add(town);
}
public List<Structure> getStructures(){
return structures;
}
public void addStructure(Structure structure){
structures.add(structure);
}
public void describeWorld(){
System.out.println("Initial dieties");
System.out.println("==========================");

View File

@ -10,10 +10,17 @@ import electrosphere.game.server.structure.virtual.Structure;
import electrosphere.game.server.town.Town;
import electrosphere.main.Globals;
import electrosphere.game.server.character.Character;
import electrosphere.game.server.character.CharacterDataStrings;
import electrosphere.game.server.character.CharacterUtils;
import electrosphere.game.server.structure.virtual.StructureDataStrings;
import electrosphere.game.server.structure.virtual.VirtualStructureUtils;
import electrosphere.util.FileLoadingUtils;
import electrosphere.util.Utilities;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.joml.Vector2f;
import org.joml.Vector2i;
public class MacroSimulation {
@ -39,6 +46,121 @@ public class MacroSimulation {
public void simulate(){
for(Character character : Globals.macroData.getAliveCharacters()){
//do something
checkForShelter();
checkTownMembership();
}
}
static final int MAX_PLACE_ATTEMPTS = 10;
static void checkForShelter(){
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(!chara.getDataKeys().contains(CharacterDataStrings.SHELTER)){
Vector2i charPos = CharacterUtils.getDiscretePosition(chara);
Town nearbyTown = Town.getTownAtPosition(charPos.x,charPos.y);
if(nearbyTown != null){
//if town has a place to day
if(false){
} else {
//try to find a place to put down a structure
}
} else {
//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){
System.out.println("Added shelter");
Structure placedStructure = VirtualStructureUtils.placeStructureAtPoint(placementPos.x, placementPos.y, buildingTypeToPlace);
CharacterUtils.addShelter(chara, placedStructure);
VirtualStructureUtils.addResident(placedStructure, chara);
}
}
}
}
}
static void checkTownMembership(){
//TODO: eventually exclude people who shouldn't belong to a town (traders, bandits, etc)
for(Character chara : Globals.macroData.getAliveCharacters()){
boolean hasHometown = chara.getDataKeys().contains(CharacterDataStrings.HOMETOWN);
boolean hasShelter = chara.getDataKeys().contains(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();
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");
}
}
}
}
static void checkInitCombat(){
for(Character chara : Globals.macroData.getAliveCharacters()){
Vector2i position = CharacterUtils.getDiscretePosition(chara);
}
}
}

View File

@ -18,6 +18,7 @@ import electrosphere.game.client.ClientFunctions;
import electrosphere.game.config.UserSettings;
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
import electrosphere.game.server.world.MacroData;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.game.state.MacroSimulation;
import electrosphere.game.state.MicroSimulation;
import electrosphere.logger.LoggerInterface;
@ -121,13 +122,19 @@ public class Main {
//gen terrain
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0);
Globals.serverTerrainManager.load();
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
//gen world
MacroData world = MacroData.generateWorld(0);
world.describeWorld();
Globals.macroData = MacroData.generateWorld(0);
Globals.macroData.describeWorld();
boolean run = true;
Globals.macroSimulation = new MacroSimulation();
while(run){
Globals.macroSimulation.simulate();
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
//debug: create terrain/world viewer