life state synchronization
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-07-27 01:34:17 -04:00
parent 161f40ee04
commit c5f16ae282
16 changed files with 538 additions and 247 deletions

View File

@ -8,6 +8,7 @@
review combat code (lifestate, damage calculation, etc)
audio fx for everything
fix rendering pipelines (black when looking at character from angle with item, shadows are not darker color, etc)
option to load all data cells in scene on initializing a scene (thereby loading spawn points into memory)
+ bug fixes
fix client-attached models to viewmodel drawing on previous frame

View File

@ -459,6 +459,8 @@ First animations flickering in first person (enforce animation priority requirem
Debug third person animations flickering (attachments not reflecting animations that were played that frame)
Small data fix
Refactor spawn point to not be global
Synchronize objects between client and server
Synchronize life state between client and server
# TODO
@ -466,6 +468,10 @@ Refactor spawn point to not be global
BIG BIG BIG BIG IMMEDIATE TO DO:
always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible
Ability to fully reload game engine state without exiting client
- Back out to main menu and load a new level without any values persisting
- Receive a teleport packet from server and flush all game state before requesting state from server again
Unit Testing
- Capture image from opengl to pixel-check
- Ability to click through the ui via scripts

View File

@ -284,6 +284,12 @@ public class EntityDataStrings {
public static final String VIEW_PITCH = "aiViewPitch";
public static final String AI = "ai";
/**
* Life State
*/
public static final String TREE_CLIENTLIFETREE = "treeClientLifeTree";
public static final String TREE_SERVERLIFETREE = "treeServerLifeTree";
/**
* Pose actor
*/

View File

@ -294,6 +294,58 @@ public class StateTransitionUtil {
);
}
/**
* Constructor
* @param stateEnum The enum value for this state
* @param animPriority The priority of this state's animations
* @param firstPersonAnimation The animation to play in first person. If this is null, it will not play any animation in first person
* @param thirdPersonAnimation The animation to play in third person. If this is null, it will not play any animation in third person
* @param audioPath The path to an audio file to play on starting the animation. If null, no audio will be played
*/
public static StateTransitionUtilItem create(
Object stateEnum,
int animPriority,
String firstPersonAnimation,
String thirdPersonAnimation,
String audioPath
){
return create(
stateEnum,
animPriority,
firstPersonAnimation,
null,
thirdPersonAnimation,
null,
audioPath,
null
);
}
/**
* Constructor
* @param stateEnum The enum value for this state
* @param animPriority The priority of this state's animations
* @param thirdPersonAnimation The animation to play in third person. If this is null, it will not play any animation in third person
* @param onComplete !!Must transition to the next state!! Fires when the animation completes. If not supplied, animations and autio will loop
*/
public static StateTransitionUtilItem create(
Object stateEnum,
int animPriority,
String thirdPersonAnimation,
Runnable onComplete
){
return create(
stateEnum,
animPriority,
null,
null,
thirdPersonAnimation,
null,
null,
onComplete
);
}
/**
* Constructor
* @param stateEnum The enum value for this state

View File

@ -1,6 +1,8 @@
package electrosphere.entity.state.equip;
import electrosphere.net.synchronization.FieldIdEnums;
import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;

View File

@ -0,0 +1,184 @@
package electrosphere.entity.state.life;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.btree.StateTransitionUtil;
import electrosphere.entity.btree.StateTransitionUtil.StateTransitionUtilItem;
import electrosphere.entity.state.AnimationPriorities;
import electrosphere.game.data.creature.type.HealthSystem;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.Entity;
import electrosphere.engine.Globals;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
@SynchronizedBehaviorTree(name = "clientLifeTree", isServer = false, correspondingTree="serverLifeTree")
/**
* Client life state tree
*/
public class ClientLifeTree implements BehaviorTree {
@SynchronizableEnum
/**
* States available to the life tree
*/
public static enum LifeStateEnum {
ALIVE,
DYING,
DEAD,
}
//the current state of the tree
@SyncedField
LifeStateEnum state = LifeStateEnum.ALIVE;
//the parent entity of this life tree
Entity parent;
//data used to construct the tree
HealthSystem healthSystem;
//state transition util
//state transition util
StateTransitionUtil stateTransitionUtil;
@Override
public void simulate(float deltaTime) {
}
/**
* <p> Automatically generated </p>
* <p>
* Gets state.
* </p>
*/
public LifeStateEnum getState(){
return state;
}
/**
* <p> Automatically generated </p>
* <p>
* Sets state and handles the synchronization logic for it.
* </p>
* @param state The value to set state to.
*/
public void setState(LifeStateEnum state){
this.state = state;
}
/**
* <p> (initially) Automatically generated </p>
* <p> More parameters can be safely added to this method</p>
* <p>
* Attaches this tree to the entity.
* </p>
* @param entity The entity to attach to
* @param tree The behavior tree to attach
*/
public static ClientLifeTree attachTree(Entity parent, HealthSystem healthSystem){
ClientLifeTree rVal = new ClientLifeTree(parent,healthSystem);
//put manual code here (setting params, etc)
//!!WARNING!! from here below should not be touched
//This was generated automatically to properly alert various systems that the btree exists and should be tracked
parent.putData(EntityDataStrings.TREE_CLIENTLIFETREE, rVal);
Globals.clientSceneWrapper.getScene().registerBehaviorTree(rVal);
Globals.entityValueTrackingService.attachTreeToEntity(parent, BehaviorTreeIdEnums.BTREE_CLIENTLIFETREE_ID);
return rVal;
}
/**
* <p> Automatically generated </p>
* <p>
* Detatches this tree from the entity.
* </p>
* @param entity The entity to detach to
* @param tree The behavior tree to detach
*/
public static void detachTree(Entity entity, BehaviorTree tree){
Globals.entityValueTrackingService.detatchTreeFromEntity(entity, BehaviorTreeIdEnums.BTREE_CLIENTLIFETREE_ID);
}
/**
* <p> (initially) Automatically generated </p>
* <p> Private constructor to enforce using the attach methods </p>
* <p>
* Constructor
* </p>
* @param parent The parent entity of this tree
*/
public ClientLifeTree(Entity parent, HealthSystem healthSystem){
this.parent = parent;
this.healthSystem = healthSystem;
stateTransitionUtil = StateTransitionUtil.create(parent, false, new StateTransitionUtilItem[]{
StateTransitionUtilItem.create(
LifeStateEnum.DYING,
AnimationPriorities.DEATH,
healthSystem.getDyingFirstPersonAnimation(),
healthSystem.getDyingThirdPersonAnimation(),
healthSystem.getAudioPath()
)
});
}
/**
* <p>
* Gets the ClientLifeTree of the entity
* </p>
* @param entity the entity
* @return The ClientLifeTree
*/
public static ClientLifeTree getClientLifeTree(Entity entity){
return (ClientLifeTree)entity.getData(EntityDataStrings.TREE_CLIENTLIFETREE);
}
/**
* <p> Automatically generated </p>
* <p>
* Converts this enum type to an equivalent short value
* </p>
* @param enumVal The enum value
* @return The short value
*/
public static short getLifeStateEnumEnumAsShort(LifeStateEnum enumVal){
switch(enumVal){
case ALIVE:
return 0;
case DYING:
return 1;
case DEAD:
return 2;
default:
return 0;
}
}
/**
* <p> Automatically generated </p>
* <p>
* Converts a short to the equivalent enum value
* </p>
* @param shortVal The short value
* @return The enum value
*/
public static LifeStateEnum getLifeStateEnumShortAsEnum(short shortVal){
switch(shortVal){
case 0:
return LifeStateEnum.ALIVE;
case 1:
return LifeStateEnum.DYING;
case 2:
return LifeStateEnum.DEAD;
default:
return LifeStateEnum.ALIVE;
}
}
}

View File

@ -1,202 +0,0 @@
package electrosphere.entity.state.life;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.AnimationPriorities;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.creature.type.CreatureType;
import electrosphere.game.data.creature.type.HealthSystem;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.actor.Actor;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
/**
* The status of the life value of a given entity
*/
public class LifeState implements BehaviorTree {
public static enum LifeStateEnum {
ALIVE,
DYING,
DEAD,
}
LifeStateEnum state = LifeStateEnum.ALIVE;
Entity parent;
boolean isInvincible;
int lifeCurrent;
int lifeMax;
int iFrameMaxCount;
int iFrameCurrent;
int deathFrameCurrent = -1;
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>();
public LifeState(Entity parent, HealthSystem system){
this.parent = parent;
isInvincible = false;
lifeMax = system.getMaxHealth();
lifeCurrent = lifeMax;
iFrameMaxCount = system.getOnDamageIFrames();
iFrameCurrent = 0;
}
public LifeState(Entity parent, boolean isInvincible, int lifeCurrent, int lifeMax, int iFrameMaxCount) {
this.parent = parent;
this.isInvincible = isInvincible;
this.lifeCurrent = lifeCurrent;
this.lifeMax = lifeMax;
this.iFrameMaxCount = iFrameMaxCount;
}
public boolean isIsAlive() {
return state == LifeStateEnum.ALIVE;
}
public boolean isIsInvincible() {
return isInvincible;
}
public int getLifeCurrent() {
return lifeCurrent;
}
public int getLifeMax() {
return lifeMax;
}
public void setState(LifeStateEnum state) {
this.state = state;
}
public void setIsInvincible(boolean isInvincible) {
this.isInvincible = isInvincible;
}
public void setLifeCurrent(int lifeCurrent) {
this.lifeCurrent = lifeCurrent;
}
public void setLifeMax(int lifeMax) {
this.lifeMax = lifeMax;
}
public int getiFrameMaxCount() {
return iFrameMaxCount;
}
public int getiFrameCurrent() {
return iFrameCurrent;
}
public void setiFrameMaxCount(int iFrameMaxCount) {
this.iFrameMaxCount = iFrameMaxCount;
}
public void setiFrameCurrent(int iFrameCurrent) {
this.iFrameCurrent = iFrameCurrent;
}
public void damage(int damage){
if(!isInvincible){
lifeCurrent = lifeCurrent - damage;
isInvincible = true;
if(lifeCurrent < 0){
lifeCurrent = 0;
if(Globals.RUN_SERVER){
state = LifeStateEnum.DYING;
Vector3d position = EntityUtils.getPosition(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructKillMessage(
Globals.timekeeper.getNumberOfSimFramesElapsed(),
parent.getId()
)
);
}
} else {
iFrameCurrent = iFrameMaxCount;
}
}
}
public void revive(){
state = LifeStateEnum.ALIVE;
isInvincible = false;
lifeCurrent = lifeMax;
}
public void simulate(float deltaTime){
for(EntityMessage message : networkMessageQueue){
networkMessageQueue.remove(message);
long updateTime = message.gettime();
switch(message.getMessageSubtype()){
case KILL:
//start death
if(Globals.RUN_CLIENT){
state = LifeStateEnum.DYING;
lifeCurrent = 0;
int frameskip = (int)(Globals.timekeeper.getNumberOfSimFramesElapsed() - message.gettime());
deathFrameCurrent = frameskip;
}
break;
default:
//silently ignore
break;
}
}
switch(state){
case ALIVE:
if(iFrameCurrent > 0){
iFrameCurrent--;
if(iFrameCurrent == 0){
isInvincible = false;
}
}
break;
case DYING:
CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(parent));
if(deathFrameCurrent > creatureType.getHealthSystem().getDeathFrames()){
state = LifeStateEnum.DEAD;
}
Actor entityActor = EntityUtils.getActor(parent);
if(entityActor != null){
String animationToPlay = creatureType.getHealthSystem().getDeathAnimation();
if(
!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay)
){
entityActor.playAnimation(animationToPlay,AnimationPriorities.DEATH);
entityActor.incrementAnimationTime(0.0001);
}
}
break;
case DEAD:
if(Globals.RUN_CLIENT && parent == Globals.playerEntity){
if(!Globals.RUN_SERVER){
//destroy current (client) world stuff
//only if not also running server
}
//submit respawn request
Globals.clientConnection.queueOutgoingMessage(
CharacterMessage.constructRequestSpawnCharacterMessage()
);
}
break;
}
}
public void addNetworkMessage(EntityMessage networkMessage) {
networkMessageQueue.add(networkMessage);
}
}

