diff --git a/buildNumber.properties b/buildNumber.properties index 230e65c4..db5c97c7 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Sun Nov 05 10:58:49 EST 2023 -buildNumber=12 +#Sun Feb 25 14:43:29 EST 2024 +buildNumber=13 diff --git a/docs/src/highlevel-design/macroWorldPartitioning.md b/docs/src/highlevel-design/macroWorldPartitioning.md new file mode 100644 index 00000000..f6d49291 --- /dev/null +++ b/docs/src/highlevel-design/macroWorldPartitioning.md @@ -0,0 +1,27 @@ +# Macro World Partitioning + + + +Different terrain levels: + + + + +Sky 1: 12000m - 14000m + +Sky 1: 10000m - 12000m + +Sky 1: 8000m - 10000m + +Surface: 3000m - 8000m + +Deep Earth 1: 2000m - 3000m + +Deep Earth 2: 1000m - 2000m + +Deep Earth 3: 0m - 1000m + + + + +Ocean starts at 4000m \ No newline at end of file diff --git a/docs/src/server-common/entitySpawning.md b/docs/src/server-common/entitySpawning.md new file mode 100644 index 00000000..3e8ca51f --- /dev/null +++ b/docs/src/server-common/entitySpawning.md @@ -0,0 +1,80 @@ +# Entity Spawning + +Recommended flow and tips for spawning entities from the server + + +## High Level Overview + +#### Spawning a creature +``` +CreatureTemplate template = ; +String raceName = template.getCreatureType(); +//spawn creature in world +Realm realm = Globals.realmManager.getRealms().iterator().next(); +Entity newCreature = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template); +``` + +#### Spawning a plant +``` +CreatureTemplate template = ; +String raceName = template.getCreatureType(); +//spawn creature in world +Realm realm = Globals.realmManager.getRealms().iterator().next(); +Entity newCreature = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template); +``` + + + +## Major Usage Notes + - TODO + + + + + + + + + + + + +## Main Classes + +[CreatureUtils.java](@ref #electrosphere.entity.types.creature.CreatureUtils) - Provides utilities for spawning creatures into the game world for both server and client + + + + +## Code Organization and Best Practices + +#### Startup + + +#### Usage + + + + + + + + + + + +## Terminology + + + + + + + + + + + + + +## Future Goals diff --git a/net/entity.json b/net/entity.json index 4c70e091..805065ab 100644 --- a/net/entity.json +++ b/net/entity.json @@ -108,6 +108,10 @@ { "name" : "propertyValueString", "type" : "VAR_STRING" + }, + { + "name" : "foliageSeed", + "type" : "FIXED_LONG" } ], "messageTypes" : [ @@ -291,6 +295,17 @@ "bone", "targetID" ] + }, + { + "messageName" : "SpawnFoliageSeed", + "data" : [ + "entityID", + "creatureTemplate", + "foliageSeed", + "positionX", + "positionY", + "positionZ" + ] } diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index 60bf98c3..c930228c 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -159,9 +159,11 @@ public class CollisionEngine { } public void clearCollidableImpulseLists(){ + spaceLock.acquireUninterruptibly(); for(Collidable collidable : collidableList){ collidable.clear(); } + spaceLock.release(); } public List getCollidables(){ @@ -375,9 +377,11 @@ public class CollisionEngine { } public void registerCollisionObject(DBody body, Collidable collidable){ + spaceLock.acquireUninterruptibly(); registerPhysicsObject(body); bodyPointerMap.put(body,collidable); collidableList.add(collidable); + spaceLock.release(); } public void listBodyPositions(){ diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index cb45c298..ee69aa9a 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -62,6 +62,7 @@ import electrosphere.renderer.ui.font.FontUtils; import electrosphere.renderer.ui.font.RawFontMap; import electrosphere.script.ScriptEngine; import electrosphere.server.ai.AIManager; +import electrosphere.server.content.ServerContentManager; import electrosphere.server.datacell.EntityDataCellMapper; import electrosphere.server.datacell.RealmManager; import electrosphere.server.db.DatabaseController; @@ -244,6 +245,9 @@ public class Globals { // public static boolean LOAD_TERRAIN = true; public static ServerTerrainManager serverTerrainManager; public static Vector3d spawnPoint = new Vector3d(0,0,0); + + //content manager + public static ServerContentManager serverContentManager; //manages all models loaded into memory public static AssetManager assetManager; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java index 559d249e..fcf58d1b 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java @@ -14,6 +14,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.ServerEntityUtils; import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; +import electrosphere.server.content.ServerContentManager; import electrosphere.server.saves.SaveUtils; import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.util.FileUtils; @@ -59,6 +60,7 @@ public class ArenaLoading { private static void initServerArenaWorldData(){ Globals.serverWorldData = ServerWorldData.createArenaWorld(); + Globals.serverContentManager = ServerContentManager.createServerContentManager(); Globals.spawnPoint = new Vector3d(1,0.1,1); // Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); } diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index 1004c811..d1a3be3c 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -254,13 +254,13 @@ public class ClientLoading { // EntityUtils.getPosition(tree).set(5,0,i * 5); // } - for(int x = 0; x < 5; x++){ - for(int z = 0; z < 5; z++){ - Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong()); - ClientEntityUtils.initiallyPositionEntity(tree, new Vector3d(5 + x * 5,0,5 + z * 5)); - EntityUtils.getScale(tree).set(0.5f); - } - } + // for(int x = 0; x < 5; x++){ + // for(int z = 0; z < 5; z++){ + // Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong()); + // ClientEntityUtils.initiallyPositionEntity(tree, new Vector3d(5 + x * 5,0,5 + z * 5)); + // EntityUtils.getScale(tree).set(0.5f); + // } + // } } diff --git a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java index fc63b5dd..f2e35ce7 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java @@ -16,6 +16,7 @@ import electrosphere.menu.WindowUtils; import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.ServerConnectionHandler; import electrosphere.renderer.ui.Window; +import electrosphere.server.content.ServerContentManager; import electrosphere.server.saves.SaveUtils; import electrosphere.server.terrain.generation.OverworldChunkGenerator; import electrosphere.server.terrain.manager.ServerTerrainManager; @@ -51,10 +52,13 @@ public class DebugSPWorldLoading { SaveUtils.loadSave("random_sp_world"); //start initializing game datastructures // Globals.griddedDataCellManager.init(Globals.serverWorldData); - LoadingUtils.initGriddedRealm(); //initialize the "virtual" objects simulation LoadingUtils.initMacroSimulation(); + Globals.serverContentManager = ServerContentManager.createServerContentManager(); + + LoadingUtils.initGriddedRealm(); + LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); //init authentication diff --git a/src/main/java/electrosphere/entity/EntityCreationUtils.java b/src/main/java/electrosphere/entity/EntityCreationUtils.java index 5d42600e..442d8e19 100644 --- a/src/main/java/electrosphere/entity/EntityCreationUtils.java +++ b/src/main/java/electrosphere/entity/EntityCreationUtils.java @@ -26,15 +26,10 @@ public class EntityCreationUtils { Entity rVal = EntityUtils.spawnSpatialEntity(); //register to global entity id lookup table EntityLookupUtils.registerServerEntity(rVal); - //register to data cell - ServerDataCell entityDataCell = realm.getDataCellManager().tryCreateCellAtPoint(position); - entityDataCell.getScene().registerEntity(rVal); - //maps this entity to its realm - Globals.realmManager.mapEntityToRealm(rVal, realm); + //position entity + ServerEntityUtils.initiallyPositionEntity(realm,rVal,position); //enable behavior tree tracking ServerBehaviorTreeUtils.registerEntity(rVal); - //register to entity data cell mapper - realm.getEntityDataCellMapper().registerEntity(rVal, entityDataCell); return rVal; } diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 14af1f42..33b7bb27 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -241,6 +241,8 @@ public class EntityDataStrings { public static final String FOLIAGE_IS_FOLIAGE = "foliageIsFoliage"; public static final String FOLIAGE_TYPE = "foliageType"; public static final String FOLIAGE_AMBIENT_TREE = "foliageAmbientTree"; + public static final String FOLIAGE_SEED = "foliageSeed"; + public static final String FOLIAGE_IS_SEEDED = "foliageIsSeeded"; /* Equip state diff --git a/src/main/java/electrosphere/entity/EntityTags.java b/src/main/java/electrosphere/entity/EntityTags.java index d6cda02b..27389b68 100644 --- a/src/main/java/electrosphere/entity/EntityTags.java +++ b/src/main/java/electrosphere/entity/EntityTags.java @@ -11,6 +11,7 @@ public class EntityTags { public static final String TARGETABLE = "targetable"; public static final String LIFE_STATE = "lifeState"; public static final String CREATURE = "creature"; + public static final String FOLIAGE = "foliage"; public static final String UI = "ui"; public static final String DRAWABLE = "drawable"; public static final String DRAW_INSTANCED = "drawInstanced"; //if it's instanced, but not necessarily managed by a service (ie a tree branch) diff --git a/src/main/java/electrosphere/entity/Scene.java b/src/main/java/electrosphere/entity/Scene.java index 1978f342..a9da56e0 100644 --- a/src/main/java/electrosphere/entity/Scene.java +++ b/src/main/java/electrosphere/entity/Scene.java @@ -41,6 +41,7 @@ public class Scene { tagEntityMap.put(EntityTags.CREATURE, new HashSet()); tagEntityMap.put(EntityTags.UI, new HashSet()); tagEntityMap.put(EntityTags.DRAWABLE, new HashSet()); + tagEntityMap.put(EntityTags.DRAW_INSTANCED, new HashSet()); tagEntityMap.put(EntityTags.LIGHT, new HashSet()); tagEntityMap.put(EntityTags.ITEM, new HashSet()); tagEntityMap.put(EntityTags.GRAVITY, new HashSet()); diff --git a/src/main/java/electrosphere/entity/ServerEntityUtils.java b/src/main/java/electrosphere/entity/ServerEntityUtils.java index 846316f3..88f18dce 100644 --- a/src/main/java/electrosphere/entity/ServerEntityUtils.java +++ b/src/main/java/electrosphere/entity/ServerEntityUtils.java @@ -32,6 +32,8 @@ public class ServerEntityUtils { //initialize server datacell tracking of this entity realm.initializeServerSideEntity(entity, cell); } + //register to entity data cell mapper + realm.getEntityDataCellMapper().registerEntity(entity, cell); //reposition entity CollisionObjUtils.serverPositionCharacter(entity, position); } diff --git a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java index 7244280c..96207328 100644 --- a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java +++ b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java @@ -6,16 +6,25 @@ import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.entity.types.tree.ProceduralTree; import electrosphere.game.data.foliage.type.FoliageType; import electrosphere.game.data.foliage.type.PhysicsObject; +import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.net.parser.net.message.NetworkMessage; +import electrosphere.net.server.player.Player; import electrosphere.renderer.actor.ActorUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; +import electrosphere.util.Utilities; import java.util.List; import org.joml.Matrix4f; import org.joml.Quaternionf; +import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector4f; @@ -29,10 +38,15 @@ public class FoliageUtils { * @param type The type of foliage object * @return The entity for the foliage */ - public static Entity spawnBasicFoliage(String type){ + public static Entity spawnBasicFoliage(String type, long seed){ FoliageType rawType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); - Entity rVal = EntityCreationUtils.createClientSpatialEntity(); - EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); + Entity rVal; + if(rawType.getTreeModel()!=null){ + rVal = ProceduralTree.clientGenerateProceduralTree(type, 0); + } else { + rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); + } for(String token : rawType.getTokens()){ switch(token){ @@ -54,6 +68,104 @@ public class FoliageUtils { rVal.putData(EntityDataStrings.FOLIAGE_TYPE, type); return rVal; } + + + /** + * Spawns a tree foliage on the server + * @param realm The realm to spawn on + * @param position The position of the tree + * @param type the type of tree + * @param seed the seed for the tree + * @return the tree entity + */ + public static Entity serverSpawnTreeFoliage(Realm realm, Vector3d position, String type, long seed){ + FoliageType rawType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); + Entity rVal = ProceduralTree.serverGenerateProceduralTree(realm, position, rawType, seed); + + for(String token : rawType.getTokens()){ + switch(token){ + case "BLENDER_TRANSFORM": + ActorUtils.applyBlenderTransformer(rVal); + break; + case "BLENDER_ROTATION": + ActorUtils.applyBlenderRotation(rVal); + break; + case "PARTICLE_SPAWNER": + + break; + } + } + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.FOLIAGE); + rVal.putData(EntityDataStrings.FOLIAGE_IS_FOLIAGE, true); + rVal.putData(EntityDataStrings.FOLIAGE_TYPE, rawType); + rVal.putData(EntityDataStrings.FOLIAGE_SEED, seed); + rVal.putData(EntityDataStrings.FOLIAGE_IS_SEEDED, true); + rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); + return rVal; + } + + /** + * Gets the seed for a given foliage item + * @param entity The entity + * @return The seed + */ + public static long getFoliageSeed(Entity entity){ + return (long)entity.getData(EntityDataStrings.FOLIAGE_SEED); + } + + /** + * Gets the type of foliage + * @param entity the entity + * @return The type + */ + public static FoliageType getFoliageType(Entity entity){ + return (FoliageType)entity.getData(EntityDataStrings.FOLIAGE_TYPE); + } + + /** + * Gets whether the entity is foliage or not + * @param entity The entity + * @return true if is foliage, false otherwise + */ + public static boolean isFoliage(Entity entity){ + return entity.getData(EntityDataStrings.FOLIAGE_IS_FOLIAGE)!=null; + } + + /** + * Gets whether the entity has a foliage seed or not + * @param entity The entity + * @return true if is has seed, false otherwise + */ + public static boolean hasSeed(Entity entity){ + return entity.getData(EntityDataStrings.FOLIAGE_IS_SEEDED)!=null; + } + + + /** + * Sends a given foliage entity to a given player + * @param player The player + * @param foliage The foliage entity + */ + public static void sendFoliageToPlayer(Player player, Entity foliage){ + int id = foliage.getId(); + FoliageType type = FoliageUtils.getFoliageType(foliage); + Vector3d position = EntityUtils.getPosition(foliage); + if(FoliageUtils.hasSeed(foliage)){ + long seed = FoliageUtils.getFoliageSeed(foliage); + NetworkMessage message = EntityMessage.constructSpawnFoliageSeedMessage( + id, + type.getName(), + seed, + position.x, + position.y, + position.z + ); + player.addMessage(message); + } else { + //still needs to be implemented with new network message + throw new UnsupportedOperationException("Tried to spawn a foliage object that doesn't have a seed."); + } + } } diff --git a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java index e23c247e..9285bf60 100644 --- a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java +++ b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java @@ -35,6 +35,9 @@ import electrosphere.game.data.foliage.type.TreeModel; import electrosphere.renderer.actor.instance.InstancedActor; import electrosphere.renderer.buffer.ShaderAttribute; import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes; +import electrosphere.server.datacell.Realm; +import electrosphere.server.poseactor.PoseActor; +import electrosphere.server.poseactor.PoseActorUtils; /** * Used for generating procedural trees @@ -146,7 +149,7 @@ public class ProceduralTree { return trunkChild; } - public static List clientGenerateBranchesAlt( + private static List clientGenerateBranchesAlt( TreeModel type, Entity parent, Random rand, @@ -356,6 +359,37 @@ public class ProceduralTree { return rVal; } + /** + * Server side function to generate a tree + * @param type The type of tree as a string + * @param seed The seed (lol) for the tree + * @return The top level tree entity + */ + public static Entity serverGenerateProceduralTree(Realm realm, Vector3d position, FoliageType foliageType, long seed){ + //call recursive branching routine to generate branches from trunk + leaf blobs + TreeModel treeModel = foliageType.getTreeModel(); + + //generate trunk + Entity trunkChild = EntityCreationUtils.createServerEntity(realm,position); + + //attach physics + DBody rigidBody = CollisionBodyCreation.createCylinderBody( + realm.getCollisionEngine(), + treeModel.getPhysicsBody().getDimension1(), + treeModel.getPhysicsBody().getDimension2() + ); + Collidable collidable = new Collidable(trunkChild, Collidable.TYPE_OBJECT); + trunkChild.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + trunkChild.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(0,treeModel.getPhysicsBody().getOffsetY(),0)); + trunkChild.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, treeModel.getPhysicsBody()); + trunkChild.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + trunkChild.putData(EntityDataStrings.PHYSICS_MASS, TREE_MASS); + + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + + return trunkChild; + } + // /** // * Generates branches // * @param type The type of branch diff --git a/src/main/java/electrosphere/game/server/world/ServerWorldData.java b/src/main/java/electrosphere/game/server/world/ServerWorldData.java index b5e9ef6e..dd1c073b 100644 --- a/src/main/java/electrosphere/game/server/world/ServerWorldData.java +++ b/src/main/java/electrosphere/game/server/world/ServerWorldData.java @@ -101,11 +101,11 @@ public class ServerWorldData { } public int convertRealToChunkSpace(double real){ - return (int)Math.floor(real / dynamicInterpolationRatio); + return (int)Math.floor(real / ServerTerrainChunk.CHUNK_DIMENSION); } public float convertChunkToRealSpace(int chunk){ - return chunk * dynamicInterpolationRatio; + return chunk * ServerTerrainChunk.CHUNK_DIMENSION; } public double getRelativeLocation(double real, int world){ @@ -116,6 +116,44 @@ public class ServerWorldData { return isArena; } + + public int convertRealToWorld(double real){ + return convertRealToChunkSpace(real); + } + + public double convertWorldToReal(int world){ + return convertChunkToRealSpace(world); + } + + public Vector3i convertRealToChunkSpace(Vector3d position){ + return new Vector3i( + convertRealToChunkSpace(position.x), + convertRealToChunkSpace(position.y), + convertRealToChunkSpace(position.z) + ); + } + + /** + * Converts a world space vector to a real space vector + * @param position The world space vector + * @return The real space vector + */ + public Vector3d convertWorldToRealSpace(Vector3i position){ + return new Vector3d( + convertWorldToReal(position.x), + convertWorldToReal(position.y), + convertWorldToReal(position.z) + ); + } + + public Vector3i convertRealToVoxelSpace(Vector3d position){ + return new Vector3i( + (int)Math.floor(position.x - convertChunkToRealSpace(convertRealToChunkSpace(position.x))), + (int)Math.floor(position.y - convertChunkToRealSpace(convertRealToChunkSpace(position.y))), + (int)Math.floor(position.z - convertChunkToRealSpace(convertRealToChunkSpace(position.z))) + ); + } + /** * Converts a real coordinate to a world space coordinate * @param position The real coordinate @@ -128,18 +166,5 @@ public class ServerWorldData { convertRealToChunkSpace(position.z) ); } - - /** - * Converts a real coordinate to a voxel space coordinate, relative to the containing chunk of the real coordinate - * @param position The real coordinate - * @return The voxel space coordinate - */ - public Vector3i convertRealToVoxelSpace(Vector3d position){ - return new Vector3i( - (int)Math.floor(position.x - convertChunkToRealSpace(convertRealToChunkSpace(position.x))), - (int)Math.floor(position.y - convertChunkToRealSpace(convertRealToChunkSpace(position.y))), - (int)Math.floor(position.z - convertChunkToRealSpace(convertRealToChunkSpace(position.z))) - ); - } } diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java index 39ff91b2..846a33f1 100644 --- a/src/main/java/electrosphere/logger/LoggerInterface.java +++ b/src/main/java/electrosphere/logger/LoggerInterface.java @@ -25,7 +25,7 @@ public class LoggerInterface { loggerFileIO = new Logger(LogLevel.WARNING); loggerGameLogic = new Logger(LogLevel.WARNING); loggerRenderer = new Logger(LogLevel.WARNING); - loggerEngine = new Logger(LogLevel.DEBUG); + loggerEngine = new Logger(LogLevel.WARNING); loggerAuth = new Logger(LogLevel.WARNING); loggerDB = new Logger(LogLevel.WARNING); loggerStartup.INFO("Initialized loggers"); diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index bfee84f9..c7c9190c 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -12,6 +12,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.creature.CreatureTemplate; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.foliage.FoliageUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.EntityMessage; @@ -113,6 +114,13 @@ public class EntityProtocol { break; case SETFACING: break; + case SPAWNFOLIAGESEED: { + LoggerInterface.loggerNetworking.DEBUG("Spawn foliage " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + String type = message.getcreatureTemplate(); + newlySpawnedEntity = FoliageUtils.spawnBasicFoliage(type,message.getfoliageSeed()); + ClientEntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ())); + Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); + } break; } } diff --git a/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java b/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java index 16108270..79909580 100644 --- a/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java @@ -26,6 +26,7 @@ public class EntityMessage extends NetworkMessage { SETBTREEPROPERTYSTRING, SETBTREEPROPERTYENUM, ATTACHENTITYTOENTITY, + SPAWNFOLIAGESEED, } EntityMessageType messageType; @@ -55,6 +56,7 @@ public class EntityMessage extends NetworkMessage { float propertyValueFloat; double propertyValueDouble; String propertyValueString; + long foliageSeed; EntityMessage(EntityMessageType messageType){ this.type = MessageType.ENTITY_MESSAGE; @@ -273,6 +275,14 @@ public class EntityMessage extends NetworkMessage { this.propertyValueString = propertyValueString; } + public long getfoliageSeed() { + return foliageSeed; + } + + public void setfoliageSeed(long foliageSeed) { + this.foliageSeed = foliageSeed; + } + static void stripPacketHeader(CircularByteBuffer byteBuffer){ byteBuffer.read(2); } @@ -367,6 +377,8 @@ public class EntityMessage extends NetworkMessage { } case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY: return EntityMessage.canParseattachEntityToEntityMessage(byteBuffer); + case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED: + return EntityMessage.canParseSpawnFoliageSeedMessage(byteBuffer); } return false; } @@ -921,6 +933,64 @@ public class EntityMessage extends NetworkMessage { return rVal; } + public static boolean canParseSpawnFoliageSeedMessage(CircularByteBuffer byteBuffer){ + int currentStreamLength = byteBuffer.getRemaining(); + List temporaryByteQueue = new LinkedList(); + if(currentStreamLength < 6){ + return false; + } + int creatureTemplateSize = 0; + if(currentStreamLength < 10){ + return false; + } else { + temporaryByteQueue.add(byteBuffer.peek(6 + 0)); + temporaryByteQueue.add(byteBuffer.peek(6 + 1)); + temporaryByteQueue.add(byteBuffer.peek(6 + 2)); + temporaryByteQueue.add(byteBuffer.peek(6 + 3)); + creatureTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue); + } + if(currentStreamLength < 10 + creatureTemplateSize){ + return false; + } + if(currentStreamLength < 18 + creatureTemplateSize){ + return false; + } + if(currentStreamLength < 26 + creatureTemplateSize){ + return false; + } + if(currentStreamLength < 34 + creatureTemplateSize){ + return false; + } + if(currentStreamLength < 42 + creatureTemplateSize){ + return false; + } + return true; + } + + public static EntityMessage parseSpawnFoliageSeedMessage(CircularByteBuffer byteBuffer){ + EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNFOLIAGESEED); + stripPacketHeader(byteBuffer); + rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setcreatureTemplate(ByteStreamUtils.popStringFromByteQueue(byteBuffer)); + rVal.setfoliageSeed(ByteStreamUtils.popLongFromByteQueue(byteBuffer)); + rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + return rVal; + } + + public static EntityMessage constructSpawnFoliageSeedMessage(int entityID,String creatureTemplate,long foliageSeed,double positionX,double positionY,double positionZ){ + EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNFOLIAGESEED); + rVal.setentityID(entityID); + rVal.setcreatureTemplate(creatureTemplate); + rVal.setfoliageSeed(foliageSeed); + rVal.setpositionX(positionX); + rVal.setpositionY(positionY); + rVal.setpositionZ(positionZ); + rVal.serialize(); + return rVal; + } + @Override void serialize(){ byte[] intValues = new byte[8]; @@ -1435,6 +1505,41 @@ public class EntityMessage extends NetworkMessage { rawBytes[10+bone.length()+i] = intValues[i]; } break; + case SPAWNFOLIAGESEED: + rawBytes = new byte[2+4+4+creatureTemplate.length()+8+8+8+8]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY; + //entity messaage header + rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED; + intValues = ByteStreamUtils.serializeIntToBytes(entityID); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(creatureTemplate.length()); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + stringBytes = creatureTemplate.getBytes(); + for(int i = 0; i < creatureTemplate.length(); i++){ + rawBytes[10+i] = stringBytes[i]; + } + intValues = ByteStreamUtils.serializeLongToBytes(foliageSeed); + for(int i = 0; i < 8; i++){ + rawBytes[10+creatureTemplate.length()+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeDoubleToBytes(positionX); + for(int i = 0; i < 8; i++){ + rawBytes[18+creatureTemplate.length()+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeDoubleToBytes(positionY); + for(int i = 0; i < 8; i++){ + rawBytes[26+creatureTemplate.length()+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ); + for(int i = 0; i < 8; i++){ + rawBytes[34+creatureTemplate.length()+i] = intValues[i]; + } + break; } serialized = true; } diff --git a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java index ac2a95f8..dd383b46 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -131,6 +131,11 @@ SYNCHRONIZATION_MESSAGE, rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer); } break; + case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED: + if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ + rVal = EntityMessage.parseSpawnFoliageSeedMessage(byteBuffer); + } + break; } break; case TypeBytes.MESSAGE_TYPE_LORE: diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index a3c5bd2e..cbedff68 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -35,6 +35,7 @@ Message categories public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYSTRING = 15; public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM = 16; public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 17; + public static final byte ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED = 18; /* Entity packet sizes */ diff --git a/src/main/java/electrosphere/renderer/Mesh.java b/src/main/java/electrosphere/renderer/Mesh.java index 688004ff..8b1ba100 100644 --- a/src/main/java/electrosphere/renderer/Mesh.java +++ b/src/main/java/electrosphere/renderer/Mesh.java @@ -164,7 +164,7 @@ public class Mesh { Matrix4d vertexPretransform = new Matrix4d().identity(); if(metadata != null){ - System.out.println("Pretransforming"); + LoggerInterface.loggerRenderer.DEBUG("Pretransforming"); vertexPretransform.translationRotateScale(metadata.getOffset(), metadata.getRotation(), metadata.getScale()); } diff --git a/src/main/java/electrosphere/server/content/EnvironmentGenerator.java b/src/main/java/electrosphere/server/content/EnvironmentGenerator.java index 8a66cc19..5abd5f75 100644 --- a/src/main/java/electrosphere/server/content/EnvironmentGenerator.java +++ b/src/main/java/electrosphere/server/content/EnvironmentGenerator.java @@ -3,12 +3,20 @@ package electrosphere.server.content; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.foliage.FoliageUtils; +import electrosphere.entity.types.tree.ProceduralTree; +import electrosphere.logger.LoggerInterface; +import electrosphere.server.datacell.GriddedDataCellManager; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.terrain.manager.ServerTerrainChunk; import java.util.List; import java.util.Random; + +import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector3i; @@ -19,9 +27,10 @@ import org.joml.Vector3i; public class EnvironmentGenerator { - public static void generatePlains(ServerDataCell cell, Vector3i worldPos, long randomizer){ + public static void generatePlains(Realm realm, ServerDataCell cell, Vector3i worldPos, long randomizer){ Random rand = new Random(randomizer); int targetNum = (int)(rand.nextFloat() * 10) + 10; + LoggerInterface.loggerGameLogic.DEBUG("generate plains"); for(int i = 0; i < targetNum; i++){ // Entity newTree = FoliageUtils.spawnBasicFoliage("FallOak1"); // cell.getScene().registerEntity(newTree); @@ -33,4 +42,18 @@ public class EnvironmentGenerator { // EntityUtils.getPosition(newTree).set(posX,posY,posZ); } } + + public static void generateForest(Realm realm, ServerDataCell cell, Vector3i worldPos, long randomizer){ + Random rand = new Random(randomizer); + int targetNum = (int)(rand.nextFloat() * 5) + 5; + LoggerInterface.loggerGameLogic.DEBUG("generate forest"); + for(int i = 0; i < targetNum; i++){ + Vector3d position = new Vector3d( + Globals.serverWorldData.convertWorldToReal(worldPos.x) + rand.nextFloat() * 5, + 0, + Globals.serverWorldData.convertWorldToReal(worldPos.z) + rand.nextFloat() * 5 + ); + Entity tree = FoliageUtils.serverSpawnTreeFoliage(realm, position, "oak", rand.nextLong()); + } + } } diff --git a/src/main/java/electrosphere/server/content/ServerContentManager.java b/src/main/java/electrosphere/server/content/ServerContentManager.java index 97d5e5e5..3ca905f4 100644 --- a/src/main/java/electrosphere/server/content/ServerContentManager.java +++ b/src/main/java/electrosphere/server/content/ServerContentManager.java @@ -3,26 +3,37 @@ package electrosphere.server.content; import org.joml.Vector3i; import electrosphere.engine.Globals; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.pathfinding.NavMeshUtils; public class ServerContentManager { + + + private ServerContentManager(){ + + } + + public static ServerContentManager createServerContentManager(){ + return new ServerContentManager(); + } - public void generateContentForDataCell(Vector3i worldPos, ServerDataCell cell){ + public void generateContentForDataCell(Realm realm, Vector3i worldPos, ServerDataCell cell){ if(!Globals.serverWorldData.isArena()){ //in other words, if not arena mode //if on disk (has already been generated) //else create from scratch - EnvironmentGenerator.generatePlains(cell, worldPos, 0); + EnvironmentGenerator.generateForest(realm, cell, worldPos, 0); } - cell.setNavMesh( - NavMeshUtils.createMeshFromChunk(Globals.serverTerrainManager.getChunk( - worldPos.x, - worldPos.y, - worldPos.z - ), - Globals.navMeshManager.getBlockerCache().getBlocker(worldPos.x, worldPos.z)) - ); + //TODO: generate navmesh + // cell.setNavMesh( + // NavMeshUtils.createMeshFromChunk(Globals.serverTerrainManager.getChunk( + // worldPos.x, + // worldPos.y, + // worldPos.z + // ), + // Globals.navMeshManager.getBlockerCache().getBlocker(worldPos.x, worldPos.z)) + // ); } diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 1a95a257..c83c2c1d 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -17,6 +17,7 @@ import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.player.Player; +import electrosphere.server.content.ServerContentManager; import electrosphere.server.datacell.interfaces.DataCellManager; import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.physics.PhysicsDataCell; @@ -44,14 +45,17 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager ServerTerrainManager serverTerrainManager; //lock for terrain editing Semaphore terrainEditLock = new Semaphore(1); + //manager for getting entities to fill in a cell + ServerContentManager serverContentManager; /** * Constructor * @param parent The gridded data cell manager's parent realm */ - public GriddedDataCellManager(Realm parent, ServerTerrainManager serverTerrainManager) { + public GriddedDataCellManager(Realm parent, ServerTerrainManager serverTerrainManager, ServerContentManager serverContentManager) { this.parent = parent; this.serverTerrainManager = serverTerrainManager; + this.serverContentManager = serverContentManager; } /** @@ -389,6 +393,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager ServerDataCell rVal = parent.createNewCell(); groundDataCells.put(getServerDataCellKey(worldPos),rVal); cellPositionMap.put(rVal,new Vector3i(worldPos)); + serverContentManager.generateContentForDataCell(parent, worldPos, rVal); return rVal; } @@ -450,7 +455,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager * @param cell The data cell * @return The world position */ - private Vector3i getCellWorldPosition(ServerDataCell cell){ + public Vector3i getCellWorldPosition(ServerDataCell cell){ return cellPositionMap.get(cell); } diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java index bb87f791..06509805 100644 --- a/src/main/java/electrosphere/server/datacell/RealmManager.java +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -53,7 +53,7 @@ public class RealmManager { //create realm Realm realm = new Realm(collisionEngine, new HitboxManager()); //create function classes - GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm,Globals.serverTerrainManager); + GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm,Globals.serverTerrainManager,Globals.serverContentManager); EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper(); //init gridded manager griddedDataCellManager.init(serverWorldData); diff --git a/src/main/java/electrosphere/server/datacell/ServerDataCell.java b/src/main/java/electrosphere/server/datacell/ServerDataCell.java index cb48169f..c49b996d 100644 --- a/src/main/java/electrosphere/server/datacell/ServerDataCell.java +++ b/src/main/java/electrosphere/server/datacell/ServerDataCell.java @@ -4,6 +4,7 @@ import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.Scene; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.foliage.FoliageUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.structure.StructureUtils; import electrosphere.game.server.character.Character; @@ -153,6 +154,9 @@ public class ServerDataCell { if(StructureUtils.isStructure(entity)){ StructureUtils.sendStructureToPlayer(player, entity); } + if(FoliageUtils.isFoliage(entity)){ + FoliageUtils.sendFoliageToPlayer(player, entity); + } } diff --git a/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java index d7479b03..b6fa1263 100644 --- a/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java @@ -37,6 +37,14 @@ public interface DataCellManager { */ public ServerDataCell getDataCellAtPoint(Vector3d point); + + /** + * Gets the world position of a given data cell + * @param cell The data cell + * @return The world position + */ + public Vector3i getCellWorldPosition(ServerDataCell cell); + /** * Tries to create a data cell at a given real point * @param point The real point diff --git a/src/main/java/electrosphere/server/saves/SaveUtils.java b/src/main/java/electrosphere/server/saves/SaveUtils.java index 2a625bde..e86184fa 100644 --- a/src/main/java/electrosphere/server/saves/SaveUtils.java +++ b/src/main/java/electrosphere/server/saves/SaveUtils.java @@ -5,6 +5,7 @@ import java.util.List; import electrosphere.engine.Globals; import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; +import electrosphere.server.content.ServerContentManager; import electrosphere.server.db.DatabaseUtils; import electrosphere.server.terrain.generation.OverworldChunkGenerator; import electrosphere.server.terrain.generation.interfaces.ChunkGenerator; @@ -111,6 +112,7 @@ public class SaveUtils { Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0,new OverworldChunkGenerator()); SaveUtils.loadTerrainAndDB(currentSaveName); Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); + Globals.serverContentManager = ServerContentManager.createServerContentManager(); Globals.realmManager.createGriddedRealm(Globals.serverWorldData); return true; } diff --git a/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java b/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java index da89966d..9d73aadd 100644 --- a/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java +++ b/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java @@ -60,10 +60,10 @@ public class ChunkDiskMap { * @param saveName The save name */ public void init(String saveName){ - System.out.println("INIT CHUNK MAP " + saveName); + LoggerInterface.loggerEngine.DEBUG("INIT CHUNK MAP " + saveName); if(FileUtils.getSaveFile(saveName, "chunk.map").exists()){ worldPosFileMap = FileUtils.loadObjectFromSavePath(saveName, "chunk.map", Map.class); - System.out.println("POS FILE MAP: " + worldPosFileMap.keySet()); + LoggerInterface.loggerEngine.DEBUG("POS FILE MAP: " + worldPosFileMap.keySet()); } else { worldPosFileMap = new HashMap(); } @@ -106,7 +106,7 @@ public class ChunkDiskMap { * @return The server terrain chunk if it exists, null otherwise */ public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){ - System.out.println("Load chunk " + worldX + " " + worldY + " " + worldZ); + LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ); ServerTerrainChunk rVal = null; if(containsTerrainAtPosition(worldX, worldY, worldZ)){ //read file