From 755db7ba72551faf9fb3502c23d3c45c6b70c372 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 13 Nov 2024 18:55:02 -0500 Subject: [PATCH] editor entity support --- assets/Data/entity/foliage.json | 26 ++++++ assets/Shaders/FragmentShader.fs | 4 +- buildNumber.properties | 4 +- docs/src/progress/renderertodo.md | 4 + .../ui/menu/debug/ImGuiPlayerEntity.java | 11 +++ .../debug/entity/ImGuiEntityHitboxTab.java | 81 ++++++++++++++++ .../menu/debug/entity/ImGuiEntityMacros.java | 46 ++++++---- .../controls/ControlHandler.java | 14 +++ .../java/electrosphere/engine/Globals.java | 2 +- .../ChunkGenerationTestLoading.java | 1 - .../loadingthreads/LevelEditorLoading.java | 1 - .../engine/loadingthreads/LoadingUtils.java | 7 +- .../entity/ClientEntityUtils.java | 3 + .../entity/state/attach/AttachUtils.java | 22 ++--- .../state/hitbox/HitboxCollectionState.java | 92 ++++++++++++++++--- .../groundmove/ClientGroundMovementTree.java | 9 +- .../entity/types/creature/CreatureUtils.java | 6 +- .../client/protocol/CharacterProtocol.java | 1 + .../parser/net/message/CharacterMessage.java | 32 +++++++ .../parser/net/message/NetworkMessage.java | 5 + .../net/parser/net/message/TypeBytes.java | 2 + .../net/server/ServerConnectionHandler.java | 8 ++ .../net/server/player/Player.java | 9 ++ .../server/protocol/CharacterProtocol.java | 91 +++++++++++++++++- .../client/ClientSynchronizationManager.java | 1 - .../character/PlayerCharacterCreation.java | 4 +- .../content/ServerContentGenerator.java | 80 ++++++++-------- 27 files changed, 466 insertions(+), 100 deletions(-) create mode 100644 src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityHitboxTab.java diff --git a/assets/Data/entity/foliage.json b/assets/Data/entity/foliage.json index 91414b02..1916bd80 100644 --- a/assets/Data/entity/foliage.json +++ b/assets/Data/entity/foliage.json @@ -167,6 +167,32 @@ "TREE", "FLAMMABLE" ], + "hitboxes" : [ + { + "type": "hurt", + "offset": [0, 0.045, 0], + "radius": 0.175 + }, + { + "type": "hurt", + "offset": [0, 0.6, 0], + "radius": 0.175 + }, + { + "type": "hurt", + "offset": [0, 1.2, 0], + "radius": 0.175 + }, + { + "type": "hurt", + "offset": [0, 1.8, 0], + "radius": 0.175 + } + ], + "healthSystem" : { + "maxHealth" : 100, + "onDamageIFrames" : 5 + }, "graphicsTemplate": { "model": { "path" : "Models/foliage/tree4.glb" diff --git a/assets/Shaders/FragmentShader.fs b/assets/Shaders/FragmentShader.fs index 73c132a7..9606e939 100644 --- a/assets/Shaders/FragmentShader.fs +++ b/assets/Shaders/FragmentShader.fs @@ -119,7 +119,7 @@ void main(){ vec3 textureColor = texture(material.diffuse, TexCoord).rgb; //shadow - float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm); + float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), -norm); // //point light calculations @@ -259,5 +259,5 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){ // shadow = currentDepth; - return shadow; + return clamp(1.0 - shadow, 0.0, 0.7); } \ No newline at end of file diff --git a/buildNumber.properties b/buildNumber.properties index f5e3fc8f..42dfb1d4 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Wed Nov 13 13:33:32 EST 2024 -buildNumber=381 +#Wed Nov 13 15:53:18 EST 2024 +buildNumber=382 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 9237f530..5e090a7b 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1012,6 +1012,10 @@ Work on making chunk reloading less obvious Fix default chunk generator Fix unit test Fix missing data on katana item +Ability to replacing a player's entity +Fix shadows on main shader +Button to swap between player entity and editor entity +Fix physics being disabled on editing a level diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java index 2fb3a708..f3726c48 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java @@ -11,6 +11,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.state.attack.ClientAttackTree; import electrosphere.entity.state.server.ServerPlayerViewDirTree; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; import electrosphere.server.datacell.utils.EntityLookupUtils; @@ -72,10 +73,20 @@ public class ImGuiPlayerEntity { ImGuiEntityMacros.showEntity(Globals.playerEntity); } ImGui.sameLine(); + + // + //swap editor/noneditor + if(ImGui.button("Swap Entity")){ + Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructEditorSwapMessage()); + } + ImGui.sameLine(); + + if(ImGui.button("1st Person Details")){ ImGuiEntityMacros.showEntity(Globals.firstPersonEntity); } ImGui.sameLine(); + if(ImGui.button("Server Details")){ int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId()); Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity); diff --git a/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityHitboxTab.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityHitboxTab.java new file mode 100644 index 00000000..3b3bbd59 --- /dev/null +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityHitboxTab.java @@ -0,0 +1,81 @@ +package electrosphere.client.ui.menu.debug.entity; + +import java.util.LinkedList; +import java.util.List; + +import org.ode4j.ode.DGeom; +import org.ode4j.ode.DSphere; + +import electrosphere.entity.Entity; +import electrosphere.entity.state.hitbox.HitboxCollectionState; +import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState; +import electrosphere.game.data.collidable.HitboxData; +import imgui.ImGui; + +/** + * Tab for viewing and editing data about hitboxes + */ +public class ImGuiEntityHitboxTab { + + /** + * Minimum offset value + */ + static final float MIN_OFFSET = -10; + + /** + * Maximum offset value + */ + static final float MAX_OFFSET = 10; + + /** + * Weights used for the slider + */ + static float[] weights = new float[3]; + + /** + * Scale storage + */ + static float[] scale = new float[1]; + + /** + * Hitbox data view + */ + protected static void drawHitboxTab(boolean show, Entity detailViewEntity){ + if(show && ImGui.collapsingHeader("Hitbox Data")){ + ImGui.indent(); + if(detailViewEntity != null && HitboxCollectionState.hasHitboxState(detailViewEntity)){ + HitboxCollectionState hitboxCollectionState = HitboxCollectionState.getHitboxState(detailViewEntity); + + int i = 0; + for(HitboxState state : hitboxCollectionState.getHitboxes()){ + HitboxData data = state.getHitboxData(); + String name = "[" + i + "] "; + if(state.getBoneName() != null){ + name = name + " " + state.getBoneName(); + } + if(ImGui.collapsingHeader(name)){ + if(ImGui.sliderFloat3("Offset", weights, MIN_OFFSET, MAX_OFFSET)){ + List values = new LinkedList(); + values.add((double)weights[0]); + values.add((double)weights[1]); + values.add((double)weights[2]); + data.setOffset(values); + } + if(ImGui.sliderFloat("Scale", scale, MIN_OFFSET, MAX_OFFSET)){ + data.setRadius(scale[0]); + DGeom geom = hitboxCollectionState.getGeom(state); + if(geom instanceof DSphere){ + DSphere sphere = (DSphere)geom; + sphere.setRadius(scale[0]); + } + } + } + i++; + } + + } + ImGui.unindent(); + } + } + +} diff --git a/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java index 6b273d57..8fc54915 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java @@ -17,6 +17,7 @@ import electrosphere.entity.state.AnimationPriorities; import electrosphere.entity.state.attach.AttachUtils; import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.equip.ClientEquipState; +import electrosphere.entity.state.hitbox.HitboxCollectionState; import electrosphere.entity.state.server.ServerPlayerViewDirTree; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.foliage.FoliageUtils; @@ -54,6 +55,7 @@ public class ImGuiEntityMacros { //tree node values private static boolean showDataTab = false; //show all data names stored in the entity private static boolean showActorTab = false; //show the actor tab + private static boolean showHitboxTab = false; //show the hitbox tab private static boolean showInstancedActorTab = false; //show the instanced actor tab private static boolean showPoseActorTab = false; //show the pose actor tab private static boolean showEquipStateTab = false; //actor details @@ -66,8 +68,8 @@ public class ImGuiEntityMacros { * Creates the windows in this file */ public static void createClientEntityWindows(){ - createClientEntityDetailWindow(); - createClientEntitySelectionWindow(); + ImGuiEntityMacros.createClientEntityDetailWindow(); + ImGuiEntityMacros.createClientEntitySelectionWindow(); } /** @@ -142,7 +144,13 @@ public class ImGuiEntityMacros { showFirstPersonTab = !showFirstPersonTab; } if( - (AttachUtils.hasChildren(detailViewEntity) || AttachUtils.getParent(detailViewEntity) != null || detailViewEntity == Globals.firstPersonEntity || detailViewEntity == Globals.playerEntity) && + ( + AttachUtils.hasChildren(detailViewEntity) || + AttachUtils.getParent(detailViewEntity) != null || + detailViewEntity == Globals.firstPersonEntity || + detailViewEntity == Globals.playerEntity || + Globals.clientSceneWrapper.clientToServerMapContainsId(detailViewEntity.getId()) + ) && ImGui.checkbox("Linked entities`", showLinkedEntitiesTab) ){ showLinkedEntitiesTab = !showLinkedEntitiesTab; @@ -153,18 +161,22 @@ public class ImGuiEntityMacros { if(PhysicsEntityUtils.getDBody(detailViewEntity) != null && ImGui.checkbox("Physics", showPhysicsTab)){ showPhysicsTab = !showPhysicsTab; } + if(HitboxCollectionState.hasHitboxState(detailViewEntity) && ImGui.checkbox("Hitbox State", showHitboxTab)){ + showHitboxTab = !showHitboxTab; + } ImGui.treePop(); } ImGui.nextColumn(); ImGuiEntityActorTab.drawActorView(showActorTab,detailViewEntity); ImGuiEntityInstancedActorTab.drawInstancedActorView(showInstancedActorTab, detailViewEntity); - drawPoseActor(); - drawEquipState(); - drawFirstPersonView(); - drawLinkedEntities(); - drawServerViewDir(); - drawPhysicsDetails(); - drawDataView(); + ImGuiEntityHitboxTab.drawHitboxTab(showHitboxTab,detailViewEntity); + ImGuiEntityMacros.drawPoseActor(); + ImGuiEntityMacros.drawEquipState(); + ImGuiEntityMacros.drawFirstPersonView(); + ImGuiEntityMacros.drawLinkedEntities(); + ImGuiEntityMacros.drawServerViewDir(); + ImGuiEntityMacros.drawPhysicsDetails(); + ImGuiEntityMacros.drawDataView(); } }); clientEntityDetailWindow.setOpen(false); @@ -412,18 +424,18 @@ public class ImGuiEntityMacros { if(showLinkedEntitiesTab && ImGui.collapsingHeader("Linked entities")){ ImGui.indent(); if(detailViewEntity == Globals.playerEntity && ImGui.button("View Model")){ - showEntity(Globals.firstPersonEntity); + ImGuiEntityMacros.showEntity(Globals.firstPersonEntity); } if(detailViewEntity == Globals.firstPersonEntity && ImGui.button("3rd Person Model")){ - showEntity(Globals.playerEntity); + ImGuiEntityMacros.showEntity(Globals.playerEntity); } if(AttachUtils.getParent(detailViewEntity) != null && ImGui.button("Parent")){ - showEntity(AttachUtils.getParent(detailViewEntity)); + ImGuiEntityMacros.showEntity(AttachUtils.getParent(detailViewEntity)); } if(AttachUtils.hasChildren(detailViewEntity) && ImGui.collapsingHeader("Children")){ for(Entity child : AttachUtils.getChildrenList(detailViewEntity)){ if(ImGui.button("Child " + child.getId())){ - showEntity(child); + ImGuiEntityMacros.showEntity(child); } } } @@ -432,7 +444,7 @@ public class ImGuiEntityMacros { for(String equippedPoint : clientEquipState.getEquippedPoints()){ Entity entity = clientEquipState.getEquippedItemAtPoint(equippedPoint); if(ImGui.button("Slot: " + equippedPoint)){ - showEntity(entity); + ImGuiEntityMacros.showEntity(entity); } } } @@ -442,7 +454,7 @@ public class ImGuiEntityMacros { int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(detailViewEntity.getId()); Entity serverEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity); if(serverEntity != null && ImGui.button("Server Entity")){ - showEntity(serverEntity); + ImGuiEntityMacros.showEntity(serverEntity); } } else if(Globals.clientSceneWrapper.containsServerId(detailViewEntity.getId())){ //detailViewEntity is a server entity @@ -450,7 +462,7 @@ public class ImGuiEntityMacros { int clientId = Globals.clientSceneWrapper.mapServerToClientId(detailViewEntity.getId()); Entity clientEntity = Globals.clientSceneWrapper.getScene().getEntityFromId(clientId); if(clientEntity != null && ImGui.button("Client Entity")){ - showEntity(clientEntity); + ImGuiEntityMacros.showEntity(clientEntity); } } ImGui.unindent(); diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 0d88d51b..89ae0eea 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -104,6 +104,7 @@ import electrosphere.entity.state.movement.sprint.ClientSprintTree; import electrosphere.entity.state.movement.walk.ClientWalkTree; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.logger.LoggerInterface; +import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.renderer.ui.elements.Window; import electrosphere.renderer.ui.events.ClickEvent; import electrosphere.renderer.ui.events.KeyboardEvent; @@ -209,6 +210,7 @@ public class ControlHandler { //debug public static final String DEBUG_FRAMESTEP = "framestep"; public static final String DEBUG_OPEN_DEBUG_MENU = "openDebugMenu"; + public static final String DEBUG_SWAP_EDITOR_MODE = "swapEditorMode"; //freecam public static final String FREECAM_UP = "freecamUp"; @@ -432,6 +434,7 @@ public class ControlHandler { */ handler.addControl(DATA_STRING_INPUT_CODE_DEBUG_SPAWN_ITEM, new Control(ControlType.KEY,GLFW_KEY_Q,false,"","")); handler.addControl(DEBUG_OPEN_DEBUG_MENU, new Control(ControlType.KEY, GLFW_KEY_F2,false,"Debug Menu","Opens the debug menu")); + handler.addControl(DEBUG_SWAP_EDITOR_MODE, new Control(ControlType.KEY, GLFW_KEY_F4,false,"Swap Editor Mode","Swaps to/from the editor entity")); /* return @@ -1196,6 +1199,17 @@ public class ControlHandler { }}); controls.get(DEBUG_FRAMESTEP).setRepeatTimeout(0.5f * Main.targetFrameRate); // RenderingEngine.incrementOutputFramebuffer(); + + + // + //Swap to/from editor entity + // + alwaysOnDebugControlList.add(controls.get(DEBUG_SWAP_EDITOR_MODE)); + controls.get(DEBUG_SWAP_EDITOR_MODE).setOnPress(new ControlMethod(){public void execute(){ + LoggerInterface.loggerEngine.INFO("Swap to/from editor entity"); + Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructEditorSwapMessage()); + }}); + controls.get(DEBUG_SWAP_EDITOR_MODE).setRepeatTimeout(0.5f * Main.targetFrameRate); } void setAlwaysOnDebugControls(){ diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index f2643a53..b3bde10a 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -167,7 +167,7 @@ public class Globals { public static boolean RUN_DEMO = false; public static boolean RUN_CLIENT = true; public static boolean RUN_HIDDEN = false; //glfw session will be created with hidden window - public static boolean RUN_AUDIO = false; + public static boolean RUN_AUDIO = true; public static boolean RUN_SCRIPTS = true; public static boolean RUN_PHYSICS = true; //toggles whether physics is run or not public static int clientCharacterID; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ChunkGenerationTestLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ChunkGenerationTestLoading.java index a34f2f70..777029a3 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ChunkGenerationTestLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ChunkGenerationTestLoading.java @@ -31,7 +31,6 @@ public class ChunkGenerationTestLoading { // Globals.RUN_CLIENT = true; Globals.RUN_SERVER = true; - Globals.RUN_PHYSICS = false; Globals.aiManager.setActive(false); diff --git a/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java b/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java index 9c12b4bd..06a95a8d 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java @@ -51,7 +51,6 @@ public class LevelEditorLoading { // Globals.RUN_CLIENT = true; Globals.RUN_SERVER = true; - Globals.RUN_PHYSICS = false; Globals.aiManager.setActive(false); diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java index aee1994d..b73df3dd 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java @@ -36,6 +36,11 @@ public class LoadingUtils { * The size of the buffer */ static final int STREAM_BUFFER_SIZE = 16 * 1024 * 1024; + + /** + * The name of the editor race + */ + public static final String EDITOR_RACE_NAME = "editor"; @@ -139,7 +144,7 @@ public class LoadingUtils { //Create entity // //send default template back - String race = "editor"; + String race = EDITOR_RACE_NAME; if(!isEditor){ List races = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces(); race = races.get(new Random().nextInt(races.size())); diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java index f1ebf60f..fabb61c4 100644 --- a/src/main/java/electrosphere/entity/ClientEntityUtils.java +++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java @@ -64,6 +64,9 @@ public class ClientEntityUtils { if(Globals.clientScene != null){ Globals.clientScene.deregisterEntity(entity); } + if(entity == Globals.playerEntity && Globals.firstPersonEntity != null){ + ClientEntityUtils.destroyEntity(Globals.firstPersonEntity); + } } } diff --git a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java index f4d5b271..9603e12d 100644 --- a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java @@ -48,8 +48,8 @@ public class AttachUtils { */ public static void serverUpdateAttachedEntityPositions(ServerDataCell cell){ Globals.profiler.beginAggregateCpuSample("AttachUtils.serverUpdateAttachedEntityPositions"); - serverUpdateBoneAttachedEntityPositions(cell); - serverUpdateNonBoneAttachments(cell); + AttachUtils.serverUpdateBoneAttachedEntityPositions(cell); + AttachUtils.serverUpdateNonBoneAttachments(cell); Globals.profiler.endCpuSample(); } @@ -62,7 +62,7 @@ public class AttachUtils { Entity parent; if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ String targetBone; - if((targetBone = getTargetBone(currentEntity))!=null){ + if((targetBone = AttachUtils.getTargetBone(currentEntity))!=null){ PoseActor parentActor = EntityUtils.getPoseActor(parent); //manual offset @@ -71,7 +71,7 @@ public class AttachUtils { offset = new Vector3d(); } - calculateEntityTransforms( + AttachUtils.calculateEntityTransforms( currentEntity, new Vector3d(offset), new Quaterniond(AttachUtils.getRotationOffset(currentEntity)), @@ -106,7 +106,7 @@ public class AttachUtils { //update entities attached to centerpoint + transform of other entities for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.TRANSFORM_ATTACHED)){ if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ - if((transform = getTransformOffset(currentEntity))!=null){ + if((transform = AttachUtils.getTransformOffset(currentEntity))!=null){ //parent objects Vector3d parentPosition = EntityUtils.getPosition(parent); Quaterniond parentRotation = EntityUtils.getRotation(parent); @@ -163,8 +163,8 @@ public class AttachUtils { */ public static void clientUpdateAttachedEntityPositions(){ Globals.profiler.beginCpuSample("AttachUtils.clientUpdateAttachedEntityPositions"); - clientUpdateBoneAttachments(); - clientUpdateNonBoneAttachments(); + AttachUtils.clientUpdateBoneAttachments(); + AttachUtils.clientUpdateNonBoneAttachments(); Globals.profiler.endCpuSample(); } @@ -179,7 +179,7 @@ public class AttachUtils { if(currentEntity == null){ LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Trying to update client bone attachment where null entity is registered!")); } else if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ - clientUpdateEntityTransforms(currentEntity,parent); + AttachUtils.clientUpdateEntityTransforms(currentEntity,parent); } else if(currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BASE)!=null){ Vector3d positionOffset = getVectorOffset(currentEntity); Vector3d parentPosition = EntityUtils.getPosition(parent); @@ -196,7 +196,7 @@ public class AttachUtils { */ public static void clientUpdateEntityTransforms(Entity child, Entity parent){ String targetBone; - if((targetBone = getTargetBone(child))!=null){ + if((targetBone = AttachUtils.getTargetBone(child))!=null){ Actor parentActor = EntityUtils.getActor(parent); //manual offset @@ -205,7 +205,7 @@ public class AttachUtils { offset = new Vector3d(); } - calculateEntityTransforms( + AttachUtils.calculateEntityTransforms( child, new Vector3d(offset), new Quaterniond(AttachUtils.getRotationOffset(child)), @@ -233,7 +233,7 @@ public class AttachUtils { //update entities attached to centerpoint + transform of other entities for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.TRANSFORM_ATTACHED)){ if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ - if((transform = getTransformOffset(currentEntity))!=null){ + if((transform = AttachUtils.getTransformOffset(currentEntity))!=null){ //parent objects Vector3d parentPosition = EntityUtils.getPosition(parent); Quaterniond parentRotation = EntityUtils.getRotation(parent); diff --git a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java index 8da689a0..f46039db 100644 --- a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java +++ b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java @@ -70,6 +70,16 @@ public class HitboxCollectionState { //the map of geometry -> hitbox shape status, useful for finding data about a given hitbox during collision Map geomStateMap = new HashMap(); + /** + * The list of all hitbox states + */ + List allStates = new LinkedList(); + + /** + * The list of non-bone hitboxes + */ + List nonBoneHitboxes = new LinkedList(); + //callback to provide a position for the hitbox each frame HitboxPositionCallback positionCallback; @@ -162,7 +172,7 @@ public class HitboxCollectionState { if(hitboxDataRaw.getBone() != null){ rVal.addHitbox(hitboxDataRaw.getBone(),state); } else { - LoggerInterface.loggerEngine.WARNING("Trying to attach hitbox to bone where bone cannot be found: " + hitboxDataRaw.getBone()); + rVal.addHitbox(state); } rVal.registerGeom(geom,state); } @@ -262,12 +272,20 @@ public class HitboxCollectionState { } } } - } else if(positionCallback != null){ - DGeom geom = body.getGeomIterator().next(); - Vector3d worldPosition = this.positionCallback.getPosition(); - Quaterniond rotation = new Quaterniond().identity(); - - PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation); + for(HitboxState state : this.nonBoneHitboxes){ + DGeom geom = this.stateGeomMap.get(state); + HitboxState shapeStatus = this.geomStateMap.get(geom); + switch(shapeStatus.shapeType){ + case SPHERE: { + this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null); + } break; + case CAPSULE: { + this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null); + } break; + case STATIC_CAPSULE: { + } break; + } + } } //update bone-attached hitboxes on server @@ -298,20 +316,31 @@ public class HitboxCollectionState { } } } - } else if(positionCallback != null){ - DGeom geom = body.getGeomIterator().next(); - Vector3d worldPosition = this.positionCallback.getPosition(); - Quaterniond rotation = new Quaterniond().identity(); - - PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation); + for(HitboxState state : this.nonBoneHitboxes){ + DGeom geom = this.stateGeomMap.get(state); + HitboxState shapeStatus = this.geomStateMap.get(geom); + switch(shapeStatus.shapeType){ + case SPHERE: { + this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null); + } break; + case CAPSULE: { + this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null); + } break; + case STATIC_CAPSULE: { + } break; + } + } } + //update non-bone attached static objects on server } else if(parent != null && isServer){ for(DGeom geom : this.geoms){ HitboxState shapeStatus = this.geomStateMap.get(geom); switch(shapeStatus.shapeType){ case SPHERE: { + this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null); } break; case CAPSULE: { + this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null); } break; case STATIC_CAPSULE: { this.updateStaticCapsulePosition(collisionEngine, geom, shapeStatus); @@ -346,7 +375,10 @@ public class HitboxCollectionState { Quaterniond offsetRotation = new Quaterniond(); //the bone's transform - Vector3d bonePositionD = new Vector3d(bonePosition); + Vector3d bonePositionD = new Vector3d(); + if(bonePosition != null){ + bonePositionD = new Vector3d(bonePosition); + } Quaterniond boneRotation = new Quaterniond(); //the parent's transform @@ -380,7 +412,10 @@ public class HitboxCollectionState { Quaterniond offsetRotation = new Quaterniond(); //the bone's transform - Vector3d bonePositionD = new Vector3d(bonePosition); + Vector3d bonePositionD = new Vector3d(); + if(bonePosition != null){ + bonePositionD = new Vector3d(bonePosition); + } Quaterniond boneRotation = new Quaterniond(); //the parent's transform @@ -453,6 +488,15 @@ public class HitboxCollectionState { return this.geomStateMap.get(geom); } + /** + * Gets the geom from the state object + * @param state The state object + * @return The associated geom + */ + public DGeom getGeom(HitboxState state){ + return this.stateGeomMap.get(state); + } + /** * Gets the hitbox state of the entity * @param entity the entity @@ -533,6 +577,14 @@ public class HitboxCollectionState { return this.geoms; } + /** + * Gets the list of all hitboxes + * @return The list of all hitboxes + */ + public List getHitboxes(){ + return this.allStates; + } + /** * Gets the hitboxes associated with a bone * @param bone The bone @@ -555,6 +607,16 @@ public class HitboxCollectionState { states.add(state); this.boneHitboxMap.put(bone,states); } + this.allStates.add(state); + } + + /** + * Adds a hitbox with an offset + * @param state The hitbox + */ + private void addHitbox(HitboxState state){ + this.nonBoneHitboxes.add(state); + this.allStates.add(state); } /** diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java index 43bea2bf..5c724f94 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java @@ -204,7 +204,14 @@ public class ClientGroundMovementTree implements BehaviorTree { Vector3d facingVector = CreatureUtils.getFacingVector(parent); float maxNaturalVelocity = ServerGroundMovementTree.getMaximumVelocity(parent, this.groundMovementData, facing); DBody body = PhysicsEntityUtils.getDBody(parent); - DVector3C linearVelocity = body.getLinearVel(); + DVector3C linearVelocity = null; + + //body can be null if the behavior tree wasn't detatched for some reason + if(body != null){ + linearVelocity = body.getLinearVel(); + } else { + return; + } // //rotation update diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 8bc40bbb..17bbd6ed 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -403,12 +403,12 @@ public class CreatureUtils { LoggerInterface.loggerNetworking.INFO("Sending controller packets"); player.addMessage(NetUtils.createSetCreatureControllerIdEntityMessage(creature)); Player entityOwner = Globals.playerManager.getPlayerFromId(CreatureUtils.getControllerPlayerId(creature)); + if(player.hasSentPlayerEntity()){ + throw new Error("Re-sending player entity to player!"); + } if(entityOwner == player){ player.setHasSentPlayerEntity(true); } - if(Globals.playerEntity != null && player.getId() == Globals.clientPlayer.getId() && player.getPlayerEntity() == creature){ - throw new Error("Re-sending player entity to player!"); - } } } diff --git a/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java index 80e2d73c..eb6ed320 100644 --- a/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java @@ -33,6 +33,7 @@ public class CharacterProtocol implements ClientProtocolTemplate= TypeBytes.CHARACTER_MESSAGE_TYPE_EDITORSWAP_SIZE){ + return true; + } else { + return false; + } } return false; } @@ -301,6 +308,24 @@ public class CharacterMessage extends NetworkMessage { return rVal; } + /** + * Parses a message of type EditorSwap + */ + public static CharacterMessage parseEditorSwapMessage(CircularByteBuffer byteBuffer){ + CharacterMessage rVal = new CharacterMessage(CharacterMessageType.EDITORSWAP); + stripPacketHeader(byteBuffer); + return rVal; + } + + /** + * Constructs a message of type EditorSwap + */ + public static CharacterMessage constructEditorSwapMessage(){ + CharacterMessage rVal = new CharacterMessage(CharacterMessageType.EDITORSWAP); + rVal.serialize(); + return rVal; + } + @Override void serialize(){ byte[] intValues = new byte[8]; @@ -379,6 +404,13 @@ public class CharacterMessage extends NetworkMessage { rawBytes[6+i] = stringBytes[i]; } break; + case EDITORSWAP: + rawBytes = new byte[2]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER; + //entity messaage header + rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_EDITORSWAP; + 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 6e44b898..40a96433 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -299,6 +299,11 @@ public abstract class NetworkMessage { rVal = CharacterMessage.parseResponseSpawnCharacterMessage(byteBuffer); } break; + case TypeBytes.CHARACTER_MESSAGE_TYPE_EDITORSWAP: + if(CharacterMessage.canParseMessage(byteBuffer,secondByte)){ + rVal = CharacterMessage.parseEditorSwapMessage(byteBuffer); + } + break; } break; case TypeBytes.MESSAGE_TYPE_INVENTORY: 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 4d7256b2..b103a71a 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -127,6 +127,7 @@ public class TypeBytes { public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE = 4; public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER = 5; public static final byte CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER = 6; + public static final byte CHARACTER_MESSAGE_TYPE_EDITORSWAP = 7; /* Character packet sizes */ @@ -134,6 +135,7 @@ public class TypeBytes { public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE = 2; public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE = 2; public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE = 2; + public static final byte CHARACTER_MESSAGE_TYPE_EDITORSWAP_SIZE = 2; /* Inventory subcategories diff --git a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java index dfea176c..8e144085 100644 --- a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java +++ b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java @@ -390,10 +390,18 @@ public class ServerConnectionHandler implements Runnable { return Globals.RUN_SERVER && Globals.RUN_CLIENT && Globals.clientPlayer != null && this.playerID == Globals.clientPlayer.getId(); } + /** + * Sets the current creature template for the connection + * @param currentCreatureTemplate The new creature template + */ public void setCreatureTemplate(CreatureTemplate currentCreatureTemplate){ this.currentCreatureTemplate = currentCreatureTemplate; } + /** + * Gets the current creature template for the connection + * @return The current template + */ public CreatureTemplate getCurrentCreatureTemplate(){ return this.currentCreatureTemplate; } diff --git a/src/main/java/electrosphere/net/server/player/Player.java b/src/main/java/electrosphere/net/server/player/Player.java index 7167bc34..763f0fa7 100644 --- a/src/main/java/electrosphere/net/server/player/Player.java +++ b/src/main/java/electrosphere/net/server/player/Player.java @@ -2,6 +2,8 @@ package electrosphere.net.server.player; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.ServerConnectionHandler; @@ -141,7 +143,14 @@ public class Player { * @param playerEntity The player's entity */ public void setPlayerEntity(Entity playerEntity) { + boolean isReplacing = false; + if(this.playerEntity != null){ + isReplacing = true; + } this.playerEntity = playerEntity; + if(isReplacing){ + this.addMessage(EntityMessage.constructsetPropertyMessage(playerEntity.getId(), System.currentTimeMillis(), 0, CreatureUtils.getControllerPlayerId(playerEntity))); + } } /** diff --git a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java index 5c49901d..0dcd995f 100644 --- a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java @@ -1,12 +1,23 @@ package electrosphere.net.server.protocol; +import java.util.List; +import java.util.Random; + import org.joml.Vector3d; import electrosphere.engine.Globals; +import electrosphere.engine.loadingthreads.LoadingUtils; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.types.creature.CreatureTemplate; +import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem; +import electrosphere.game.data.creature.type.CreatureData; +import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.net.server.player.Player; import electrosphere.net.template.ServerProtocolTemplate; import electrosphere.server.character.PlayerCharacterCreation; import electrosphere.server.datacell.Realm; @@ -38,7 +49,10 @@ public class CharacterProtocol implements ServerProtocolTemplate races = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces(); + while(race.matches(LoadingUtils.EDITOR_RACE_NAME)){ + race = races.get(new Random().nextInt(races.size())); + } + //create template + CreatureData type = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(race); + CreatureTemplate template = CreatureTemplate.create(race); + for(VisualAttribute attribute : type.getVisualAttributes()){ + if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){ + float min = attribute.getMinValue(); + float max = attribute.getMaxValue(); + float defaultValue = min + (max - min)/2.0f; + //add attribute to creature template + template.putAttributeValue(attribute.getAttributeId(), defaultValue); + } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){ + template.putAttributeValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId()); + } + } + template.getCreatureToolbarData().setSlotItem("0", new ToolbarItem(71, "terrainTool")); + template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette")); + template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector")); + //set player character template + connectionHandler.setCreatureTemplate(template); + } else { + String race = LoadingUtils.EDITOR_RACE_NAME; + CreatureData type = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(race); + CreatureTemplate template = CreatureTemplate.create(race); + for(VisualAttribute attribute : type.getVisualAttributes()){ + if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){ + float min = attribute.getMinValue(); + float max = attribute.getMaxValue(); + float defaultValue = min + (max - min)/2.0f; + //add attribute to creature template + template.putAttributeValue(attribute.getAttributeId(), defaultValue); + } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){ + template.putAttributeValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId()); + } + } + template.getCreatureToolbarData().setSlotItem("0", new ToolbarItem(71, "terrainTool")); + template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette")); + template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector")); + //set player character template + connectionHandler.setCreatureTemplate(template); + } + + //destroy the old entity + Player player = connectionHandler.getPlayer(); + Entity playerEntity = player.getPlayerEntity(); + Vector3d position = EntityUtils.getPosition(playerEntity); + Globals.realmManager.getEntityRealm(playerEntity).getSpawnPoint().set(position); + ServerEntityUtils.destroyEntity(playerEntity); + + //spawn the new one + player.setHasSentPlayerEntity(false); + Entity newEntity = CharacterProtocol.spawnEntityForClient(connectionHandler); + ServerEntityUtils.repositionEntity(newEntity, position); + return newEntity; + } + } diff --git a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java index 962df178..9e82c6c4 100644 --- a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java @@ -2,7 +2,6 @@ package electrosphere.net.synchronization.client; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; -import electrosphere.util.Utilities; import electrosphere.entity.state.equip.ClientToolbarState; import electrosphere.entity.state.stance.ClientStanceComponent; import electrosphere.entity.state.movement.sprint.ClientSprintTree; diff --git a/src/main/java/electrosphere/server/character/PlayerCharacterCreation.java b/src/main/java/electrosphere/server/character/PlayerCharacterCreation.java index 67d2bb47..41ca56b2 100644 --- a/src/main/java/electrosphere/server/character/PlayerCharacterCreation.java +++ b/src/main/java/electrosphere/server/character/PlayerCharacterCreation.java @@ -22,7 +22,7 @@ public class PlayerCharacterCreation { * Spawns the player's character * @param connectionHandler The connection handler of the player */ - public static void spawnPlayerCharacter(ServerConnectionHandler connectionHandler){ + public static Entity spawnPlayerCharacter(ServerConnectionHandler connectionHandler){ Player playerObject = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId()); Realm realm = Globals.realmManager.getRealms().iterator().next(); @@ -56,6 +56,8 @@ public class PlayerCharacterCreation { if(searchedRealm == null){ LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Player entity created but not attached to a realm!")); } + + return newPlayerEntity; } /** diff --git a/src/main/java/electrosphere/server/content/ServerContentGenerator.java b/src/main/java/electrosphere/server/content/ServerContentGenerator.java index 934d8bff..149f7877 100644 --- a/src/main/java/electrosphere/server/content/ServerContentGenerator.java +++ b/src/main/java/electrosphere/server/content/ServerContentGenerator.java @@ -48,48 +48,48 @@ public class ServerContentGenerator { ); } - // //setup - // Random random = new Random(randomizer); + //setup + Random random = new Random(randomizer); - // //generate foliage - // BiomeData biome = null; - // if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){ - // biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z); - // } - // List foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions(); - // if(foliageDescriptions != null){ - // for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ - // for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ - // double height = realm.getServerWorldData().getServerTerrainManager().getElevation(worldPos.x, worldPos.z, x, z) + HEIGHT_MANUAL_ADJUSTMENT; - // if( - // realm.getServerWorldData().convertVoxelToRealSpace(0, worldPos.y) <= height && - // realm.getServerWorldData().convertVoxelToRealSpace(ServerTerrainChunk.CHUNK_DIMENSION, worldPos.y) > height - // ){ - // for(BiomeFoliageDescription foliageDescription : foliageDescriptions){ - // double scale = foliageDescription.getScale(); - // double regularity = foliageDescription.getRegularity(); - // double threshold = foliageDescription.getThreshold(); - // double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x); - // double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z); - // if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){ - // String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size())); - // FoliageUtils.serverSpawnTreeFoliage( - // realm, - // new Vector3d( - // realX, - // height, - // realZ - // ), - // type, - // random.nextLong() - // ); - // } - // } - // } - // } - // } - // } + //generate foliage + BiomeData biome = null; + if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){ + biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z); + } + List foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions(); + if(foliageDescriptions != null){ + for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ + for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ + double height = realm.getServerWorldData().getServerTerrainManager().getElevation(worldPos.x, worldPos.z, x, z) + HEIGHT_MANUAL_ADJUSTMENT; + if( + realm.getServerWorldData().convertVoxelToRealSpace(0, worldPos.y) <= height && + realm.getServerWorldData().convertVoxelToRealSpace(ServerTerrainChunk.CHUNK_DIMENSION, worldPos.y) > height + ){ + for(BiomeFoliageDescription foliageDescription : foliageDescriptions){ + double scale = foliageDescription.getScale(); + double regularity = foliageDescription.getRegularity(); + double threshold = foliageDescription.getThreshold(); + double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x); + double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z); + if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){ + String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size())); + FoliageUtils.serverSpawnTreeFoliage( + realm, + new Vector3d( + realX, + height, + realZ + ), + type, + random.nextLong() + ); + } + } + } + } + } + } }