View File

@ -1,15 +0,0 @@
package electrosphere.entity.state.life;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
/**
* Utility functions for dealing with life state
*/
public class LifeUtils {
public static LifeState getLifeState(Entity e){
return (LifeState)e.getData(EntityDataStrings.LIFE_STATE);
}
}

View File

@ -0,0 +1,200 @@
package electrosphere.entity.state.life;
import electrosphere.net.synchronization.FieldIdEnums;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.btree.StateTransitionUtil;
import electrosphere.entity.btree.StateTransitionUtil.StateTransitionUtilItem;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.Entity;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.state.AnimationPriorities;
import electrosphere.entity.state.life.ClientLifeTree.LifeStateEnum;
import electrosphere.game.data.creature.type.HealthSystem;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
@SynchronizedBehaviorTree(name = "serverLifeTree", isServer = true, correspondingTree="clientLifeTree")
/**
* Server life state tree
*/
public class ServerLifeTree implements BehaviorTree {
//the current state of the tree
@SyncedField
LifeStateEnum state = LifeStateEnum.ALIVE;
//the parent entity of this life tree
Entity parent;
//data used to construct the tree
HealthSystem healthSystem;
//state transition util
StateTransitionUtil stateTransitionUtil;
//is the entity invincible
boolean isInvincible = false;
//the current life value
int lifeCurrent = 1;
//the maximum life value
int lifeMax = 1;
//the maximum iframes
int iFrameMaxCount = 1;
//the current iframe count
int iFrameCurrent = 0;
@Override
public void simulate(float deltaTime) {
switch(state){
case ALIVE: {
if(iFrameCurrent > 0){
iFrameCurrent--;
if(iFrameCurrent == 0){
isInvincible = false;
}
}
} break;
case DYING: {
this.stateTransitionUtil.simulate(LifeStateEnum.DYING);
} break;
case DEAD: {
} break;
}
}
/**
* Revives the entity
*/
public void revive(){
this.setState(LifeStateEnum.ALIVE);
isInvincible = false;
lifeCurrent = lifeMax;
}
/**
* Damages the entity
* @param damage The amount of damage to inflict
*/
public void damage(int damage){
if(!isInvincible){
lifeCurrent = lifeCurrent - damage;
isInvincible = true;
if(lifeCurrent < 0){
lifeCurrent = 0;
this.setState(LifeStateEnum.DYING);
} else {
iFrameCurrent = iFrameMaxCount;
}
}
}
/**
* Checks if the entity is alive
* @return true if alive, false otherwise
*/
public boolean isAlive(){
return this.state == LifeStateEnum.ALIVE;
}
/**
* <p> Automatically generated </p>
* <p>
* Gets state.
* </p>
*/
public LifeStateEnum getState(){
return state;
}
/**
* <p> Automatically generated </p>
* <p>
* Sets state and handles the synchronization logic for it.
* </p>
* @param state The value to set state to.
*/
public void setState(LifeStateEnum state){
this.state = state;
int value = ClientLifeTree.getLifeStateEnumEnumAsShort(state);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID, FieldIdEnums.TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID, value));
}
/**
* <p> (initially) Automatically generated </p>
* <p> More parameters can be safely added to this method</p>
* <p>
* Attaches this tree to the entity.
* </p>
* @param entity The entity to attach to
* @param tree The behavior tree to attach
*/
public static ServerLifeTree attachTree(Entity parent, HealthSystem healthSystem){
ServerLifeTree rVal = new ServerLifeTree(parent, healthSystem);
//put manual code here (setting params, etc)
//!!WARNING!! from here below should not be touched
//This was generated automatically to properly alert various systems that the btree exists and should be tracked
ServerBehaviorTreeUtils.attachBTreeToEntity(parent, rVal);
parent.putData(EntityDataStrings.TREE_SERVERLIFETREE, rVal);
Globals.entityValueTrackingService.attachTreeToEntity(parent, BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID);
return rVal;
}
/**
* <p> Automatically generated </p>
* <p>
* Detatches this tree from the entity.
* </p>
* @param entity The entity to detach to
* @param tree The behavior tree to detach
*/
public static void detachTree(Entity entity, BehaviorTree tree){
Globals.entityValueTrackingService.detatchTreeFromEntity(entity, BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID);
}
/**
* <p> (initially) Automatically generated </p>
* <p> Private constructor to enforce using the attach methods </p>
* <p>
* Constructor
* </p>
* @param parent The parent entity of this tree
*/
public ServerLifeTree(Entity parent, HealthSystem healthSystem){
this.parent = parent;
this.lifeMax = healthSystem.getMaxHealth();
this.lifeCurrent = this.lifeMax;
this.iFrameMaxCount = healthSystem.getOnDamageIFrames();
this.iFrameCurrent = 0;
this.healthSystem = healthSystem;
stateTransitionUtil = StateTransitionUtil.create(parent, true, new StateTransitionUtilItem[]{
StateTransitionUtilItem.create(
LifeStateEnum.DYING,
AnimationPriorities.DEATH,
this.healthSystem.getDyingThirdPersonAnimation(),
() -> {
this.setState(LifeStateEnum.DEAD);
}
)
});
}
/**
* <p>
* Gets the ServerLifeTree of the entity
* </p>
* @param entity the entity
* @return The ServerLifeTree
*/
public static ServerLifeTree getServerLifeTree(Entity entity){
return (ServerLifeTree)entity.getData(EntityDataStrings.TREE_SERVERLIFETREE);
}
}

