town population spawning
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
84b4c11199
commit
5be0a197c3
@ -1952,6 +1952,8 @@ Block chunks properly stride
|
||||
|
||||
(05/24/2025)
|
||||
Work on rotating structures
|
||||
Towns spawn a population of characters when they are max-res'd
|
||||
Hitbox synchronization work
|
||||
|
||||
|
||||
|
||||
|
||||
@ -860,7 +860,7 @@ public class CollisionEngine {
|
||||
DRay ray = OdeHelper.createRay(space, length);
|
||||
ray.set(start.x - this.floatingOrigin.x, start.y - this.floatingOrigin.y, start.z - this.floatingOrigin.z, unitDir.x, unitDir.y, unitDir.z);
|
||||
//collide
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, typeMask);
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, geomPointerMap, typeMask);
|
||||
rayCastCallback.setLength(length);
|
||||
space.collide2(space, data, rayCastCallback);
|
||||
//destroy ray
|
||||
@ -884,7 +884,7 @@ public class CollisionEngine {
|
||||
DRay ray = OdeHelper.createRay(space, length);
|
||||
ray.set(start.x - this.floatingOrigin.x, start.y - this.floatingOrigin.y, start.z - this.floatingOrigin.z, unitDir.x, unitDir.y, unitDir.z);
|
||||
//collide
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, null);
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, geomPointerMap, null);
|
||||
rayCastCallback.setLength(length);
|
||||
space.collide2(ray, data, rayCastCallback);
|
||||
//destroy ray
|
||||
@ -908,7 +908,7 @@ public class CollisionEngine {
|
||||
DRay ray = OdeHelper.createRay(space, length);
|
||||
ray.set(start.x - this.floatingOrigin.x, start.y - this.floatingOrigin.y, start.z - this.floatingOrigin.z, unitDir.x, unitDir.y, unitDir.z);
|
||||
//collide
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, typeMask);
|
||||
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, geomPointerMap, typeMask);
|
||||
rayCastCallback.setLength(length);
|
||||
space.collide2(ray, data, rayCastCallback);
|
||||
//destroy ray
|
||||
@ -1474,6 +1474,20 @@ public class CollisionEngine {
|
||||
geom.setBody(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the ode library
|
||||
*/
|
||||
public static void lockOde(){
|
||||
spaceLock.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the ode library
|
||||
*/
|
||||
public static void unlockOde(){
|
||||
spaceLock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the collision engine
|
||||
* @return The status of the collision engine
|
||||
|
||||
@ -72,6 +72,13 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
|
||||
|
||||
Collidable collidable1 = rayCastData.bodyEntityMap.get(b1);
|
||||
Collidable collidable2 = rayCastData.bodyEntityMap.get(b2);
|
||||
|
||||
if(collidable1 == null){
|
||||
collidable1 = rayCastData.geomEntityMap.get(o1);
|
||||
}
|
||||
if(collidable2 == null){
|
||||
collidable2 = rayCastData.geomEntityMap.get(o2);
|
||||
}
|
||||
|
||||
//don't self cast -- should work on both server and client
|
||||
if(collidable1 != null && collidable1.getParent() == Globals.clientState.playerEntity){
|
||||
@ -151,6 +158,11 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
|
||||
*/
|
||||
Map<DBody,Collidable> bodyEntityMap;
|
||||
|
||||
/**
|
||||
* The map of ode DGeom -> collidable
|
||||
*/
|
||||
Map<DGeom,Collidable> geomEntityMap;
|
||||
|
||||
/**
|
||||
* The mask of collidable types to filter collisions by. Can be null.
|
||||
*/
|
||||
@ -169,10 +181,12 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
|
||||
/**
|
||||
* Constructor
|
||||
* @param bodyEntityMap The map of ode DBody -> collidable
|
||||
* @param geomEntityMap The map of ode DGeom -> collidable
|
||||
* @param collidableTypeMask The mask of collidable types to filter collisions by. Can be null.
|
||||
*/
|
||||
public RayCastCallbackData(Map<DBody,Collidable> bodyEntityMap,List<String> collidableTypeMask){
|
||||
public RayCastCallbackData(Map<DBody,Collidable> bodyEntityMap, Map<DGeom,Collidable> geomEntityMap, List<String> collidableTypeMask){
|
||||
this.bodyEntityMap = bodyEntityMap;
|
||||
this.geomEntityMap = geomEntityMap;
|
||||
this.collidableTypeMask = collidableTypeMask;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,22 +18,17 @@ public class HitboxManager {
|
||||
/**
|
||||
* The list of all hitboxes
|
||||
*/
|
||||
List<HitboxCollectionState> hitboxes = new LinkedList<HitboxCollectionState>();
|
||||
private List<HitboxCollectionState> hitboxes = new LinkedList<HitboxCollectionState>();
|
||||
|
||||
/**
|
||||
* The collision engine for the hitbox manager
|
||||
*/
|
||||
CollisionEngine collisionEngine;
|
||||
private CollisionEngine collisionEngine;
|
||||
|
||||
/**
|
||||
* Lock for hitbox collections
|
||||
*/
|
||||
ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* An incrementer for hitbox IDs
|
||||
*/
|
||||
long idIncrementer = 0;
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -51,7 +46,6 @@ public class HitboxManager {
|
||||
public void registerHitbox(HitboxCollectionState hitbox){
|
||||
lock.lock();
|
||||
hitboxes.add(hitbox);
|
||||
idIncrementer++;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
@ -206,6 +206,7 @@ public class HitboxCollectionState {
|
||||
*/
|
||||
private void createBody(){
|
||||
CollisionEngine collisionEngine = this.manager.getCollisionEngine();
|
||||
CollisionEngine.lockOde();
|
||||
//create the shapes
|
||||
for(HitboxData hitboxDataRaw : this.rawData){
|
||||
DGeom geom = null;
|
||||
@ -284,6 +285,7 @@ public class HitboxCollectionState {
|
||||
//register collidable with collision engine
|
||||
this.collidable = new Collidable(this.parent, Collidable.TYPE_OBJECT, true);
|
||||
collisionEngine.registerCollisionObject(this.body, this.collidable);
|
||||
CollisionEngine.unlockOde();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -11,6 +11,7 @@ import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.state.server.ServerCharacterData;
|
||||
import electrosphere.entity.types.creature.CreatureUtils;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.datacell.ServerDataCell;
|
||||
import electrosphere.server.datacell.ServerWorldData;
|
||||
@ -30,9 +31,9 @@ import electrosphere.server.macro.spatial.MacroObject;
|
||||
public class ServerContentManager {
|
||||
|
||||
/**
|
||||
* Maximum amount of time to wait
|
||||
* Maximum amount of time to wait for macro data to generate
|
||||
*/
|
||||
public static final int MAX_TIME_TO_WAIT = 100;
|
||||
public static final int MAX_TIME_TO_WAIT = 10000;
|
||||
|
||||
/**
|
||||
* controls whether the manager should generate content on loading a new scene
|
||||
@ -170,15 +171,19 @@ public class ServerContentManager {
|
||||
* @param object The object
|
||||
*/
|
||||
public void spawnMacroObject(Realm realm, MacroObject object){
|
||||
if(object instanceof Character && Race.hasRace((Character)object)){
|
||||
Race race = Race.getRace((Character)object);
|
||||
String creatureName = race.getAssociatedCreature();
|
||||
if(creatureName == null){
|
||||
throw new Error("Creature name not defined! " + ((Character)object).getId());
|
||||
if(object instanceof Character){
|
||||
if(Race.hasRace((Character)object)){
|
||||
Race race = Race.getRace((Character)object);
|
||||
String creatureName = race.getAssociatedCreature();
|
||||
if(creatureName == null){
|
||||
throw new Error("Creature name not defined! " + ((Character)object).getId());
|
||||
}
|
||||
//place macro object
|
||||
Entity characterEntity = CreatureUtils.serverSpawnBasicCreature(realm, object.getPos(), creatureName, null);
|
||||
ServerCharacterData.attachServerCharacterData(characterEntity, (Character)object);
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.WARNING("No race defined!");
|
||||
}
|
||||
//place macro object
|
||||
Entity characterEntity = CreatureUtils.serverSpawnBasicCreature(realm, object.getPos(), creatureName, null);
|
||||
ServerCharacterData.attachServerCharacterData(characterEntity, (Character)object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package electrosphere.server.macro;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
@ -18,6 +20,7 @@ import electrosphere.server.macro.spatial.MacroObject;
|
||||
import electrosphere.server.macro.structure.VirtualStructure;
|
||||
import electrosphere.server.macro.town.Town;
|
||||
import electrosphere.util.FileUtils;
|
||||
import electrosphere.util.annotation.Exclude;
|
||||
import electrosphere.util.math.GeomUtils;
|
||||
|
||||
import java.util.Random;
|
||||
@ -55,6 +58,12 @@ public class MacroData {
|
||||
*/
|
||||
List<VirtualStructure> structures = new LinkedList<VirtualStructure>();
|
||||
|
||||
/**
|
||||
* Maps structure id -> structure
|
||||
*/
|
||||
@Exclude
|
||||
private Map<Integer,VirtualStructure> idStructMap = new HashMap<Integer,VirtualStructure>();
|
||||
|
||||
/**
|
||||
* List of roads
|
||||
*/
|
||||
@ -157,6 +166,15 @@ public class MacroData {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds datastructures for the macro data
|
||||
*/
|
||||
public void rebuildDatastructures(){
|
||||
for(VirtualStructure struct : this.structures){
|
||||
this.idStructMap.put(struct.getId(),struct);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this macro data to a save path
|
||||
* @param saveName The name of the save
|
||||
@ -276,12 +294,7 @@ public class MacroData {
|
||||
* @return The structure if it exists, null otherwise
|
||||
*/
|
||||
public VirtualStructure getStructure(int id){
|
||||
for(VirtualStructure struct : structures){
|
||||
if(struct.getId() == id){
|
||||
return struct;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return this.idStructMap.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -291,6 +304,7 @@ public class MacroData {
|
||||
public void addStructure(VirtualStructure structure){
|
||||
structure.setId(structures.size());
|
||||
structures.add(structure);
|
||||
this.idStructMap.put(structure.getId(),structure);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -33,6 +33,9 @@ public class MacroDataLoader {
|
||||
structure.setFab(fab);
|
||||
}
|
||||
|
||||
//rebuild datastructures
|
||||
rVal.rebuildDatastructures();
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import org.joml.Vector3d;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.macro.town.Town;
|
||||
import electrosphere.server.macro.town.TownLayout;
|
||||
import electrosphere.server.macro.town.TownPopulator;
|
||||
|
||||
/**
|
||||
* Updates macro data as a player comes into range of it
|
||||
@ -33,6 +34,8 @@ public class MacroDataUpdater {
|
||||
Vector3d townPos = town.getPos();
|
||||
if(townPos.distance(playerPos) < TOWN_GENERATION_DIST){
|
||||
TownLayout.layoutTown(realm, macroData, town);
|
||||
TownPopulator.populateTown(realm, macroData, town);
|
||||
town.setResolution(Town.TOWN_RES_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
package electrosphere.server.macro.structure;
|
||||
|
||||
import org.joml.AABBd;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.client.block.BlockChunkData;
|
||||
import electrosphere.controls.cursor.CursorState;
|
||||
|
||||
/**
|
||||
* Utility functions for dealing with structures on the server
|
||||
*/
|
||||
@ -44,4 +51,48 @@ public class VirtualStructureUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Samples a virtual structure's fab
|
||||
* @param struct The structure
|
||||
* @param currRealPos The real position to sample from
|
||||
* @return The type if it is in the structure's bounds, 0 otherwise
|
||||
*/
|
||||
public static short getSample(VirtualStructure struct, Vector3d currRealPos){
|
||||
AABBd aabb = struct.getAABB();
|
||||
Vector3d localBlockPos = new Vector3d(
|
||||
Math.round((currRealPos.x - aabb.minX) / BlockChunkData.BLOCK_SIZE_MULTIPLIER),
|
||||
Math.round((currRealPos.y - aabb.minY) / BlockChunkData.BLOCK_SIZE_MULTIPLIER),
|
||||
Math.round((currRealPos.z - aabb.minZ) / BlockChunkData.BLOCK_SIZE_MULTIPLIER)
|
||||
);
|
||||
|
||||
Quaterniond rotationQuat = CursorState.getBlockRotation(struct.getRotation());
|
||||
rotationQuat.transform(localBlockPos);
|
||||
Vector3d dimVec = new Vector3d(struct.getFab().getDimensions());
|
||||
rotationQuat.transform(dimVec);
|
||||
dimVec.absolute();
|
||||
if(localBlockPos.x < 0){
|
||||
localBlockPos.x = dimVec.x + localBlockPos.x;
|
||||
}
|
||||
if(localBlockPos.y < 0){
|
||||
localBlockPos.y = dimVec.y + localBlockPos.y;
|
||||
}
|
||||
if(localBlockPos.z < 0){
|
||||
localBlockPos.z = dimVec.z + localBlockPos.z;
|
||||
}
|
||||
int finalX = Math.round((float)localBlockPos.x);
|
||||
int finalY = Math.round((float)localBlockPos.y);
|
||||
int finalZ = Math.round((float)localBlockPos.z);
|
||||
if(
|
||||
finalX >= 0 &&
|
||||
finalY >= 0 &&
|
||||
finalZ >= 0 &&
|
||||
finalX < struct.getFab().getDimensions().x &&
|
||||
finalY < struct.getFab().getDimensions().y &&
|
||||
finalZ < struct.getFab().getDimensions().z
|
||||
){
|
||||
return struct.getFab().getType(finalX,finalY,finalZ);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -213,23 +213,8 @@ public class TownLayout {
|
||||
|
||||
closedSet.add(openHash);
|
||||
}
|
||||
|
||||
// System.out.println("Structure count: " + town.getStructures(macroData).size());
|
||||
|
||||
town.setResolution(Town.TOWN_RES_MAX);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Generates structures along a road
|
||||
// * @param realm The realm
|
||||
// * @param town The town
|
||||
// * @param road The road
|
||||
// * @param allowedStructures The list of allowed structure types
|
||||
// */
|
||||
// private static void generateStructuresAlongRoad(Realm realm, Town town, Road road, List<StructureData> allowedStructures){
|
||||
// TownLayout.generateStructuresAlongRoad(realm, town, road.getPoint1(), road.getPoint2(), road.getRadius(), allowedStructures);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Generates structures along a road
|
||||
* @param realm The realm
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package electrosphere.server.macro.town;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.types.EntityTypes.EntityType;
|
||||
import electrosphere.entity.types.creature.ObjectTemplate;
|
||||
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.race.Race;
|
||||
import electrosphere.server.macro.structure.VirtualStructure;
|
||||
import electrosphere.server.service.CharacterService;
|
||||
|
||||
/**
|
||||
* Creates the population of a town
|
||||
*/
|
||||
public class TownPopulator {
|
||||
|
||||
/**
|
||||
* Populates a town with characters
|
||||
* @param macroData The macro data
|
||||
* @param town The town
|
||||
*/
|
||||
public static void populateTown(Realm realm, MacroData macroData, Town town){
|
||||
List<VirtualStructure> structs = town.getStructures(macroData);
|
||||
for(VirtualStructure struct : structs){
|
||||
ObjectTemplate template = ObjectTemplate.create(EntityType.CREATURE, "human");
|
||||
Character chara = Globals.serverState.characterService.createCharacter(template, CharacterService.NO_PLAYER);
|
||||
Race.setRace(chara, Globals.gameConfigCurrent.getRaceMap().getRace("human"));
|
||||
CharacterUtils.addShelter(chara, struct);
|
||||
chara.setPos(new Vector3d(struct.getPos()).add(1,1,1));
|
||||
}
|
||||
System.out.println("Total characters: " + Globals.serverState.characterService.getAllCharacters().size());
|
||||
}
|
||||
|
||||
}
|
||||
@ -138,10 +138,12 @@ public class StructureRepairUtils {
|
||||
|
||||
//check existing blocks
|
||||
BlockChunkData blockChunkData = griddedDataCellManager.getBlocksAtPosition(chunkPos);
|
||||
short existingBlockType = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
|
||||
short desiredType = fab.getType(x, y, z);
|
||||
if(existingBlockType != desiredType){
|
||||
return true;
|
||||
if(blockChunkData != null){
|
||||
short existingBlockType = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
|
||||
short desiredType = fab.getType(x, y, z);
|
||||
if(existingBlockType != desiredType){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public class CharacterService extends SignalServiceImpl {
|
||||
/**
|
||||
* Playerid id for a playerless character
|
||||
*/
|
||||
public static final int NO_PLAYER = 0;
|
||||
public static final int NO_PLAYER = -1;
|
||||
|
||||
/**
|
||||
* Map that stores the characters currently loaded into memory
|
||||
|
||||
Loading…
Reference in New Issue
Block a user