From 6a3bedf80884ab90ae92ba544604aaa29027ad40 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 27 Apr 2022 21:01:35 -0400 Subject: [PATCH] Respawn system --- net/entity.json | 1 + .../entity/state/life/LifeState.java | 120 +++++++++++++++--- .../game/data/creature/type/HealthSystem.java | 11 ++ .../net/parser/net/message/EntityMessage.java | 12 +- .../net/parser/net/message/TypeBytes.java | 2 +- 5 files changed, 123 insertions(+), 23 deletions(-) diff --git a/net/entity.json b/net/entity.json index 19b512d2..0b43b8a3 100644 --- a/net/entity.json +++ b/net/entity.json @@ -157,6 +157,7 @@ { "messageName" : "Kill", "data" : [ + "time", "entityID" ] }, diff --git a/src/main/java/electrosphere/entity/state/life/LifeState.java b/src/main/java/electrosphere/entity/state/life/LifeState.java index 53de7473..cc3a11b2 100644 --- a/src/main/java/electrosphere/entity/state/life/LifeState.java +++ b/src/main/java/electrosphere/entity/state/life/LifeState.java @@ -1,27 +1,46 @@ package electrosphere.entity.state.life; +import java.util.concurrent.CopyOnWriteArrayList; + import org.joml.Vector3d; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.data.creature.type.CreatureType; import electrosphere.game.data.creature.type.HealthSystem; import electrosphere.main.Globals; +import electrosphere.main.Main; +import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.renderer.actor.Actor; -public class LifeState { +public class LifeState implements BehaviorTree { + + + public static enum LifeStateEnum { + ALIVE, + DYING, + DEAD, + } + + LifeStateEnum state = LifeStateEnum.ALIVE; Entity parent; - boolean isAlive; boolean isInvincible; int lifeCurrent; int lifeMax; int iFrameMaxCount; int iFrameCurrent; + int deathFrameCurrent = -1; + + CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + public LifeState(Entity parent, HealthSystem system){ this.parent = parent; - isAlive = true; isInvincible = false; lifeMax = system.getMaxHealth(); lifeCurrent = lifeMax; @@ -29,9 +48,8 @@ public class LifeState { iFrameCurrent = 0; } - public LifeState(Entity parent, boolean isAlive, boolean isInvincible, int lifeCurrent, int lifeMax, int iFrameMaxCount) { + public LifeState(Entity parent, boolean isInvincible, int lifeCurrent, int lifeMax, int iFrameMaxCount) { this.parent = parent; - this.isAlive = isAlive; this.isInvincible = isInvincible; this.lifeCurrent = lifeCurrent; this.lifeMax = lifeMax; @@ -39,7 +57,7 @@ public class LifeState { } public boolean isIsAlive() { - return isAlive; + return state == LifeStateEnum.ALIVE; } public boolean isIsInvincible() { @@ -54,8 +72,8 @@ public class LifeState { return lifeMax; } - public void setIsAlive(boolean isAlive) { - this.isAlive = isAlive; + public void setState(LifeStateEnum state) { + this.state = state; } public void setIsInvincible(boolean isInvincible) { @@ -92,15 +110,16 @@ public class LifeState { isInvincible = true; if(lifeCurrent < 0){ lifeCurrent = 0; - isAlive = false; if(Globals.RUN_SERVER){ + state = LifeStateEnum.DYING; Vector3d position = EntityUtils.getPosition(parent); Globals.dataCellManager.sendNetworkMessageToChunk( - EntityMessage.constructKillMessage( - parent.getId() - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) + EntityMessage.constructKillMessage( + Main.getCurrentFrame(), + parent.getId() + ), + Globals.serverWorldData.convertRealToChunkSpace(position.x), + Globals.serverWorldData.convertRealToChunkSpace(position.z) ); } } else { @@ -110,18 +129,81 @@ public class LifeState { } public void revive(){ - isAlive = true; + state = LifeStateEnum.ALIVE; isInvincible = false; lifeCurrent = lifeMax; } public void simulate(){ - if(iFrameCurrent > 0){ - iFrameCurrent--; - if(iFrameCurrent == 0){ - isInvincible = false; + 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)(Main.getCurrentFrame() - message.gettime()); + deathFrameCurrent = frameskip; + } + break; + case ATTACHENTITYTOENTITY: + case ATTACKUPDATE: + case CREATE: + case DESTROY: + case SETBEHAVIORTREE: + case SETPOSITION: + case SETPROPERTY: + case MOVE: + case SETFACING: + case MOVEUPDATE: + //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,1); + entityActor.incrementAnimationTime(0.01); + } + } + 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); } } diff --git a/src/main/java/electrosphere/game/data/creature/type/HealthSystem.java b/src/main/java/electrosphere/game/data/creature/type/HealthSystem.java index 53302b65..3838f5ed 100644 --- a/src/main/java/electrosphere/game/data/creature/type/HealthSystem.java +++ b/src/main/java/electrosphere/game/data/creature/type/HealthSystem.java @@ -7,6 +7,8 @@ package electrosphere.game.data.creature.type; public class HealthSystem { int maxHealth; int onDamageIFrames; + int deathFrames; + String deathAnimation; public int getMaxHealth() { return maxHealth; @@ -15,11 +17,20 @@ public class HealthSystem { public int getOnDamageIFrames() { return onDamageIFrames; } + + public int getDeathFrames(){ + return deathFrames; + } + + public String getDeathAnimation(){ + return deathAnimation; + } public HealthSystem clone(){ HealthSystem rVal = new HealthSystem(); rVal.maxHealth = maxHealth; rVal.onDamageIFrames = onDamageIFrames; + rVal.deathFrames = deathFrames; return rVal; } diff --git a/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java b/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java index eff01c89..28791712 100644 --- a/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/EntityMessage.java @@ -462,12 +462,14 @@ public class EntityMessage extends NetworkMessage { public static EntityMessage parseKillMessage(List byteStream){ EntityMessage rVal = new EntityMessage(EntityMessageType.KILL); stripPacketHeader(byteStream); + rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteStream)); rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteStream)); return rVal; } - public static EntityMessage constructKillMessage(int entityID){ + public static EntityMessage constructKillMessage(long time,int entityID){ EntityMessage rVal = new EntityMessage(EntityMessageType.KILL); + rVal.settime(time); rVal.setentityID(entityID); rVal.serialize(); return rVal; @@ -786,14 +788,18 @@ public class EntityMessage extends NetworkMessage { } break; case KILL: - rawBytes = new byte[2+4]; + rawBytes = new byte[2+8+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY; //entity messaage header rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_KILL; + intValues = ByteStreamUtils.serializeLongToBytes(time); + for(int i = 0; i < 8; i++){ + rawBytes[2+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeIntToBytes(entityID); for(int i = 0; i < 4; i++){ - rawBytes[2+i] = intValues[i]; + rawBytes[10+i] = intValues[i]; } break; case DESTROY: 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 6909b985..32800983 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -34,7 +34,7 @@ Message categories public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE = 74; public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE_SIZE = 74; public static final byte ENTITY_MESSAGE_TYPE_MOVE_SIZE = 38; - public static final byte ENTITY_MESSAGE_TYPE_KILL_SIZE = 6; + public static final byte ENTITY_MESSAGE_TYPE_KILL_SIZE = 14; public static final byte ENTITY_MESSAGE_TYPE_DESTROY_SIZE = 6; public static final byte ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE_SIZE = 22; public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE = 22;