View File

@ -1,6 +1,7 @@
package electrosphere.entity.state.movement.groundmove;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.net.synchronization.FieldIdEnums;
import electrosphere.net.parser.net.message.SynchronizationMessage;

View File

@ -30,7 +30,8 @@ import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.ServerInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.state.life.LifeState;
import electrosphere.entity.state.life.ClientLifeTree;
import electrosphere.entity.state.life.ServerLifeTree;
import electrosphere.entity.state.movement.AirplaneMovementTree;
import electrosphere.entity.state.movement.FallTree;
import electrosphere.entity.state.movement.JumpTree;
@ -359,8 +360,10 @@ public class CreatureUtils {
Globals.clientScene.registerBehaviorTree(rotatorTree);
}
//add health system
rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem()));
Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIFE_STATE);
if(rawType.getHealthSystem() != null){
ClientLifeTree.attachTree(rVal,rawType.getHealthSystem());
Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIFE_STATE);
}
//idle tree & generic stuff all creatures have
ClientIdleTree idleTree = new ClientIdleTree(rVal);
rVal.putData(EntityDataStrings.TREE_IDLE, idleTree);
@ -661,8 +664,10 @@ public class CreatureUtils {
}
//add health system
rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem()));
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.LIFE_STATE);
if(rawType.getHealthSystem() != null){
ServerLifeTree.attachTree(rVal, rawType.getHealthSystem());
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.LIFE_STATE);
}
//idle tree & generic stuff all creatures have
ServerIdleTree.attachTree(rVal);
CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());

