life state synchronization
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				studiorailgun/Renderer/pipeline/head There was a failure building this commit
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	studiorailgun/Renderer/pipeline/head There was a failure building this commit
				
			This commit is contained in:
		
							parent
							
								
									161f40ee04
								
							
						
					
					
						commit
						c5f16ae282
					
				| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|      */ | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
|      | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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; | ||||
|  | ||||
| @ -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())); | ||||
|         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())); | ||||
|         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()); | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
|      | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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:{ | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user