editor entity support
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-11-13 18:55:02 -05:00
parent a32f6200cc
commit 755db7ba72
27 changed files with 466 additions and 100 deletions

View File

@ -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"

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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<Double> values = new LinkedList<Double>();
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();
}
}
}

View File

@ -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();

View File

@ -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(){

View File

@ -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;

View File

@ -31,7 +31,6 @@ public class ChunkGenerationTestLoading {
//
Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = true;
Globals.RUN_PHYSICS = false;
Globals.aiManager.setActive(false);

View File

@ -51,7 +51,6 @@ public class LevelEditorLoading {
//
Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = true;
Globals.RUN_PHYSICS = false;
Globals.aiManager.setActive(false);

View File

@ -37,6 +37,11 @@ public class LoadingUtils {
*/
static final int STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
/**
* The name of the editor race
*/
public static final String EDITOR_RACE_NAME = "editor";
static void initServerThread(){
@ -139,7 +144,7 @@ public class LoadingUtils {
//Create entity
//
//send default template back
String race = "editor";
String race = EDITOR_RACE_NAME;
if(!isEditor){
List<String> races = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces();
race = races.get(new Random().nextInt(races.size()));

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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<DGeom,HitboxState> geomStateMap = new HashMap<DGeom,HitboxState>();
/**
* The list of all hitbox states
*/
List<HitboxState> allStates = new LinkedList<HitboxState>();
/**
* The list of non-bone hitboxes
*/
List<HitboxState> nonBoneHitboxes = new LinkedList<HitboxState>();
//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<HitboxState> 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);
}
/**

View File

@ -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

View File

@ -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!");
}
}
}

View File

@ -33,6 +33,7 @@ public class CharacterProtocol implements ClientProtocolTemplate<CharacterMessag
case RESPONSECHARACTERLIST:
case RESPONSECREATECHARACTERFAILURE:
case RESPONSESPAWNCHARACTER:
case EDITORSWAP:
//silently ignore
break;
}

View File

@ -18,6 +18,7 @@ public class CharacterMessage extends NetworkMessage {
RESPONSECREATECHARACTERFAILURE,
REQUESTSPAWNCHARACTER,
RESPONSESPAWNCHARACTER,
EDITORSWAP,
}
/**
@ -99,6 +100,12 @@ public class CharacterMessage extends NetworkMessage {
}
case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER:
return CharacterMessage.canParseResponseSpawnCharacterMessage(byteBuffer);
case TypeBytes.CHARACTER_MESSAGE_TYPE_EDITORSWAP:
if(byteBuffer.getRemaining() >= 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;
}

View File

@ -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:

View File

@ -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

View File

@ -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;
}

View File

@ -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)));
}
}
/**

View File

@ -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<CharacterMessag
}
} break;
case REQUESTSPAWNCHARACTER: {
spawnEntityForClient(connectionHandler);
CharacterProtocol.spawnEntityForClient(connectionHandler);
} break;
case EDITORSWAP: {
CharacterProtocol.swapPlayerCharacter(connectionHandler);
} break;
case RESPONSECHARACTERLIST:
case RESPONSECREATECHARACTERSUCCESS:
@ -52,9 +66,10 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
/**
* Spawns the player's entity
* @param connectionHandler The connection handler for the player
* @return THe player's entity
*/
static void spawnEntityForClient(ServerConnectionHandler connectionHandler){
PlayerCharacterCreation.spawnPlayerCharacter(connectionHandler);
static Entity spawnEntityForClient(ServerConnectionHandler connectionHandler){
Entity rVal = PlayerCharacterCreation.spawnPlayerCharacter(connectionHandler);
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
Vector3d spawnPoint = realm.getSpawnPoint();
//set client initial discrete position
@ -65,6 +80,76 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
)
);
return rVal;
}
/**
* Swaps the type of the player character (to editor or vice-versa)
* @param connectionHandler The connection handler to swap
* @return The new player entity
*/
static Entity swapPlayerCharacter(ServerConnectionHandler connectionHandler){
//change the connection handler's creature template
if(connectionHandler.getCurrentCreatureTemplate().getCreatureType().matches(LoadingUtils.EDITOR_RACE_NAME)){
//solve what race to pick
String race = LoadingUtils.EDITOR_RACE_NAME;
List<String> 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;
}
}

View File

@ -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;

View File

@ -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;
}
/**

View File

@ -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<BiomeFoliageDescription> 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<BiomeFoliageDescription> 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()
);
}
}
}
}
}
}
}