View File

@ -4,32 +4,71 @@ package electrosphere.game.data.creature.type;
* Data about the health of a creature
*/
public class HealthSystem {
int maxHealth;
int onDamageIFrames;
int deathFrames;
String deathAnimation;
//the maximum health
int maxHealth;
//the number of iframes on taking damage
int onDamageIFrames;
//the third person animation to play when the entity is dying
String dyingThirdPersonAnimation;
//the first person animation to play when the entity is dying
String dyingFirstPersonAnimation;
//The audio file to play when the entity dies
String audioPath;
/**
* Gets the maximum health
* @return The maximum health
*/
public int getMaxHealth() {
return maxHealth;
}
/**
* Gets the number of iframes on damage
* @return The number of iframes
*/
public int getOnDamageIFrames() {
return onDamageIFrames;
}
public int getDeathFrames(){
return deathFrames;
/**
* Gets the animation to play in third person when the entity is dying
* @return The animation
*/
public String getDyingThirdPersonAnimation(){
return dyingThirdPersonAnimation;
}
public String getDeathAnimation(){
return deathAnimation;
/**
* Gets the animation to play in first person when the entity is dying
* @return The animation
*/
public String getDyingFirstPersonAnimation(){
return dyingFirstPersonAnimation;
}
/**
* Gets the audio path to play when the entity is dying
* @return The audio path
*/
public String getAudioPath(){
return audioPath;
}
/**
* Clones health system data
*/
public HealthSystem clone(){
HealthSystem rVal = new HealthSystem();
rVal.maxHealth = maxHealth;
rVal.onDamageIFrames = onDamageIFrames;
rVal.deathFrames = deathFrames;
rVal.dyingThirdPersonAnimation = dyingThirdPersonAnimation;
rVal.dyingFirstPersonAnimation = dyingFirstPersonAnimation;
return rVal;
}

View File

@ -15,6 +15,8 @@ public class BehaviorTreeIdEnums {
public static final int BTREE_SERVERGRAVITY_ID = 7;
public static final int BTREE_IDLE_ID = 8;
public static final int BTREE_SERVERIDLE_ID = 9;
public static final int BTREE_CLIENTLIFETREE_ID = 6;
public static final int BTREE_SERVERLIFETREE_ID = 13;
public static final int BTREE_CLIENTGROUNDMOVEMENTTREE_ID = 10;
public static final int BTREE_SERVERGROUNDMOVEMENTTREE_ID = 11;

View File

@ -1,6 +1,7 @@
package electrosphere.net.synchronization;
import electrosphere.entity.state.life.ClientLifeTree;
import electrosphere.net.synchronization.FieldIdEnums;
import electrosphere.entity.state.block.ClientBlockTree;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
@ -165,6 +166,14 @@ public class ClientSynchronizationManager {
} break;
}
} break;
case BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID: {
switch(message.getfieldId()){
case FieldIdEnums.TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID:{
ClientLifeTree tree = ClientLifeTree.getClientLifeTree(entity);
tree.setState(ClientLifeTree.getLifeStateEnumShortAsEnum((short)message.getbTreeValue()));
} break;
}
} break;
case BehaviorTreeIdEnums.BTREE_SERVERGROUNDMOVEMENTTREE_ID: {
switch(message.getfieldId()){
case FieldIdEnums.TREE_SERVERGROUNDMOVEMENTTREE_SYNCEDFIELD_FACING_ID:{

View File

@ -19,6 +19,8 @@ public class FieldIdEnums {
public static final int TREE_SERVERGRAVITY_SYNCEDFIELD_STATE_ID = 11;
public static final int TREE_IDLE_SYNCEDFIELD_STATE_ID = 12;
public static final int TREE_SERVERIDLE_SYNCEDFIELD_STATE_ID = 13;
public static final int TREE_CLIENTLIFETREE_SYNCEDFIELD_STATE_ID = 10;
public static final int TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID = 17;
public static final int TREE_CLIENTGROUNDMOVEMENTTREE_SYNCEDFIELD_FACING_ID = 14;
public static final int TREE_SERVERGROUNDMOVEMENTTREE_SYNCEDFIELD_FACING_ID = 15;

View File

@ -6,18 +6,15 @@ import org.ode4j.ode.DGeom;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxType;
import electrosphere.entity.state.life.LifeUtils;
import electrosphere.entity.state.life.ServerLifeTree;
import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.datacell.Realm;
/**
* Callback for managing collisions on the server
@ -62,12 +59,13 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
if(isItem){
if(hitboxAttachParent != receiverParent){
int damage = ItemUtils.getWeaponDataRaw(impactorParent).getDamage();
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
System.out.println("ServerHitboxResolutionCallback - Unimplemented!!");
Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
LifeUtils.getLifeState(receiverParent).revive();
ServerLifeTree serverLifeTree = ServerLifeTree.getServerLifeTree(receiverParent);
serverLifeTree.damage(damage);
if(!serverLifeTree.isAlive()){
throw new UnsupportedOperationException("Reviving not implemented yet!");
// Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
// EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
// serverLifeTree.revive();
}
}
} else {
@ -81,12 +79,13 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
damage = (int)ProjectileTree.getProjectileTree(impactorParent).getDamage();
}
}
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
System.out.println("ServerHitboxResolutionCallback - Unimplemented!!");
Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
LifeUtils.getLifeState(receiverParent).revive();
ServerLifeTree serverLifeTree = ServerLifeTree.getServerLifeTree(receiverParent);
serverLifeTree.damage(damage);
if(!serverLifeTree.isAlive()){
throw new UnsupportedOperationException("Reviving not implemented yet!");
// Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
// EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
// serverLifeTree.revive();
}
}
}