Compare commits

...

4 Commits

Author SHA1 Message Date
austin
e671cda62d hitboxes, ui, bug fixes, network fixes, etc
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
2024-06-14 13:58:10 -04:00
austin
4ae09e7afb network fixes, documentation, etc 2024-06-07 19:42:48 -04:00
austin
a30ac75573 work on moving hitboxes to ode4j handling 2024-06-07 17:50:49 -04:00
austin
b1d79dbc16 hitboxes - refactoring work, documentation 2024-05-26 13:28:11 -04:00
133 changed files with 4354 additions and 2668 deletions

View File

@ -18,7 +18,8 @@
"renderResolutionX": 1920, "renderResolutionX": 1920,
"renderResolutionY": 1080, "renderResolutionY": 1080,
"graphicsDebugDrawCollisionSpheres" : false, "graphicsDebugDrawCollisionSpheresClient" : false,
"graphicsDebugDrawCollisionSpheresServer" : false,
"graphicsDebugDrawPhysicsObjects" : false, "graphicsDebugDrawPhysicsObjects" : false,
"graphicsDebugDrawMovementVectors" : false, "graphicsDebugDrawMovementVectors" : false,
"graphicsDebugDrawNavmesh" : false, "graphicsDebugDrawNavmesh" : false,

View File

@ -5,32 +5,37 @@
"hitboxes" : [ "hitboxes" : [
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.031", "bone": "Bicep.L",
"radius": 0.04 "radius": 0.04
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.012", "bone": "Bicep.R",
"radius": 0.04 "radius": 0.04
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.003", "bone": "Leg.L",
"radius": 0.04 "radius": 0.04
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.010", "bone": "Leg.R",
"radius": 0.04
},
{
"type": "hurt",
"bone": "Shoulder.L",
"radius": 0.06 "radius": 0.06
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.001", "bone": "Shoulder.R",
"radius": 0.06 "radius": 0.06
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.014", "bone": "Neck",
"radius": 0.06 "radius": 0.06
}, },
{ {
@ -40,13 +45,8 @@
}, },
{ {
"type": "hurt", "type": "hurt",
"bone": "Bone.014", "bone": "Head",
"radius": 0.06 "radius": 0.06
},
{
"type": "hurt",
"bone": "Bone.019",
"radius": 0.04
} }
], ],
"tokens" : [ "tokens" : [
@ -241,10 +241,10 @@
"equipPoints" : [ "equipPoints" : [
{ {
"equipPointId" : "handLeft", "equipPointId" : "handLeft",
"bone" : "MiddleLower.L", "bone" : "Hand.L",
"firstPersonBone" : "hand.L", "firstPersonBone" : "hand.L",
"offsetVector" : [], "offsetVector" : [0,0,0],
"offsetRotation" : [], "offsetRotation" : [0,0,0,1],
"equipClassWhitelist" : [ "equipClassWhitelist" : [
"tool", "tool",
"shield", "shield",
@ -253,10 +253,10 @@
}, },
{ {
"equipPointId" : "handRight", "equipPointId" : "handRight",
"bone" : "MiddleLower.R", "bone" : "Hand.R",
"firstPersonBone" : "hand.R", "firstPersonBone" : "hand.R",
"offsetVector" : [], "offsetVector" : [0,0,0],
"offsetRotation" : [0.3057,0.2926,0.09933,0.9006], "offsetRotation" : [-0.334,0.145,-0.28,0.89],
"equipClassWhitelist" : [ "equipClassWhitelist" : [
"tool", "tool",
"weapon", "weapon",

View File

@ -11,17 +11,17 @@
"damage" : 10, "damage" : 10,
"hitboxes" : [ "hitboxes" : [
{ {
"type": "hit", "type": "hit_connected",
"bone": "Blade1", "bone": "Blade1",
"radius": 0.04 "radius": 0.04
}, },
{ {
"type": "hit", "type": "hit_connected",
"bone": "Blade2", "bone": "Blade2",
"radius": 0.04 "radius": 0.04
}, },
{ {
"type": "hit", "type": "hit_connected",
"bone": "Blade3", "bone": "Blade3",
"radius": 0.04 "radius": 0.04
} }

View File

@ -26,6 +26,7 @@
], ],
"files" : [ "files" : [
"Data/objects/floatingisland.json", "Data/objects/floatingisland.json",
"Data/objects/testscene1objects.json" "Data/objects/testscene1objects.json",
"Data/objects/debug_objects.json"
] ]
} }

View File

@ -0,0 +1,18 @@
{
"objects" : [
{
"objectId" : "hitboxTester",
"hitboxData" : [
{
"type": "static_capsule",
"radius": 2,
"length": 5
}
],
"tokens": []
}
],
"files" : []
}

View File

@ -0,0 +1,10 @@
{
"hints": [
{
"id": "Basic Navigation",
"titleString": "Navigation",
"descriptionString": "You can move the mouse to move the camera around. Also, you can use the W, A, S, and D keys to move your character.",
"image": ""
}
]
}

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file #maven.buildNumber.plugin properties file
#Sun May 19 19:34:37 EDT 2024 #Fri Jun 14 13:45:11 EDT 2024
buildNumber=132 buildNumber=137

View File

@ -9,6 +9,7 @@
- @subpage timekeeper - @subpage timekeeper
- @subpage archimprovementtargets - @subpage archimprovementtargets
- @subpage savesindex - @subpage savesindex
- @subpage hitboxesindex
# What is this section # What is this section

View File

@ -0,0 +1,29 @@
@page hitboxesindex Hitboxes
# Architecture Highest Level
New architecture needs to be something like
Per realm/client scene, we have a collision engine that has a whole bunch of capsules.
We update those collision engines at the top of the frame.
On collision, run collision logic
# Design Notes
We want to have one collision per "object" per frame. IE, lets say you have a sword with two hitboxes on it that both collide with an enemy.
This would technically generate two collision events per frame. Need to condense this to one collision "event".
Going to have one body per object, ie one body per sword, but then multiple shapes per body.
Then drop the collision engine down to 1 collision per body per frame.

View File

@ -310,14 +310,107 @@ Attaching items to hands in first person
Fix grass placement Fix grass placement
(05/26/2024)
VERY rudimentary first person documentation to give basic navigation to relevant files.
Fix attacking looping and freezing the character in place
- Was using delta real time (0.02ms) instead of delta frames in server and client attack trees (1 frame/simulate() call)
Document hitboxes
- Documented how it works currently and the architecture we want to move towards
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Need to have an object attached to creature that stores the rigid body
- When creating the creature, for each hitbox, create shapes for the rigid body
- Attach the overall object to the creature entity
(05/27/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Synchronize hitbox positions each frame
(05/31/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Write custom callback for the collision engine for just hitboxes
(06/04/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Need to have an object attached to creature that stores the rigid body
- When creating the creature, for each hitbox, create shapes for the rigid body
- Attach the overall object to the creature entity
(06/07/2024)
Hitboxes work to properly use capsules (constantly destroy/recreate every frane because od4j doesn't allow rescaling :<)
(06/10/2024)
Add flow for demo menu/level loading
(06/11/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Properly calculate the capsule that bridges from previous frame to current frame hitbox location
- Write custom callback for the collision engine for just hitboxes
Fix player model side-jog animations
(06/13/2024)
Fix newly exported model not rendering correctly
- All bones are passed into the shader every render call, the bone values must be corrupted
- NIGHTMARE BUG
Fix equipping an item spawning two items
(06/14/2024)
Fix inventory ui not closing when you hit 'i' key (will need to update utility functions to manage input mode so you're not doing it in callback)
Develop debug ui for equip points
# TODO # TODO
Demo requirements:
= Assets =
Block animation in first person
Block animation in third person
Fix attack animation bone rotations for hand
Clean up equip state data
Audio FX for everything
= Coding =
Fix items falling below the ground
Control rebinding menu from title screen
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Introduce block hitbox (blockbox) type
Enemy AI
Probably some kind of tutorial text
Network-able ui messages
Ability to display video both on title screen as well as in game windows for tutorials
better scaffolding for scripting engine with hooks for equipping items, spawning entities, pausing/resuming play, etc
Ability for private realms to have time start/stop based on the player's feedback <-- sync this up to tutorial ui via script
BIG BIG BIG BIG IMMEDIATE TO DO:
always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Introduce block hitbox (blockbox) type
Fix voxel type selection menu not showing textures
- The quads are off screen because the calculation for ndcX/ndcY are putting it wayyy to the right -- will need to revisit calcs for all that
Fix being able to walk off far side of the world (ie in level editor) Fix being able to walk off far side of the world (ie in level editor)
Grass System properly LOD Grass System properly LOD
- Have foliage dynamically time out cells to be reconsidered based on distance from player (if close, short cooldown, if far long cooldown) - Have foliage dynamically time out cells to be reconsidered based on distance from player (if close, short cooldown, if far long cooldown)
Would be nice to be able to cut clients that stream their logs to my server
Data Cleanup Data Cleanup
- Clean up creatures - Clean up creatures
- Remove unused ones - Remove unused ones
@ -343,6 +436,8 @@ More Debug menus
- Screen that shows the overall status of fluid cell manager - Screen that shows the overall status of fluid cell manager
- Screen that shows the overall status of realm 0 - Screen that shows the overall status of realm 0
- Screen that shows the overall status of realm manager - Screen that shows the overall status of realm manager
- Particularly, want a view of all entities in the scene, and the ability to click on a single entity to get an overview of everything on the entity
- For each behavior tree, ability to click into the tree and view fine details about its state (both pure state variable as well as other relevant variables)
Revisit first attempt at instancing (its really laggy lol) Revisit first attempt at instancing (its really laggy lol)
- Maybe have draw call happen on top level entity and immediately queue all children recursively - Maybe have draw call happen on top level entity and immediately queue all children recursively

View File

@ -6,4 +6,5 @@
- @subpage staticmorph - @subpage staticmorph
- @subpage shadermask - @subpage shadermask
- @subpage animationmask - @subpage animationmask
- @subpage meshmask - @subpage meshmask
- @subpage firstpersonviewmodel

View File

@ -0,0 +1,10 @@
@page firstpersonviewmodel First Person Viewmodel
# The pipeline
There is a separate render pipeline for first person elements. It is composited ontop the main render in the composite pipeline.
# The actor
There is a global entity, firstPersonEntity, that is rendered in the first person pipeline. This is the source of the visuals in that render.
The animations for this actor are controlled via the `FirstPersonTree`. It provides a convenient function where you give it the entity and the name of an animation and it will play it.

View File

@ -13,34 +13,41 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "RequestCharacterList", "messageName" : "RequestCharacterList",
"description" : "Requests the list of characters from the server for the logged in user account",
"data" : [] "data" : []
}, },
{ {
"messageName" : "ResponseCharacterList", "messageName" : "ResponseCharacterList",
"description" : "Gives the client the list of characters available to it",
"data" : [ "data" : [
"data" "data"
] ]
}, },
{ {
"messageName" : "RequestCreateCharacter", "messageName" : "RequestCreateCharacter",
"description" : "Requests that the server create a new character with the data provided",
"data" : [ "data" : [
"data" "data"
] ]
}, },
{ {
"messageName" : "ResponseCreateCharacterSuccess", "messageName" : "ResponseCreateCharacterSuccess",
"description" : "Tells the client that it successfully created a character",
"data" : [] "data" : []
}, },
{ {
"messageName" : "ResponseCreateCharacterFailure", "messageName" : "ResponseCreateCharacterFailure",
"description" : "Tells the client that it failed to create a character",
"data" : [] "data" : []
}, },
{ {
"messageName" : "RequestSpawnCharacter", "messageName" : "RequestSpawnCharacter",
"description" : "Requests that the server spawn the client in as a given character",
"data" : [] "data" : []
}, },
{ {
"messageName" : "ResponseSpawnCharacter", "messageName" : "ResponseSpawnCharacter",
"description" : "Deprecated - Unused",
"data" : [ "data" : [
"data" "data"
] ]

View File

@ -117,6 +117,7 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "Create", "messageName" : "Create",
"description" : "Spawns an empty entity on the client",
"data" : [ "data" : [
"entityID", "entityID",
"entityCategory", "entityCategory",
@ -128,6 +129,7 @@
}, },
{ {
"messageName" : "SpawnCreature", "messageName" : "SpawnCreature",
"description" : "Spawns a creature on the client",
"data" : [ "data" : [
"entityID", "entityID",
"creatureTemplate", "creatureTemplate",
@ -138,6 +140,7 @@
}, },
{ {
"messageName" : "SpawnItem", "messageName" : "SpawnItem",
"description" : "Spawns an item on the client",
"data" : [ "data" : [
"entityID", "entityID",
"creatureTemplate", "creatureTemplate",
@ -146,28 +149,9 @@
"positionZ" "positionZ"
] ]
}, },
{
"messageName" : "SetPosition",
"data" : [
"entityID",
"time",
"positionX",
"positionY",
"positionZ"
]
},
{
"messageName" : "setFacing",
"data" : [
"entityID",
"time",
"rotationX",
"rotationY",
"rotationZ"
]
},
{ {
"messageName" : "moveUpdate", "messageName" : "moveUpdate",
"description" : "Updates a client on the move state of an entity",
"data" : [ "data" : [
"entityID", "entityID",
"time", "time",
@ -179,11 +163,13 @@
"rotationZ", "rotationZ",
"rotationW", "rotationW",
"velocity", "velocity",
"propertyValueInt",
"treeState" "treeState"
] ]
}, },
{ {
"messageName" : "attackUpdate", "messageName" : "attackUpdate",
"description" : "Updates the client on the status of a given attack",
"data" : [ "data" : [
"entityID", "entityID",
"time", "time",
@ -199,20 +185,12 @@
}, },
{ {
"messageName" : "startAttack", "messageName" : "startAttack",
"description" : "Alerts the server that the client wants to start attacking",
"data" : [] "data" : []
}, },
{
"messageName" : "Move",
"data" : [
"entityID",
"time",
"positionX",
"positionY",
"positionZ"
]
},
{ {
"messageName" : "Kill", "messageName" : "Kill",
"description" : "Kills an entity (ie plays death animation, creates effects, etc -- does not actually delete the entity from data/scene)",
"data" : [ "data" : [
"time", "time",
"entityID" "entityID"
@ -220,21 +198,14 @@
}, },
{ {
"messageName" : "Destroy", "messageName" : "Destroy",
"description" : "Destroys an entity, clearing it from the client scene",
"data" : [ "data" : [
"entityID" "entityID"
] ]
}, },
{
"messageName" : "SetBehaviorTree",
"data" : [
"entityID",
"time",
"treeType",
"treeStatus"
]
},
{ {
"messageName" : "setProperty", "messageName" : "setProperty",
"description" : "Sets a property on an entity (old method user to set the player's entity)",
"data" : [ "data" : [
"entityID", "entityID",
"time", "time",
@ -242,58 +213,9 @@
"propertyValue" "propertyValue"
] ]
}, },
{
"messageName": "setBTreePropertyInt",
"data" : [
"entityID",
"time",
"bTreeID",
"propertyID",
"propertyValueInt"
]
},
{
"messageName": "setBTreePropertyFloat",
"data" : [
"entityID",
"time",
"bTreeID",
"propertyID",
"propertyValueFloat"
]
},
{
"messageName": "setBTreePropertyDouble",
"data" : [
"entityID",
"time",
"bTreeID",
"propertyID",
"propertyValueDouble"
]
},
{
"messageName": "setBTreePropertyString",
"data" : [
"entityID",
"time",
"bTreeID",
"propertyID",
"propertyValueString"
]
},
{
"messageName": "setBTreePropertyEnum",
"data" : [
"entityID",
"time",
"bTreeID",
"propertyID",
"propertyValueInt"
]
},
{ {
"messageName" : "attachEntityToEntity", "messageName" : "attachEntityToEntity",
"description" : "Tells the client to attach an entity to another entity",
"data" : [ "data" : [
"entityID", "entityID",
"bone", "bone",
@ -302,6 +224,7 @@
}, },
{ {
"messageName" : "SpawnFoliageSeed", "messageName" : "SpawnFoliageSeed",
"description" : "Spawns a foliage object on the client with a given seed value",
"data" : [ "data" : [
"entityID", "entityID",
"creatureTemplate", "creatureTemplate",
@ -310,6 +233,17 @@
"positionY", "positionY",
"positionZ" "positionZ"
] ]
},
{
"messageName" : "updateEntityViewDir",
"description" : "Updates the server's value for where the player is looking",
"data" : [
"entityID",
"time",
"positionX",
"positionY",
"positionZ"
]
} }

View File

@ -42,6 +42,7 @@
}, },
{ {
"messageName" : "clientRequestEquipItem", "messageName" : "clientRequestEquipItem",
"description" : "Requests that the server equip an item to the player's entity",
"data" : [ "data" : [
"equipPointId", "equipPointId",
"entityId" "entityId"
@ -49,6 +50,7 @@
}, },
{ {
"messageName" : "serverCommandMoveItemContainer", "messageName" : "serverCommandMoveItemContainer",
"description" : "Instructs the client to move an item to a container",
"data" : [ "data" : [
"entityId", "entityId",
"containerType", "containerType",
@ -57,6 +59,7 @@
}, },
{ {
"messageName" : "serverCommandEquipItem", "messageName" : "serverCommandEquipItem",
"description" : "Instructs the client to equip an item to an entity",
"data" : [ "data" : [
"equipperId", "equipperId",
"equipPointId", "equipPointId",
@ -66,6 +69,7 @@
}, },
{ {
"messageName" : "serverCommandUnequipItem", "messageName" : "serverCommandUnequipItem",
"description" : "Instructs the client to unequip an item",
"data" : [ "data" : [
"equipperId", "equipperId",
"equipPointId" "equipPointId"
@ -73,6 +77,7 @@
}, },
{ {
"messageName" : "clientRequestUnequipItem", "messageName" : "clientRequestUnequipItem",
"description" : "Requests that the server unequip an item from the client's entity",
"data" : [ "data" : [
"equipPointId" "equipPointId"
] ]

View File

@ -13,32 +13,12 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "RequestRaces", "messageName" : "RequestRaces",
"description" : "Requests the data for all races available to the character to play",
"data" : [] "data" : []
}, },
{ {
"messageName" : "ResponseRaces", "messageName" : "ResponseRaces",
"data" : [ "description" : "Responds with the data on all races available for play",
"data"
]
},
{
"messageName" : "RequestRaceData",
"data" : []
},
{
"messageName" : "ResponseRaceData",
"data" : [
"data"
]
},
{
"messageName" : "RequestData",
"data" : [
"data"
]
},
{
"messageName" : "ResponseData",
"data" : [ "data" : [
"data" "data"
] ]

View File

@ -25,12 +25,14 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "Set_ID", "messageName" : "Set_ID",
"description" : "Provides the server's id for the player",
"data" : [ "data" : [
"playerID" "playerID"
] ]
}, },
{ {
"messageName" : "SetInitialDiscretePosition", "messageName" : "SetInitialDiscretePosition",
"description" : "Tells the client the initial position of the player entity",
"data" : [ "data" : [
"initialDiscretePositionX", "initialDiscretePositionX",
"initialDiscretePositionY", "initialDiscretePositionY",

View File

@ -10,10 +10,12 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "Ping", "messageName" : "Ping",
"description" : "Pings the other side of the socket",
"data" : [] "data" : []
}, },
{ {
"messageName" : "Pong", "messageName" : "Pong",
"description" : "Replies to a ping from the other side of the socket",
"data" : [] "data" : []
} }
] ]
@ -35,10 +37,12 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "AuthRequest", "messageName" : "AuthRequest",
"description" : "Requests authorization from the client",
"data" : [] "data" : []
}, },
{ {
"messageName" : "AuthDetails", "messageName" : "AuthDetails",
"description" : "Tells the server the auth details of this client",
"data" : [ "data" : [
"user", "user",
"pass" "pass"
@ -46,10 +50,12 @@
}, },
{ {
"messageName" : "AuthSuccess", "messageName" : "AuthSuccess",
"description" : "Tells the client it successfully logged in",
"data" : [] "data" : []
}, },
{ {
"messageName" : "AuthFailure", "messageName" : "AuthFailure",
"description" : "Tells the client it failed to log in",
"data" : [] "data" : []
} }
] ]

View File

@ -30,6 +30,7 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "UpdateClientState", "messageName" : "UpdateClientState",
"description" : "Updates an integer on the client",
"data" : [ "data" : [
"entityId", "entityId",
"bTreeId", "bTreeId",
@ -39,6 +40,7 @@
}, },
{ {
"messageName" : "UpdateClientStringState", "messageName" : "UpdateClientStringState",
"description" : "Updates a string on the client",
"data" : [ "data" : [
"entityId", "entityId",
"bTreeId", "bTreeId",
@ -48,6 +50,7 @@
}, },
{ {
"messageName" : "AttachTree", "messageName" : "AttachTree",
"description" : "Attaches a btree to an entity on the client",
"data" : [ "data" : [
"entityId", "entityId",
"bTreeId" "bTreeId"
@ -55,6 +58,7 @@
}, },
{ {
"messageName" : "DetatchTree", "messageName" : "DetatchTree",
"description" : "Detatches a btree from an entity on the client",
"data" : [ "data" : [
"entityId", "entityId",
"bTreeId" "bTreeId"

View File

@ -102,10 +102,12 @@
"messageTypes" : [ "messageTypes" : [
{ {
"messageName" : "RequestMetadata", "messageName" : "RequestMetadata",
"description" : "Requests terrain metadata from the server",
"data" : [] "data" : []
}, },
{ {
"messageName" : "ResponseMetadata", "messageName" : "ResponseMetadata",
"description" : "Tell the client the terrain metadata",
"data" : [ "data" : [
"worldSizeDiscrete", "worldSizeDiscrete",
"dynamicInterpolationRatio", "dynamicInterpolationRatio",
@ -116,15 +118,9 @@
"worldMaxY" "worldMaxY"
] ]
}, },
{
"messageName" : "RequestChunk",
"data" : [
"worldX",
"worldY"
]
},
{ {
"messageName" : "RequestEditVoxel", "messageName" : "RequestEditVoxel",
"description" : "Requests that a voxel be edited on the server",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -138,6 +134,7 @@
}, },
{ {
"messageName" : "UpdateVoxel", "messageName" : "UpdateVoxel",
"description" : "Tells the client to update a voxel's value",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -151,6 +148,7 @@
}, },
{ {
"messageName" : "RequestUseTerrainPalette", "messageName" : "RequestUseTerrainPalette",
"description" : "Requests that the current player entity use a given terrain palette",
"data" : [ "data" : [
"realLocationX", "realLocationX",
"realLocationY", "realLocationY",
@ -162,6 +160,7 @@
}, },
{ {
"messageName" : "SpawnPosition", "messageName" : "SpawnPosition",
"description" : "Sets the spawn position of the client",
"data" : [ "data" : [
"realLocationX", "realLocationX",
"realLocationY", "realLocationY",
@ -170,6 +169,7 @@
}, },
{ {
"messageName" : "RequestChunkData", "messageName" : "RequestChunkData",
"description" : "Requests chunk data from the server",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -178,6 +178,7 @@
}, },
{ {
"messageName" : "sendChunkData", "messageName" : "sendChunkData",
"description" : "Sends chunk data to the client",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -187,6 +188,7 @@
}, },
{ {
"messageName" : "RequestFluidData", "messageName" : "RequestFluidData",
"description" : "Requests a fluid data from the server",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -195,6 +197,7 @@
}, },
{ {
"messageName" : "sendFluidData", "messageName" : "sendFluidData",
"description" : "Sends fluid data to the client",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",
@ -204,6 +207,7 @@
}, },
{ {
"messageName" : "updateFluidData", "messageName" : "updateFluidData",
"description" : "Updates fluid data on the client",
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",

View File

@ -2,6 +2,9 @@ package electrosphere.audio;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import electrosphere.util.MathUtils;
import static org.lwjgl.openal.AL10.*; import static org.lwjgl.openal.AL10.*;
/** /**
@ -13,7 +16,7 @@ public class AudioListener {
Vector3d position; Vector3d position;
//eye vector for listener //eye vector for listener
Vector3f eye = new Vector3f(1,0,0); Vector3f eye = MathUtils.getOriginVectorf();
//up vector for listener //up vector for listener
Vector3f up = new Vector3f(0,1,0); Vector3f up = new Vector3f(0,1,0);

View File

@ -1,19 +1,20 @@
package electrosphere.client.scene; package electrosphere.client.scene;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.ode4j.ode.DContactGeom;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.Scene; import electrosphere.entity.Scene;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/** /**
* Wrapper around the scene object to provide lots of much needed client-specific utility * Wrapper around the scene object to provide lots of much needed client-specific utility
@ -31,9 +32,18 @@ public class ClientSceneWrapper {
//The engine used to back physics collision checks in client //The engine used to back physics collision checks in client
CollisionEngine collisionEngine; CollisionEngine collisionEngine;
//The hitbox manager
HitboxManager hitboxManager;
/**
* Constructor
* @param scene The scene
* @param collisionEngine The collision engine
*/
public ClientSceneWrapper(Scene scene, CollisionEngine collisionEngine){ public ClientSceneWrapper(Scene scene, CollisionEngine collisionEngine){
this.scene = scene; this.scene = scene;
this.collisionEngine = collisionEngine; this.collisionEngine = collisionEngine;
this.hitboxManager = new HitboxManager(resolutionCallback);
} }
/** /**
@ -110,6 +120,14 @@ public class ClientSceneWrapper {
return collisionEngine; return collisionEngine;
} }
/**
* Gets the hitbox manager for the client
* @return The hitbox manager
*/
public HitboxManager getHitboxManager(){
return hitboxManager;
}
/** /**
* Destroys all entities outside simulation range * Destroys all entities outside simulation range
*/ */
@ -129,4 +147,15 @@ public class ClientSceneWrapper {
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
/**
* The resolution callback that is invoked once a collision has occurred
*/
CollisionResolutionCallback resolutionCallback = new CollisionResolutionCallback() {
@Override
public void resolve(DContactGeom geom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude) {
HitboxUtils.clientDamageHitboxColision(geom, impactor, receiver, normal, localPosition, worldPos, magnitude);
}
};
} }

View File

@ -6,16 +6,12 @@ import electrosphere.client.fluid.manager.ClientFluidManager;
import electrosphere.client.instancing.InstanceUpdater; import electrosphere.client.instancing.InstanceUpdater;
import electrosphere.client.targeting.crosshair.Crosshair; import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags; import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.collidable.ClientCollidableTree; import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.hitbox.HitboxUtils;
import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.particle.ParticleUtils; import electrosphere.entity.types.particle.ParticleUtils;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
@ -44,6 +40,7 @@ public class ClientSimulation {
public void simulate(){ public void simulate(){
Globals.profiler.beginCpuSample("simulate"); Globals.profiler.beginCpuSample("simulate");
//
//load terrain //load terrain
if(isLoadingTerrain()){ if(isLoadingTerrain()){
loadTerrain(); loadTerrain();
@ -53,10 +50,11 @@ public class ClientSimulation {
Globals.profiler.beginCpuSample("clientSynchronizationManager.processMessages"); Globals.profiler.beginCpuSample("clientSynchronizationManager.processMessages");
Globals.clientSynchronizationManager.processMessages(); Globals.clientSynchronizationManager.processMessages();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//simulate bullet physics engine step //simulate bullet physics engine step
Globals.clientSceneWrapper.getCollisionEngine().simulatePhysics((float)Globals.timekeeper.getSimFrameTime()); Globals.clientSceneWrapper.getCollisionEngine().simulatePhysics((float)Globals.timekeeper.getSimFrameTime());
Globals.clientSceneWrapper.getCollisionEngine().updateDynamicObjectTransforms(); Globals.clientSceneWrapper.getCollisionEngine().updateDynamicObjectTransforms();
//update actor animations //update actor animations
Globals.profiler.beginCpuSample("update actor animations"); Globals.profiler.beginCpuSample("update actor animations");
for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){ for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){
@ -66,12 +64,14 @@ public class ClientSimulation {
} }
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//make items play idle animation //make items play idle animation
Globals.profiler.beginCpuSample("item animations"); Globals.profiler.beginCpuSample("item animations");
for(Entity item : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM)){ for(Entity item : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM)){
ItemUtils.updateItemActorAnimation(item); ItemUtils.updateItemActorAnimation(item);
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//particle state updates //particle state updates
Globals.profiler.beginCpuSample("particle state updates"); Globals.profiler.beginCpuSample("particle state updates");
for(Entity particle : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.PARTICLE)){ for(Entity particle : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.PARTICLE)){
@ -80,18 +80,12 @@ public class ClientSimulation {
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//update attached entity positions //update attached entity positions
AttachUtils.clientUpdateAttachedEntityPositions(); AttachUtils.clientUpdateAttachedEntityPositions();
//update hitbox positions //
Globals.profiler.beginCpuSample("Hitbox updates"); //Hitbox stuff
for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){ Globals.profiler.beginCpuSample("update hitboxes");
HitboxUtils.clientUpdatePosition(currentHitbox); Globals.clientSceneWrapper.getHitboxManager().simulate();
}
//collide hitboxes
for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){
if(isReady){
HitboxUtils.clientCollideEntities(currentHitbox);
}
}
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//update audio engine //update audio engine
Globals.profiler.beginCpuSample("audio engine update"); Globals.profiler.beginCpuSample("audio engine update");
if(Globals.audioEngine!=null){ if(Globals.audioEngine!=null){
@ -99,31 +93,32 @@ public class ClientSimulation {
Globals.virtualAudioSourceManager.update((float)Globals.timekeeper.getSimFrameTime()); Globals.virtualAudioSourceManager.update((float)Globals.timekeeper.getSimFrameTime());
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//update foliage //update foliage
if(Globals.clientFoliageManager != null){ if(Globals.clientFoliageManager != null){
Globals.clientFoliageManager.update(); Globals.clientFoliageManager.update();
} }
//tally collidables and offset position accordingly //
// for(Entity currentCollidable : Globals.entityManager.getEntitiesWithTag(EntityTags.COLLIDABLE)){
// CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable);
// tree.simulate(Main.deltaFrames);
// }
//targeting crosshair //targeting crosshair
Globals.profiler.beginCpuSample("crosshair update"); Globals.profiler.beginCpuSample("crosshair update");
Crosshair.checkTargetable(); Crosshair.checkTargetable();
Crosshair.updateTargetCrosshairPosition(); Crosshair.updateTargetCrosshairPosition();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//simulate behavior trees //simulate behavior trees
Globals.clientSceneWrapper.getScene().simulateBehaviorTrees((float)Globals.timekeeper.getSimFrameTime()); Globals.clientSceneWrapper.getScene().simulateBehaviorTrees((float)Globals.timekeeper.getSimFrameTime());
//
//sum collidable impulses //sum collidable impulses
Globals.profiler.beginCpuSample("collidable logic"); Globals.profiler.beginCpuSample("collidable logic");
for(Entity collidable : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){ for(Entity collidable : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){
ClientCollidableTree.getClientCollidableTree(collidable).simulate((float)Globals.timekeeper.getSimFrameTime()); ClientCollidableTree.getClientCollidableTree(collidable).simulate((float)Globals.timekeeper.getSimFrameTime());
} }
//
//clear collidable impulse lists //clear collidable impulse lists
Globals.clientSceneWrapper.getCollisionEngine().clearCollidableImpulseLists(); Globals.clientSceneWrapper.getCollisionEngine().clearCollidableImpulseLists();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//
//wrap up functions //wrap up functions
runClientFunctions(); runClientFunctions();

View File

@ -11,10 +11,11 @@ import org.lwjgl.assimp.AIVector3D;
import org.ode4j.math.DMatrix3; import org.ode4j.math.DMatrix3;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
import org.ode4j.ode.DBox; import org.ode4j.ode.DBox;
import org.ode4j.ode.DCapsule;
import org.ode4j.ode.DCylinder; import org.ode4j.ode.DCylinder;
import org.ode4j.ode.DGeom;
import org.ode4j.ode.DSphere; import org.ode4j.ode.DSphere;
import org.ode4j.ode.DTriMesh; import org.ode4j.ode.DTriMesh;
import org.ode4j.ode.OdeHelper;
import electrosphere.entity.types.terrain.TerrainChunkData; import electrosphere.entity.types.terrain.TerrainChunkData;
@ -24,6 +25,7 @@ import electrosphere.entity.types.terrain.TerrainChunkData;
public class CollisionBodyCreation { public class CollisionBodyCreation {
//Matrix for correcting initial axis of eg cylinders or capsules //Matrix for correcting initial axis of eg cylinders or capsules
//this rotates by 90 degrees along the x axis
public static final DMatrix3 AXIS_CORRECTION_MATRIX = new DMatrix3( public static final DMatrix3 AXIS_CORRECTION_MATRIX = new DMatrix3(
1.0000000, 0.0000000, 0.0000000, 1.0000000, 0.0000000, 0.0000000,
0.0000000, 0.0000000, -1.0000000, 0.0000000, 0.0000000, -1.0000000,
@ -81,6 +83,39 @@ public class CollisionBodyCreation {
return collisionEngine.createDBody(geom); return collisionEngine.createDBody(geom);
} }
/**
* Creates a dbody with existing shapes that are provided
* @param collisionEngine the collision engine to create it in
* @param geoms the geometries to attach
* @return the dbody
*/
public static DBody createBodyWithShapes(CollisionEngine collisionEngine, DGeom ... geoms){
return collisionEngine.createDBody(geoms);
}
/**
* Creates a sphere shape
* @param collisionEngine the collision engine
* @param radius the radius of the sphere
* @param categoryBits the category bits for the shape
* @return the sphere shape
*/
public static DSphere createShapeSphere(CollisionEngine collisionEngine, double radius, long categoryBits){
return collisionEngine.createSphereGeom(radius, categoryBits);
}
/**
* Creates a capsule shape
* @param collisionEngine The collision engine
* @param radius the radius of the capsule
* @param length the length of the capsule
* @param categoryBits the category bits for the shape
* @return the capsule shape
*/
public static DCapsule createCapsuleShape(CollisionEngine collisionEngine, double radius, double length, long categoryBits){
return collisionEngine.createCapsuleGeom(radius, length, categoryBits);
}
/** /**
* Sets the provided body to be a kinematic body (no gravity applied) * Sets the provided body to be a kinematic body (no gravity applied)
* @param collisionEngine The collision engine * @param collisionEngine The collision engine
@ -110,6 +145,35 @@ public class CollisionBodyCreation {
collisionEngine.setOffsetPosition(body, offsetPosition); collisionEngine.setOffsetPosition(body, offsetPosition);
} }
/**
* Removes a geom from a body
* @param collisionEngine the collision engine
* @param body the body
* @param geom the geometry
*/
public static void removeShapeFromBody(CollisionEngine collisionEngine, DBody body, DGeom geom){
collisionEngine.removeGeometryFromBody(body, geom);
}
/**
* Destroys a geometry
* @param collisionEngine The collision engine
* @param geom the geometry
*/
public static void destroyShape(CollisionEngine collisionEngine, DGeom geom){
collisionEngine.destroyGeom(geom);
}
/**
* Attaches a geom to a body
* @param collisionEngine the collision engine
* @param body the body
* @param geom the geometry
*/
public static void attachGeomToBody(CollisionEngine collisionEngine, DBody body, DGeom geom){
collisionEngine.attachGeomToBody(body, geom);
}
/** /**
* Creates an ode DBody from a terrain chunk data object * Creates an ode DBody from a terrain chunk data object
@ -154,7 +218,7 @@ public class CollisionBodyCreation {
*/ */
public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene, long categoryBits){ public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene, long categoryBits){
DBody body = collisionEngine.createDBody(null); DBody body = collisionEngine.createDBody((DGeom[])null);
PointerBuffer meshesBuffer = scene.mMeshes(); PointerBuffer meshesBuffer = scene.mMeshes();
while(meshesBuffer.hasRemaining()){ while(meshesBuffer.hasRemaining()){

View File

@ -31,6 +31,7 @@ import org.ode4j.ode.DBox;
import org.ode4j.ode.DCapsule; import org.ode4j.ode.DCapsule;
import org.ode4j.ode.DContact; import org.ode4j.ode.DContact;
import org.ode4j.ode.DContactBuffer; import org.ode4j.ode.DContactBuffer;
import org.ode4j.ode.DContactGeom;
import org.ode4j.ode.DContactJoint; import org.ode4j.ode.DContactJoint;
import org.ode4j.ode.DCylinder; import org.ode4j.ode.DCylinder;
import org.ode4j.ode.DGeom; import org.ode4j.ode.DGeom;
@ -50,12 +51,13 @@ import org.ode4j.ode.OdeHelper;
import electrosphere.collision.RayCastCallback.RayCastCallbackData; import electrosphere.collision.RayCastCallback.RayCastCallbackData;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.time.Timekeeper;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.types.hitbox.HitboxData;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
/** /**
@ -63,9 +65,6 @@ import electrosphere.logger.LoggerInterface;
*/ */
public class CollisionEngine { public class CollisionEngine {
//step interval time size
public static final float ENGINE_STEP_SIZE = 0.01f;
//gravity constant //gravity constant
public static final float GRAVITY_MAGNITUDE = 9.8f * 2; public static final float GRAVITY_MAGNITUDE = 9.8f * 2;
@ -91,16 +90,44 @@ public class CollisionEngine {
//callbacks for collision check //callbacks for collision check
RayCastCallback rayCastCallback = new RayCastCallback(); RayCastCallback rayCastCallback = new RayCastCallback();
//the collision resolution callback
CollisionResolutionCallback collisionResolutionCallback;
//buffer for collisions
DContactBuffer contacts = null;
// Callback for any near collisions in the broadphase of the collision check
private DNearCallback nearCallback;
/**
* Constructor
*/
public CollisionEngine(){ public CollisionEngine(){
world = OdeHelper.createWorld(); world = OdeHelper.createWorld();
space = OdeHelper.createBHVSpace(Collidable.TYPE_STATIC_BIT); space = OdeHelper.createBHVSpace(Collidable.TYPE_STATIC_BIT);
world.setGravity(0,-GRAVITY_MAGNITUDE,0); world.setGravity(0,-GRAVITY_MAGNITUDE,0);
contactgroup = OdeHelper.createJointGroup(); contactgroup = OdeHelper.createJointGroup();
this.nearCallback = new DNearCallback() {
@Override
public void call(Object data, DGeom o1, DGeom o2) {
nearCallback( data, o1, o2);
}
};
} }
public static void resolveCollision(Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude){ /**
* Resolves collisions in the engine
* @param contactGeom the ode4j contact geometry
* @param impactor the instigator of the collision
* @param receiver the receiver of the collision
* @param normal the normal to the collision surface
* @param localPosition the local position of the collision
* @param worldPos the world position of the collision
* @param magnitude the magnitude of the collision
*/
public static void resolveCollision(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude){
switch(receiver.getType()){ switch(receiver.getType()){
case Collidable.TYPE_CREATURE: case Collidable.TYPE_CREATURE:
switch(impactor.getType()){ switch(impactor.getType()){
@ -223,7 +250,7 @@ public class CollisionEngine {
//simulate physics //simulate physics
Globals.profiler.beginCpuSample("step physics"); Globals.profiler.beginCpuSample("step physics");
world.quickStep(ENGINE_STEP_SIZE); world.quickStep(Timekeeper.ENGINE_STEP_SIZE);
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
// remove all contact joints // remove all contact joints
@ -233,27 +260,45 @@ public class CollisionEngine {
} }
/** /**
* Callback for any near collisions in the broadphase of the collision check * Runs a collision cycle on all bodies in the collision engine
*/ */
private DNearCallback nearCallback = new DNearCallback() { public void collide(){
@Override Globals.profiler.beginCpuSample("physics");
public void call(Object data, DGeom o1, DGeom o2) { spaceLock.acquireUninterruptibly();
nearCallback( data, o1, o2); Globals.profiler.beginCpuSample("collide");
} OdeHelper.spaceCollide(space, 0, nearCallback);
}; Globals.profiler.endCpuSample();
//buffer for collisions // remove all contact joints
DContactBuffer contacts = null; contactgroup.empty();
spaceLock.release();
Globals.profiler.endCpuSample();
}
// this is called by dSpaceCollide when two objects in space are /**
// potentially colliding. * Sets the near callback function for all collision calls.
* !!YOU LIKELY WANT TO INSTEAD OVERWRITE THE CollisionResolutionCallback!!
* @param callback the callback
*/
public void setNearCallback(DNearCallback callback){
this.nearCallback = callback;
}
/**
* This is called by dSpaceCollide when two objects in space are potentially colliding.
* @param data The data
* @param o1 the first collision body
* @param o2 the second collision body
*/
private void nearCallback (Object data, DGeom o1, DGeom o2) { private void nearCallback (Object data, DGeom o1, DGeom o2) {
// if (o1->body && o2->body) return; // if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint // exit without doing anything if the two bodies are connected by a joint
DBody b1 = o1.getBody(); DBody b1 = o1.getBody();
DBody b2 = o2.getBody(); DBody b2 = o2.getBody();
if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)) return; if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)){
return;
}
//creates a buffer to store potential collisions //creates a buffer to store potential collisions
DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box
@ -284,33 +329,51 @@ public class CollisionEngine {
DContact contact = contacts.get(i); DContact contact = contacts.get(i);
//special code for ray casting //special code for ray casting
if (o1 instanceof DRay || o2 instanceof DRay){ if (o1 instanceof DRay || o2 instanceof DRay){
DMatrix3 Rotation = new DMatrix3(); DVector3 end = new DVector3();
Rotation.setIdentity(); end.eqSum( contact.geom.pos, contact.geom.normal, contact.geom.depth );
// dsDrawSphere(contact.geom.pos, Rotation, (0.01));
DVector3 End = new DVector3();
End.eqSum( contact.geom.pos, contact.geom.normal, contact.geom.depth );
// dsDrawLine(contact.geom.pos, End);
continue; continue;
} }
// contact.geom.pos // Use the default collision resolution
resolveCollision( if(collisionResolutionCallback == null) {
bodyPointerMap.get(o1.getBody()), resolveCollision(
bodyPointerMap.get(o2.getBody()), contact.geom,
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0), bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0), bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos), PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
(float)contact.geom.depth PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
resolveCollision(
contact.geom,
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
} else {
//use custom collision resolution
collisionResolutionCallback.resolve(
contact.geom,
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
); );
resolveCollision( collisionResolutionCallback.resolve(
bodyPointerMap.get(o2.getBody()), contact.geom,
bodyPointerMap.get(o1.getBody()), bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal), bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.fdir1), PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos), PhysicsUtils.odeVecToJomlVec(contact.fdir1),
(float)contact.geom.depth PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
); );
}
//add contact to contact group //add contact to contact group
DJoint c = OdeHelper.createContactJoint (world,contactgroup,contact ); DJoint c = OdeHelper.createContactJoint (world,contactgroup,contact );
@ -325,6 +388,14 @@ public class CollisionEngine {
} }
} }
} }
/**
* Sets the function that is called once a collision has happened
* @param collisionResolutionCallback the function
*/
public void setCollisionResolutionCallback(CollisionResolutionCallback collisionResolutionCallback){
this.collisionResolutionCallback = collisionResolutionCallback;
}
/** /**
* *
@ -691,6 +762,19 @@ public class CollisionEngine {
spaceLock.release(); spaceLock.release();
} }
/**
* Sets the transform of a geometry
* @param geom The geometry
* @param position The position
* @param rotation The rotation
*/
protected void setGeomTransform(DGeom geom, Vector3d position, Quaterniond rotation){
spaceLock.acquireUninterruptibly();
geom.setOffsetWorldPosition(position.x, position.y, position.z);
geom.setOffsetQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
spaceLock.release();
}
/** /**
* Corrects the initial axis of eg cylinders or capsules * Corrects the initial axis of eg cylinders or capsules
* @param geom the geometry to correct * @param geom the geometry to correct
@ -758,5 +842,49 @@ public class CollisionEngine {
body.getGeomIterator().next().setOffsetPosition(offsetVector.x,offsetVector.y,offsetVector.z); body.getGeomIterator().next().setOffsetPosition(offsetVector.x,offsetVector.y,offsetVector.z);
spaceLock.release(); spaceLock.release();
} }
/**
* Removes the geometry from the body
* @param body the body
* @param geom the geometry
*/
protected void removeGeometryFromBody(DBody body, DGeom geom){
geom.setBody(null);
}
/**
* Destroys a geometry
* @param geom The geometry
*/
protected void destroyGeom(DGeom geom){
geom.destroy();
}
/**
* Attaches a geom to a body
* @param body the body
* @param geom the geom
*/
protected void attachGeomToBody(DBody body, DGeom geom){
geom.setBody(body);
}
/**
* A callback for resolving collisions between two entities
*/
public interface CollisionResolutionCallback {
/**
* Resolves a collision between two collidables in the engine
* @param contactGeom the ode4j contact geom
* @param impactor The collidable initiating the contact
* @param receiver The collidable recieving the contact
* @param normal The normal of the collision
* @param localPosition The local position of the collision
* @param worldPos The world position of the collision
* @param magnitude The magnitude of the collision
*/
public void resolve(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude);
}
} }

View File

@ -2,10 +2,11 @@ package electrosphere.collision;
import org.joml.Matrix4d; import org.joml.Matrix4d;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
import org.ode4j.ode.DCylinder; import org.ode4j.ode.DGeom;
import org.ode4j.ode.DTriMesh; import org.ode4j.ode.DTriMesh;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
@ -301,5 +302,14 @@ public class PhysicsEntityUtils {
public static DBody getDBody(Entity entity){ public static DBody getDBody(Entity entity){
return (DBody)entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); return (DBody)entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
} }
/**
* Sets the position of a DGeom
* @param collisionEngine the collision engine
* @param geom the geometry
*/
public static void setGeometryPosition(CollisionEngine collisionEngine, DGeom geom, Vector3d position, Quaterniond rotation){
collisionEngine.setGeomTransform(geom, position, rotation);
}
} }

View File

@ -39,7 +39,15 @@ public class PhysicsUtils {
*/ */
public static Vector3d odeVecToJomlVec(org.ode4j.math.DVector3C vector){ public static Vector3d odeVecToJomlVec(org.ode4j.math.DVector3C vector){
return new Vector3d(vector.get0(),vector.get1(),vector.get2()); return new Vector3d(vector.get0(),vector.get1(),vector.get2());
}
/**
* Converts a joml vector to an Ode vector
* @param vector joml vector
* @return Ode vector
*/
public static org.ode4j.math.DVector3C jomlVecToOdeVec(Vector3d vector){
return new org.ode4j.math.DVector3(vector.x,vector.y,vector.z);
} }
/** /**

View File

@ -0,0 +1,85 @@
package electrosphere.collision.hitbox;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.engine.Globals;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Manages all hitboxes on either the server or client
*/
public class HitboxManager {
//the list of all hitboxes
CopyOnWriteArrayList<HitboxCollectionState> hitboxes = new CopyOnWriteArrayList<HitboxCollectionState>();
//the collision engine for this hitbox manager
CollisionEngine collisionEngine;
//an id incrementer for hitboxes
long idIncrementer = 0;
/**
* Constructor
* @param resolutionCallback The callback that fires when a collision occurs
*/
public HitboxManager(CollisionResolutionCallback resolutionCallback){
collisionEngine = new CollisionEngine();
collisionEngine.setCollisionResolutionCallback(resolutionCallback);
}
/**
* Registers a hitbox to the manager
* @param hitbox the hitbox to register
*/
public void registerHitbox(HitboxCollectionState hitbox){
hitboxes.add(hitbox);
idIncrementer++;
}
/**
* Gets all hitboxes in the manager
* @return all hitboxes in the manager
*/
public CopyOnWriteArrayList<HitboxCollectionState> getAllHitboxes(){
return hitboxes;
}
/**
* Deregisters a hitbox from the manager
* @param hitbox the hitbox to deregister
*/
public void deregisterHitbox(HitboxCollectionState hitbox){
hitboxes.remove(hitbox);
}
/**
* Gets the collision engine associated with the hitbox manager
* @return The collision engine
*/
public CollisionEngine getCollisionEngine(){
return this.collisionEngine;
}
/**
* Runs all per frame functions of the hitbox manager
*/
public void simulate(){
//update all positions
Globals.profiler.beginCpuSample("Update hitbox positions");
for(HitboxCollectionState state : hitboxes){
state.clearCollisions();
state.updateHitboxPositions(this.collisionEngine);
}
Globals.profiler.endCpuSample();
//collide hitboxes
Globals.profiler.beginCpuSample("Collide hitboxes");
this.collisionEngine.collide();
this.collisionEngine.clearCollidableImpulseLists();
Globals.profiler.endCpuSample();
}
}

View File

@ -0,0 +1,324 @@
package electrosphere.collision.hitbox;
import electrosphere.collision.collidable.Collidable;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxType;
import electrosphere.game.data.collidable.HitboxData;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DContactGeom;
import org.ode4j.ode.DGeom;
/**
* Utilities for working with hitboxes
*/
public class HitboxUtils {
// /**
// * Spawns a hitbox entity on the client
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone on the parent to attach to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hitbox entity on the server
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone to attach to the hitbox to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hurtbox on the client
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hurtbox on the server
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
public static void clientUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
/**
* Updates the position of a hitbox
* @param hitbox the hitbox to update
*/
public static void serverUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3d(parentPos.x,parentPos.y,parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
/**
* Handles a damage collision on the client
* @param impactor the entity initiating the collision
* @param receiver the entity receiving the collision
*/
public static void clientDamageHitboxColision(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude){
Entity impactorParent = impactor.getParent();
Entity receiverParent = receiver.getParent();
HitboxCollectionState impactorState = HitboxCollectionState.getHitboxState(impactorParent);
HitboxCollectionState receiverState = HitboxCollectionState.getHitboxState(receiverParent);
DGeom impactorGeom = contactGeom.g1;
DGeom receiverGeom = contactGeom.g2;
HitboxState impactorShapeStatus = impactorState.getShapeStatus(impactorGeom);
HitboxState receiverShapeStatus = receiverState.getShapeStatus(receiverGeom);
//currently, impactor needs to be an item, and the receiver must not be an item
boolean isDamageEvent =
impactorShapeStatus != null &&
receiverShapeStatus != null &&
impactorShapeStatus.getType() == HitboxType.HIT &&
receiverShapeStatus.getType() == HitboxType.HURT &&
AttachUtils.getParent(impactorParent) != receiverParent
;
if(impactorShapeStatus != null){
impactorShapeStatus.setHadCollision(true);
}
if(receiverShapeStatus != null){
receiverShapeStatus.setHadCollision(true);
}
if(isDamageEvent){
//TODO: client logic for audio etc
}
// Entity hitboxParent = (Entity)impactor.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
// Entity hurtboxParent = (Entity)receiver.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
// boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
// Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
// if(isItem){
// if(hitboxAttachParent != hurtboxParent){
// Vector3d hurtboxPos = EntityUtils.getPosition(receiver);
// ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
// }
// } else {
// //client no longer manages damage; however, keeping this code around for the moment to show how we
// //might approach adding client-side effects as soon as impact occurs (ie play a sound, shoot sparks, etc)
// //before the server responds with a valid collision event or not
// // int damage = 0;
// // //for entities using attacktree
// // if(CreatureUtils.clientGetAttackTree(hitboxParent) != null){
// // damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
// // } else {
// // //for entities using shooter tree
// // if(ProjectileTree.getProjectileTree(hitboxParent) != null){
// // damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
// // }
// // }
// // LifeUtils.getLifeState(hurtboxParent).damage(damage);
// // if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
// // EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
// // LifeUtils.getLifeState(hurtboxParent).revive();
// // }
// }
}
/**
* Gets the data for a hitbox
* @param e the entity encapsulating the hitbox
* @return the hitbox data
*/
public static HitboxData getHitboxData(Entity e){
return (HitboxData)e.getData(EntityDataStrings.HITBOX_DATA);
}
/**
* Intended to be implemented as an anonoymous class when needed
*/
public interface HitboxPositionCallback {
/**
* Gets the current position this hitbox should be at
* @return The position this hitbox should be at
*/
public Vector3d getPosition();
}
}

View File

@ -10,19 +10,36 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.ui.events.MouseEvent; import electrosphere.renderer.ui.events.MouseEvent;
import electrosphere.util.MathUtils;
/**
* Handler for camera-related events and controls
*/
public class CameraHandler { public class CameraHandler {
//the horizontal mouse sensitivity
float mouseSensitivityHorizontal = .1f; float mouseSensitivityHorizontal = .1f;
//the vertical mouse sensitivity
float mouseSensitivityVertical = .08f; float mouseSensitivityVertical = .08f;
//the speed of the freecam
float cameraSpeed; float cameraSpeed;
//the current yaw
float yaw = 150; float yaw = 150;
//the current pitch
float pitch = 50; float pitch = 50;
//the camera's rotation vector
Vector3f cameraRotationVector = new Vector3f(); Vector3f cameraRotationVector = new Vector3f();
//the radial offset of the camera
Vector3f radialOffset = new Vector3f(0,1,0); Vector3f radialOffset = new Vector3f(0,1,0);
//if set to true, the camera will track the player's entity
boolean trackPlayerEntity = true; boolean trackPlayerEntity = true;
/**
* Handles a mouse event
* @param event The mouse event
*/
public void handleMouseEvent(MouseEvent event){ public void handleMouseEvent(MouseEvent event){
if(Globals.controlHandler != null && !Globals.controlHandler.isMouseVisible()){ if(Globals.controlHandler != null && !Globals.controlHandler.isMouseVisible()){
@ -40,10 +57,17 @@ public class CameraHandler {
updateGlobalCamera(); updateGlobalCamera();
} }
/**
* Updates the radial offset
* @param offset the radial offset
*/
public void updateRadialOffset(Vector3f offset){ public void updateRadialOffset(Vector3f offset){
radialOffset = offset; radialOffset = offset;
} }
/**
* Updates the global camera
*/
public void updateGlobalCamera(){ public void updateGlobalCamera(){
Globals.profiler.beginCpuSample("updateGlobalCamera"); Globals.profiler.beginCpuSample("updateGlobalCamera");
if(Globals.playerCamera != null){ if(Globals.playerCamera != null){
@ -82,7 +106,7 @@ public class CameraHandler {
// float pitchRad = pitch / 180.0f * (float)Math.PI; // float pitchRad = pitch / 180.0f * (float)Math.PI;
// float rollRad = 0.0f; // float rollRad = 0.0f;
// pitchQuat.mul(yawQuat); // pitchQuat.mul(yawQuat);
cameraRotationVector = pitchQuat.transform(new Vector3f(0,0,1)); cameraRotationVector = pitchQuat.transform(MathUtils.getOriginVectorf());
cameraRotationVector = yawQuat.transform(cameraRotationVector); cameraRotationVector = yawQuat.transform(cameraRotationVector);
cameraRotationVector.normalize(); cameraRotationVector.normalize();
@ -107,8 +131,21 @@ public class CameraHandler {
cameraRotationVector.mul(CameraEntityUtils.getOrbitalCameraDistance(Globals.playerCamera)); cameraRotationVector.mul(CameraEntityUtils.getOrbitalCameraDistance(Globals.playerCamera));
CameraEntityUtils.setCameraEye(Globals.playerCamera, cameraRotationVector); CameraEntityUtils.setCameraEye(Globals.playerCamera, cameraRotationVector);
//tell the server that we changed where we're looking
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructupdateEntityViewDirMessage(
Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId()),
Globals.timekeeper.getNumberOfSimFramesElapsed(),
cameraRotationVector.x,
cameraRotationVector.y,
cameraRotationVector.z
)
);
//the view matrix
Globals.viewMatrix = CameraEntityUtils.getCameraViewMatrix(Globals.playerCamera); Globals.viewMatrix = CameraEntityUtils.getCameraViewMatrix(Globals.playerCamera);
//update the cursor on client side
updatePlayerCursor(); updatePlayerCursor();
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
@ -136,10 +173,18 @@ public class CameraHandler {
} }
} }
/**
* Gets the yaw of the camera handler
* @return the yaw
*/
public float getYaw(){ public float getYaw(){
return yaw; return yaw;
} }
/**
* Gets the pitch of the camera handler
* @return the pitch
*/
public float getPitch(){ public float getPitch(){
return pitch; return pitch;
} }

View File

@ -61,6 +61,7 @@ import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_RIGHT;
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos; import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
import static org.lwjgl.glfw.GLFW.glfwSetInputMode; import static org.lwjgl.glfw.GLFW.glfwSetInputMode;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -107,8 +108,7 @@ import electrosphere.renderer.ui.events.MouseEvent;
import electrosphere.renderer.ui.events.ScrollEvent; import electrosphere.renderer.ui.events.ScrollEvent;
/** /**
* * Main handler for controls
* @author amaterasu
*/ */
public class ControlHandler { public class ControlHandler {
@ -204,7 +204,9 @@ public class ControlHandler {
public static final String FREECAM_RIGHT = "freecamRight"; public static final String FREECAM_RIGHT = "freecamRight";
public static final String FREECAM_MOUSE = "freecamMouse"; public static final String FREECAM_MOUSE = "freecamMouse";
/**
* The different buckets of inputs that the control handler be configured to scan for each frame
*/
public static enum ControlsState { public static enum ControlsState {
TITLE_PAGE, TITLE_PAGE,
TITLE_MENU, TITLE_MENU,
@ -215,14 +217,39 @@ public class ControlHandler {
NO_INPUT, NO_INPUT,
} }
//The bucket of inputs that the control handler is currently scanning for
ControlsState state = ControlsState.TITLE_MENU; ControlsState state = ControlsState.TITLE_MENU;
/**
* The list of control states that have the mouse visible and enabled
*/
static ControlsState[] mouseEnabledStates = new ControlsState[]{
ControlsState.TITLE_PAGE,
ControlsState.TITLE_MENU,
ControlsState.IN_GAME_MAIN_MENU,
ControlsState.INVENTORY,
};
//controls whether the mouse is visible or not
boolean mouseIsVisible = true; boolean mouseIsVisible = true;
//if set to true, opengl will try to capture the screen next frame
boolean shouldRecaptureScreen = false; boolean shouldRecaptureScreen = false;
//controls whether the camera is first or third person //controls whether the camera is first or third person
boolean cameraIsThirdPerson = false; boolean cameraIsThirdPerson = true;
//The list of window strings that would block main game controls
static String[] controlBlockingWindows = new String[]{
WindowStrings.LEVEL_EDTIOR_SIDE_PANEL,
WindowStrings.VOXEL_TYPE_SELECTION,
WindowStrings.WINDOW_CHARACTER,
WindowStrings.WINDOW_DEBUG,
WindowStrings.WINDOW_MENU_INGAME_MAIN,
WindowStrings.WINDOW_MENU_INVENTORY,
};
/* /*
@ -234,10 +261,10 @@ public class ControlHandler {
double ypos = 300; double ypos = 300;
double mouse_X_Buffer[] = new double[1]; double mouse_X_Buffer[] = new double[1];
double mouse_Y_Buffer[] = new double[1]; double mouse_Y_Buffer[] = new double[1];
boolean dragging = false; boolean dragging = false; //tracks whether the mouse is doing a drag input or not
//The map of data string -> control object
HashMap<String, Control> controls; HashMap<String, Control> controls;
List<Control> mainGameControlList = new LinkedList<Control>(); List<Control> mainGameControlList = new LinkedList<Control>();
@ -248,10 +275,17 @@ public class ControlHandler {
List<Control> alwaysOnDebugControlList = new LinkedList<Control>(); List<Control> alwaysOnDebugControlList = new LinkedList<Control>();
List<Control> freeCameraControlList = new LinkedList<Control>(); List<Control> freeCameraControlList = new LinkedList<Control>();
/**
* Constructor
*/
ControlHandler(){ ControlHandler(){
controls = new HashMap<String, Control>(); controls = new HashMap<String, Control>();
} }
/**
* Generates an example controls map
* @return the example controls map object
*/
public static ControlHandler generateExampleControlsMap(){ public static ControlHandler generateExampleControlsMap(){
ControlHandler handler = new ControlHandler(); ControlHandler handler = new ControlHandler();
/* /*
@ -355,11 +389,6 @@ public class ControlHandler {
framestep controls framestep controls
*/ */
handler.addControl(DEBUG_FRAMESTEP, new Control(ControlType.KEY, GLFW_KEY_P)); handler.addControl(DEBUG_FRAMESTEP, new Control(ControlType.KEY, GLFW_KEY_P));
/*
set state
*/
handler.setHandlerState(ControlsState.TITLE_MENU);
/* /*
* Free camera * Free camera
@ -393,7 +422,9 @@ public class ControlHandler {
/**
* Polls the currently set bucket of controls
*/
public void pollControls(){ public void pollControls(){
switch(state){ switch(state){
@ -446,7 +477,9 @@ public class ControlHandler {
Globals.scrollCallback.clear(); Globals.scrollCallback.clear();
} }
/**
* Attaches callbacks to each of the control objects
*/
public void setCallbacks(){ public void setCallbacks(){
setMainGameControls(); setMainGameControls();
setInGameDebugControls(); setInGameDebugControls();
@ -457,6 +490,10 @@ public class ControlHandler {
setFreecamControls(); setFreecamControls();
} }
/**
* Sets callbacks for the main game controls
*/
void setMainGameControls(){ void setMainGameControls(){
/* /*
Camera rotation Camera rotation
@ -909,7 +946,7 @@ public class ControlHandler {
mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU)); mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU));
controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU).setOnClick(new ControlMethod(){public void execute(){ controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU).setOnClick(new ControlMethod(){public void execute(){
// Globals.elementManager.registerWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, MenuGenerators.createInGameMainMenu()); // Globals.elementManager.registerWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, MenuGenerators.createInGameMainMenu());
// Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_MAIN_MENU); // Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
// Window mainMenuWindow = new Window(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); // Window mainMenuWindow = new Window(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
Window mainMenuInGame = MenuGeneratorsInGame.createInGameMainMenu(); Window mainMenuInGame = MenuGeneratorsInGame.createInGameMainMenu();
@ -917,8 +954,7 @@ public class ControlHandler {
Globals.elementManager.registerWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, mainMenuInGame); Globals.elementManager.registerWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, mainMenuInGame);
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), true); WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), true);
Globals.elementManager.focusFirstElement(); Globals.elementManager.focusFirstElement();
Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_MAIN_MENU); Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
Globals.controlHandler.showMouse();
//play sound effect //play sound effect
Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false);
}}); }});
@ -939,12 +975,13 @@ public class ControlHandler {
//make visible //make visible
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowUtils.getInventoryWindowID(inventory.getId())), true); WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowUtils.getInventoryWindowID(inventory.getId())), true);
//controls //controls
Globals.controlHandler.setHandlerState(ControlsState.INVENTORY); Globals.controlHandler.hintUpdateControlState(ControlsState.INVENTORY);
Globals.controlHandler.showMouse();
//play sound effect //play sound effect
Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false);
// //
Globals.openInventoriesCount++; Globals.openInventoriesCount++;
} else if(InventoryUtils.hasNaturalInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId())) != null){
Globals.elementManager.closeWindow(WindowUtils.getInventoryWindowID(InventoryUtils.getNaturalInventory(Globals.playerEntity).getId()));
} }
}}); }});
controls.get(INPUT_CODE_INVENTORY_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate); controls.get(INPUT_CODE_INVENTORY_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate);
@ -957,18 +994,19 @@ public class ControlHandler {
controls.get(INPUT_CODE_CHARACTER_OPEN).setOnClick(new ControlMethod(){public void execute(){ controls.get(INPUT_CODE_CHARACTER_OPEN).setOnClick(new ControlMethod(){public void execute(){
if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER) == null){ if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER) == null){
//create window //create window
Window mainMenuWindow = MenuGeneratorsInventory.createCharacterInventoryMenu(InventoryUtils.getEquipInventory(Globals.playerEntity)); Window characterInventoryMenu = MenuGeneratorsInventory.createCharacterInventoryMenu(InventoryUtils.getEquipInventory(Globals.playerEntity));
//register //register
Globals.elementManager.registerWindow(WindowStrings.WINDOW_CHARACTER, mainMenuWindow); Globals.elementManager.registerWindow(WindowStrings.WINDOW_CHARACTER, characterInventoryMenu);
//make visible //make visible
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER), true); WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER), true);
//controls //controls
Globals.controlHandler.setHandlerState(ControlsState.INVENTORY); Globals.controlHandler.hintUpdateControlState(ControlsState.INVENTORY);
Globals.controlHandler.showMouse();
//play sound effect //play sound effect
Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false); Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/openMenu.ogg", VirtualAudioSourceType.UI, false);
// //
Globals.openInventoriesCount++; Globals.openInventoriesCount++;
} else if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER) != null){
Globals.elementManager.closeWindow(WindowStrings.WINDOW_CHARACTER);
} }
}}); }});
controls.get(INPUT_CODE_CHARACTER_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate); controls.get(INPUT_CODE_CHARACTER_OPEN).setRepeatTimeout(0.5f * Main.targetFrameRate);
@ -1037,6 +1075,10 @@ public class ControlHandler {
} }
/**
* Sets the in game debug control callbacks
*/
void setInGameDebugControls(){ void setInGameDebugControls(){
mainGameDebugControlList.add(controls.get(DATA_STRING_INPUT_CODE_DEBUG_SPAWN_ITEM)); mainGameDebugControlList.add(controls.get(DATA_STRING_INPUT_CODE_DEBUG_SPAWN_ITEM));
controls.get(DATA_STRING_INPUT_CODE_DEBUG_SPAWN_ITEM).setOnPress(new ControlMethod(){public void execute(){ controls.get(DATA_STRING_INPUT_CODE_DEBUG_SPAWN_ITEM).setOnPress(new ControlMethod(){public void execute(){
@ -1050,6 +1092,10 @@ public class ControlHandler {
controls.get(DEBUG_FRAMESTEP).setOnRelease(new ControlMethod(){public void execute(){ controls.get(DEBUG_FRAMESTEP).setOnRelease(new ControlMethod(){public void execute(){
Main.setFramestep(1); Main.setFramestep(1);
}}); }});
controls.get(DEBUG_FRAMESTEP).setOnRepeat(new ControlMethod(){public void execute(){
Main.setFramestep(1);
}});
controls.get(DEBUG_FRAMESTEP).setRepeatTimeout(0.5f * Main.targetFrameRate);
// RenderingEngine.incrementOutputFramebuffer(); // RenderingEngine.incrementOutputFramebuffer();
} }
@ -1197,6 +1243,9 @@ public class ControlHandler {
} }
/**
* Sets the freecam control callbacks
*/
void setFreecamControls(){ void setFreecamControls(){
freeCameraControlList.add(controls.get(FREECAM_UP)); freeCameraControlList.add(controls.get(FREECAM_UP));
controls.get(FREECAM_UP).setOnRepeat(new ControlMethod(){public void execute(){ controls.get(FREECAM_UP).setOnRepeat(new ControlMethod(){public void execute(){
@ -1269,6 +1318,9 @@ public class ControlHandler {
} }
/**
* Sets the typing control callbacks
*/
void setTypingControls(){ void setTypingControls(){
String[] typeKeybinds = { String[] typeKeybinds = {
@ -1332,6 +1384,9 @@ public class ControlHandler {
} }
} }
/**
* Sets the inventory control callbacks
*/
void setInventoryControls(){ void setInventoryControls(){
/* /*
Close inventory Close inventory
@ -1380,6 +1435,10 @@ public class ControlHandler {
} }
/**
* Checks a list of controls to see if the corresponding key/mouse event is firing this frame
* @param controls The list of controls to check
*/
public void runHandlers(List<Control> controls){ public void runHandlers(List<Control> controls){
//construct mouse event //construct mouse event
@ -1461,6 +1520,55 @@ public class ControlHandler {
} }
} }
/**
* Checks if any menus are open that would intercept player input (main menu, inventory, debug, etc)
* @return true if such a menu is open, false otherwise
*/
private boolean hasControlBlockingMenuOpen(){
boolean rVal = false;
//check main ui framework windows
for(String windowString : controlBlockingWindows){
rVal = rVal || WindowUtils.windowIsOpen(windowString);
}
//check imgui windows
rVal = rVal || Globals.renderingEngine.getImGuiPipeline().shouldCaptureControls();
return rVal;
}
/**
* Hints to the engine that it should update the control state
* The provided control state will be overwritten if, for instance,
* there is a menu open that demands mouse input and you are trying
* to tell the engine to convert to immediate player control
* @param desiredState The desired control state
*/
public void hintUpdateControlState(ControlsState desiredState){
ControlsState properState = desiredState;
//correct for freecam or actual ingame control based on value of getTrackPlayerEntity
if(desiredState == ControlsState.IN_GAME_FREE_CAMERA && Globals.cameraHandler.getTrackPlayerEntity()){
properState = ControlsState.MAIN_GAME;
}
if(desiredState == ControlsState.MAIN_GAME && !Globals.cameraHandler.getTrackPlayerEntity()){
properState = ControlsState.IN_GAME_FREE_CAMERA;
}
//set to menu state if a menu is open, otherwise use the hinted control scheme
if(hasControlBlockingMenuOpen()){
setHandlerState(ControlsState.IN_GAME_MAIN_MENU);
} else {
setHandlerState(properState);
}
//checks if the current handler state should have mouse enabled or not
if(Arrays.binarySearch(mouseEnabledStates,getHandlerState()) >= 0){
showMouse();
} else {
hideMouse();
}
}
/**
* Transfers the mouse position from the glfw buffer to variables stored inside the control handler
*/
void getMousePositionInBuffer(){ void getMousePositionInBuffer(){
//only if not headless, gather position //only if not headless, gather position
if(!Globals.HEADLESS){ if(!Globals.HEADLESS){
@ -1470,6 +1578,10 @@ public class ControlHandler {
} }
} }
/**
* Checks if the mouse button 1 is currently pressed
* @return true if pressed, false otherwise
*/
boolean getButton1Raw(){ boolean getButton1Raw(){
if(Globals.HEADLESS){ if(Globals.HEADLESS){
return false; return false;
@ -1478,6 +1590,10 @@ public class ControlHandler {
} }
} }
/**
* Checks if the mouse button 2 is currently pressed
* @return true if pressed, false otherwise
*/
boolean getButton2Raw(){ boolean getButton2Raw(){
if(Globals.HEADLESS){ if(Globals.HEADLESS){
return false; return false;
@ -1502,33 +1618,51 @@ public class ControlHandler {
controls.put(controlName, c); controls.put(controlName, c);
} }
public void setHandlerState(ControlsState state){ /**
* Sets the state of the controls handler
* @param state the state
*/
private void setHandlerState(ControlsState state){
this.state = state; this.state = state;
} }
/**
* Gets the current state of the controls handler
* @return the state
*/
public ControlsState getHandlerState(){ public ControlsState getHandlerState(){
return state; return state;
} }
public ControlsState getState(){ /**
return state; * Hides the mouse
} */
public void hideMouse(){ public void hideMouse(){
glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
mouseIsVisible = false; mouseIsVisible = false;
} }
/**
* Shows the mouse
*/
public void showMouse(){ public void showMouse(){
glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
mouseIsVisible = true; mouseIsVisible = true;
} }
/**
* Gets whether the mouse is visible or not
* @return true if visible, false otherwise
*/
public boolean isMouseVisible(){ public boolean isMouseVisible(){
return mouseIsVisible; return mouseIsVisible;
} }
/**
* Gets the mouse position as a vector2f
* @return The vector containing the mouse position
*/
public Vector2f getMousePosition(){ public Vector2f getMousePosition(){
double posX[] = new double[1]; double posX[] = new double[1];
double posY[] = new double[1]; double posY[] = new double[1];
@ -1537,6 +1671,11 @@ public class ControlHandler {
return rVal; return rVal;
} }
/**
* Converts a keycode to a string containing a code related to the keycode (ie "A" for 65, "Escape" for 256, etc)
* @param code The keycode
* @return The corresponding string code
*/
public static String convertKeycodeToName(int code){ public static String convertKeycodeToName(int code){
String rVal = ""; String rVal = "";
switch(code){ switch(code){
@ -1667,10 +1806,18 @@ public class ControlHandler {
return rVal; return rVal;
} }
/**
* Sets whether the engine should try to recapture window focus next frame or not
* @param shouldRecapture true if should try to recapture next frame, false otherwise
*/
public void setRecapture(boolean shouldRecapture){ public void setRecapture(boolean shouldRecapture){
this.shouldRecaptureScreen = shouldRecapture; this.shouldRecaptureScreen = shouldRecapture;
} }
/**
* Returns whether the engine should try to recapture window focus next frame or not
* @return true if it should try to recapture, false otherwise
*/
public boolean shouldRecapture(){ public boolean shouldRecapture(){
return this.shouldRecaptureScreen; return this.shouldRecaptureScreen;
} }

View File

@ -24,6 +24,7 @@ import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionWorldData; import electrosphere.collision.CollisionWorldData;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.controls.CameraHandler; import electrosphere.controls.CameraHandler;
import electrosphere.controls.ControlCallback; import electrosphere.controls.ControlCallback;
import electrosphere.controls.ControlHandler; import electrosphere.controls.ControlHandler;
@ -37,7 +38,6 @@ import electrosphere.engine.profiler.Profiler;
import electrosphere.engine.time.Timekeeper; import electrosphere.engine.time.Timekeeper;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.Scene; import electrosphere.entity.Scene;
import electrosphere.entity.types.hitbox.HitboxManager;
import electrosphere.game.config.UserSettings; import electrosphere.game.config.UserSettings;
import electrosphere.game.data.voxel.VoxelType; import electrosphere.game.data.voxel.VoxelType;
import electrosphere.game.server.structure.virtual.StructureManager; import electrosphere.game.server.structure.virtual.StructureManager;
@ -84,6 +84,11 @@ import electrosphere.util.FileUtils;
* @author amaterasu * @author amaterasu
*/ */
public class Globals { public class Globals {
//
//Process data
//
public static String javaPID;
// //
//Top level user settings object //Top level user settings object
@ -133,6 +138,7 @@ public class Globals {
//Client connection to server //Client connection to server
// //
public static ClientNetworking clientConnection; public static ClientNetworking clientConnection;
public static boolean RUN_DEMO = false;
public static boolean RUN_CLIENT = true; public static boolean RUN_CLIENT = true;
public static int clientCharacterID; public static int clientCharacterID;
@ -302,9 +308,6 @@ public class Globals {
//script engine //script engine
public static ScriptEngine scriptEngine; public static ScriptEngine scriptEngine;
//manages hitboxes
public static HitboxManager clientHitboxManager;
//client scene management //client scene management
public static Scene clientScene; public static Scene clientScene;
public static ClientSceneWrapper clientSceneWrapper; public static ClientSceneWrapper clientSceneWrapper;
@ -442,8 +445,6 @@ public class Globals {
//script engine //script engine
scriptEngine = new ScriptEngine(); scriptEngine = new ScriptEngine();
scriptEngine.init(); scriptEngine.init();
//hitbox manager
clientHitboxManager = new HitboxManager();
//ai manager //ai manager
aiManager = new AIManager(); aiManager = new AIManager();
//realm & data cell manager //realm & data cell manager
@ -520,11 +521,13 @@ public class Globals {
//init fluid shader program //init fluid shader program
FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid2/fluid2.vs", "/Shaders/fluid2/fluid2.fs"); FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid2/fluid2.vs", "/Shaders/fluid2/fluid2.fs");
//init models //init models
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_1.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_1.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_grey.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_grey.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcylinder.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitcylinder.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcapsule.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx"); assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx");
imagePlaneModelID = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/plane/plane.vs", "Shaders/plane/plane.fs")); imagePlaneModelID = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/plane/plane.vs", "Shaders/plane/plane.fs"));

View File

@ -11,6 +11,7 @@ import org.ode4j.ode.OdeHelper;
import electrosphere.audio.AudioEngine; import electrosphere.audio.AudioEngine;
import electrosphere.audio.VirtualAudioSourceManager; import electrosphere.audio.VirtualAudioSourceManager;
import electrosphere.controls.ControlHandler; import electrosphere.controls.ControlHandler;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.cli.CLIParser; import electrosphere.engine.cli.CLIParser;
import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.engine.loadingthreads.LoadingThread;
import electrosphere.engine.time.Timekeeper; import electrosphere.engine.time.Timekeeper;
@ -22,7 +23,9 @@ import electrosphere.renderer.RenderingEngine;
import electrosphere.server.simulation.MacroSimulation; import electrosphere.server.simulation.MacroSimulation;
/**
* The main class
*/
public class Main { public class Main {
@ -63,8 +66,8 @@ public class Main {
//initialize logging interfaces //initialize logging interfaces
LoggerInterface.initLoggers(); LoggerInterface.initLoggers();
//gets pid of engine //gets java pid of engine
System.out.println(ManagementFactory.getRuntimeMXBean().getName()); Globals.javaPID = ManagementFactory.getRuntimeMXBean().getName();
//load user settings //load user settings
UserSettings.loadUserSettings(); UserSettings.loadUserSettings();
@ -140,6 +143,9 @@ public class Main {
Globals.initDefaultGraphicalResources(); Globals.initDefaultGraphicalResources();
ImGuiWindowMacros.initImGuiWindows(); ImGuiWindowMacros.initImGuiWindows();
//inits the controls state of the control handler
Globals.controlHandler.hintUpdateControlState(ControlsState.TITLE_MENU);
//start initial asset loading //start initial asset loading
new Thread(Globals.initialAssetLoadingThread).start(); new Thread(Globals.initialAssetLoadingThread).start();
} }
@ -186,7 +192,11 @@ public class Main {
//fire off a loading thread for the title menus/screen //fire off a loading thread for the title menus/screen
LoggerInterface.loggerStartup.INFO("Fire off loading thread"); LoggerInterface.loggerStartup.INFO("Fire off loading thread");
if(Globals.RUN_CLIENT){ if(Globals.RUN_DEMO){
LoadingThread serverThread = new LoadingThread(LoadingThread.LOAD_DEMO_MENU);
Globals.loadingThreadsList.add(serverThread);
serverThread.start();
} else if(Globals.RUN_CLIENT){
LoadingThread serverThread = new LoadingThread(LoadingThread.LOAD_TITLE_MENU); LoadingThread serverThread = new LoadingThread(LoadingThread.LOAD_TITLE_MENU);
Globals.loadingThreadsList.add(serverThread); Globals.loadingThreadsList.add(serverThread);
serverThread.start(); serverThread.start();
@ -217,10 +227,11 @@ public class Main {
*/ */
public static void mainLoop(long maxFrames){ public static void mainLoop(long maxFrames){
double functionTrackTimeStart = 0;
//main loop //main loop
while (running) { while (running) {
try {
Globals.profiler.beginRootCpuSample("frame"); Globals.profiler.beginRootCpuSample("frame");
LoggerInterface.loggerEngine.DEBUG("Begin Main Loop Frame"); LoggerInterface.loggerEngine.DEBUG("Begin Main Loop Frame");
@ -396,6 +407,15 @@ public class Main {
LoggerInterface.loggerEngine.DEBUG("End Main Loop Frame"); LoggerInterface.loggerEngine.DEBUG("End Main Loop Frame");
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} catch (NullPointerException ex){
LoggerInterface.loggerEngine.ERROR("Main frame uncaught NPE", ex);
//after a while, jvm will stop reporting stack traces with errors
//need to explicitly kill the vm if you want to see the stack trace
if(Globals.ENGINE_DEBUG){
System.exit(1);
}
}
} }
LoggerInterface.loggerEngine.WARNING("ENGINE SHUTDOWN"); LoggerInterface.loggerEngine.WARNING("ENGINE SHUTDOWN");

View File

@ -239,13 +239,21 @@ public class AssetManager {
// //
//Pose Models //Pose Models
// //
/**
* Adds a pose model to the list of pose models to load
* @param path The path to load
*/
public void addPoseModelPathToQueue(String path){ public void addPoseModelPathToQueue(String path){
if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){ if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){
poseModelsInQueue.add(path); poseModelsInQueue.add(path);
} }
} }
/**
* Fetches a pose model
* @param path The path to fetch
* @return The pose model if it exists, null otherwise
*/
public PoseModel fetchPoseModel(String path){ public PoseModel fetchPoseModel(String path){
PoseModel rVal = null; PoseModel rVal = null;
if(poseModelsLoadedIntoMemory.containsKey(path)){ if(poseModelsLoadedIntoMemory.containsKey(path)){

View File

@ -209,7 +209,7 @@ public class ArenaLoading {
// public void simulate(){ // public void simulate(){
// if(i < 100){ // if(i < 100){
// i++; // i++;
// CollisionObjUtils.getCollidable(sword).addImpulse(new Impulse(new Vector3d(0,0,1), new Vector3d(-1,0,0), 0.001, Collidable.TYPE_CREATURE)); // CollisionObjUtils.getCollidable(sword).addImpulse(new Impulse(MathUtils.ORIGIN_VECTOR, new Vector3d(-1,0,0), 0.001, Collidable.TYPE_CREATURE));
// EntityUtils.getPosition(sword).set(1,0.2f,2); // EntityUtils.getPosition(sword).set(1,0.2f,2);
// } // }
// }}); // }});

View File

@ -38,6 +38,7 @@ import electrosphere.net.NetUtils;
import electrosphere.net.client.ClientNetworking; import electrosphere.net.client.ClientNetworking;
import electrosphere.renderer.ui.elements.Window; import electrosphere.renderer.ui.elements.Window;
import electrosphere.server.datacell.EntityDataCellMapper; import electrosphere.server.datacell.EntityDataCellMapper;
import electrosphere.util.MathUtils;
public class ClientLoading { public class ClientLoading {
@ -55,7 +56,7 @@ public class ClientLoading {
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
loadingWindow.setVisible(true); loadingWindow.setVisible(true);
//disable menu input //disable menu input
Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
//initialize the client thread (client) //initialize the client thread (client)
initClientThread(); initClientThread();
//while we don't know what races are playable, wait //while we don't know what races are playable, wait
@ -77,7 +78,7 @@ public class ClientLoading {
//log //log
LoggerInterface.loggerEngine.INFO("[Client]Finished loading character creation menu"); LoggerInterface.loggerEngine.INFO("[Client]Finished loading character creation menu");
//set menu controls again //set menu controls again
Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.TITLE_MENU); Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.TITLE_MENU);
} }
@ -87,7 +88,7 @@ public class ClientLoading {
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
loadingWindow.setVisible(true); loadingWindow.setVisible(true);
//disable menu input //disable menu input
Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
//initialize the "real" objects simulation //initialize the "real" objects simulation
initClientSimulation(); initClientSimulation();
//init foliage manager //init foliage manager
@ -104,8 +105,6 @@ public class ClientLoading {
setSimulationsToReady(); setSimulationsToReady();
//init culling manager and other graphics-focused non-simulation items //init culling manager and other graphics-focused non-simulation items
initEntityCullingManager(); initEntityCullingManager();
//hide cursor
Globals.controlHandler.hideMouse();
//make loading window disappear //make loading window disappear
loadingWindow.setVisible(false); loadingWindow.setVisible(false);
//recapture screen //recapture screen
@ -119,7 +118,7 @@ public class ClientLoading {
Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game");
//set controls state //set controls state
Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.MAIN_GAME);
} }
@ -177,9 +176,9 @@ public class ClientLoading {
*/ */
if(Globals.controlHandler.cameraIsThirdPerson()){ if(Globals.controlHandler.cameraIsThirdPerson()){
Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), MathUtils.getOriginVectorf());
} else { } else {
Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(1,0,1), MathUtils.getOriginVectorf());
} }

View File

@ -0,0 +1,31 @@
package electrosphere.engine.loadingthreads;
import electrosphere.engine.Globals;
import electrosphere.menu.WindowStrings;
import electrosphere.menu.WindowUtils;
import electrosphere.menu.mainmenu.MenuGeneratorsDemo;
import electrosphere.renderer.ui.elements.Window;
/**
* Loading routines for the demo version of the game
*/
public class DemoLoading {
//the name of the save for the demo version of the game
public static final String DEMO_LEVEL_PATH = "demo";
/**
* Loads the title menu elements for the demo version of the engine
*/
public static void loadDemoMenu(){
Globals.currentSaveName = DEMO_LEVEL_PATH;
WindowUtils.replaceMainMenuContents(MenuGeneratorsDemo.createTitleMenu());
Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING);
WindowUtils.recursiveSetVisible(loadingWindow,false);
WindowUtils.focusWindow(WindowStrings.WINDOW_MENU_MAIN);
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), true);
}
}

View File

@ -3,24 +3,30 @@ package electrosphere.engine.loadingthreads;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
/** /**
* * Threads for loading engine state
* @author amaterasu
*/ */
public class LoadingThread extends Thread { public class LoadingThread extends Thread {
public static final int LOAD_TITLE_MENU = 0; public static final int LOAD_TITLE_MENU = 0; //loads the main game title menu
public static final int LOAD_MAIN_GAME = 1; public static final int LOAD_MAIN_GAME = 1; //loads the main game
public static final int LOAD_ARENA = 2; public static final int LOAD_ARENA = 2; //loads the arena
public static final int LOAD_CHARACTER_SERVER = 3; public static final int LOAD_CHARACTER_SERVER = 3; //loads the character creation menus on the client
public static final int LOAD_CLIENT_WORLD = 4; public static final int LOAD_CLIENT_WORLD = 4; //loads the client world
public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; //loads a random singleplayer debug world
public static final int LOAD_LEVEL_EDITOR = 6; public static final int LOAD_LEVEL_EDITOR = 6; //loads the level editor
public static final int LOAD_LEVEL = 7; public static final int LOAD_LEVEL = 7; //loads a level
public static final int LOAD_DEMO_MENU = 8; //loads the main menu ui for the demo version of the client
//the type of loading to do
int threadType; int threadType;
//a lock to track when the loading had completed and block until then
Semaphore lock; Semaphore lock;
/**
* Creates the work for a loading thread
* @param type The type of thread
*/
public LoadingThread(int type){ public LoadingThread(int type){
threadType = type; threadType = type;
lock = new Semaphore(1); lock = new Semaphore(1);
@ -52,7 +58,7 @@ public class LoadingThread extends Thread {
} break; } break;
//intended to act like you went through the steps of setting up a vanilla settings SP world //intended to act like you went through the steps of setting up a vanilla settings SP world
case LOAD_DEBUG_RANDOM_SP_WORLD: { case LOAD_DEBUG_RANDOM_SP_WORLD: {
DebugSPWorldLoading.loadDebugSPWorld(); DebugSPWorldLoading.loadDebugSPWorld();
} break; } break;
@ -66,12 +72,20 @@ public class LoadingThread extends Thread {
case LOAD_LEVEL: { case LOAD_LEVEL: {
LevelLoading.loadLevel(); LevelLoading.loadLevel();
} break; } break;
//the demo menu ui
case LOAD_DEMO_MENU: {
DemoLoading.loadDemoMenu();
} break;
} }
lock.release(); lock.release();
} }
/**
* Checks if the thread has finished loading
* @return true if it has finished, false otherwise
*/
public boolean isDone(){ public boolean isDone(){
boolean rVal = lock.tryAcquire(); boolean rVal = lock.tryAcquire();
if(rVal == true){ if(rVal == true){

View File

@ -198,8 +198,15 @@ public class LoadingUtils {
} }
/**
* Loads graphics assets necessary for the client of the game engine. This should be stuff that is used essentially universally (ie textures for debugging).
*/
static void initGameGraphicalEntities(){ static void initGameGraphicalEntities(){
Globals.assetManager.addTexturePathtoQueue("Textures/transparent_red.png");
Globals.assetManager.addTexturePathtoQueue("Textures/transparent_blue.png");
Globals.assetManager.addTexturePathtoQueue("Textures/transparent_grey.png");
float skyR = 100; float skyR = 100;
float skyG = 150; float skyG = 150;

View File

@ -36,6 +36,9 @@ public class Timekeeper {
//the maximum number of simulation frames that can happen in a row before the main loop immediately skips more //the maximum number of simulation frames that can happen in a row before the main loop immediately skips more
public static final int SIM_FRAME_HARDCAP = 3; public static final int SIM_FRAME_HARDCAP = 3;
//step interval time size (for physics)
public static final float ENGINE_STEP_SIZE = 0.01f;
@ -135,4 +138,13 @@ public class Timekeeper {
return currentTime; return currentTime;
} }
/**
* The number of frames we're simulating this cycle
* @return The number of frames we're simulating this cycle
*/
public long getDeltaFrames(){
//this should always return 1. We're always simulating 1 frame per run of the loop in main
return 1;
}
} }

View File

@ -1,18 +1,17 @@
package electrosphere.entity; package electrosphere.entity;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.renderer.actor.ActorUtils; import electrosphere.renderer.actor.ActorUtils;
import electrosphere.renderer.actor.instance.InstancedActor;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.EntityLookupUtils; import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActorUtils;
public class EntityCreationUtils { public class EntityCreationUtils {
@ -82,12 +81,13 @@ public class EntityCreationUtils {
* @param modelPath The model path for the model to back the pose actor * @param modelPath The model path for the model to back the pose actor
*/ */
public static void makeEntityPoseable(Entity entity, String modelPath){ public static void makeEntityPoseable(Entity entity, String modelPath){
entity.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath)); entity.putData(EntityDataStrings.POSE_ACTOR, PoseActorUtils.createPoseActorFromModelPath(modelPath));
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity()); entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); entity.putData(EntityDataStrings.DATA_STRING_DRAW, true);
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
ServerEntityTagUtils.attachTagToEntity(entity, EntityTags.POSEABLE);
} }
@ -103,7 +103,6 @@ public class EntityCreationUtils {
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); entity.putData(EntityDataStrings.DATA_STRING_DRAW, true);
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
Globals.clientScene.registerEntity(entity);
Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE); Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE);
} }
@ -119,7 +118,6 @@ public class EntityCreationUtils {
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); entity.putData(EntityDataStrings.DATA_STRING_DRAW, true);
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
Globals.clientScene.registerEntity(entity);
Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE); Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE);
} }

View File

@ -256,7 +256,6 @@ public class EntityDataStrings {
/* /*
Equip state Equip state
*/ */
public static final String EQUIP_STATE = "equipState";
public static final String TREE_CLIENTEQUIPSTATE = "treeClientEquipState"; public static final String TREE_CLIENTEQUIPSTATE = "treeClientEquipState";
public static final String EQUIP_INVENTORY = "equipInventory"; public static final String EQUIP_INVENTORY = "equipInventory";
public static final String TREE_SERVEREQUIPSTATE = "treeServerEquipState"; public static final String TREE_SERVEREQUIPSTATE = "treeServerEquipState";
@ -282,6 +281,11 @@ public class EntityDataStrings {
* Pose actor * Pose actor
*/ */
public static final String POSE_ACTOR = "poseActor"; public static final String POSE_ACTOR = "poseActor";
/**
* Server-specific btrees
*/
public static final String TREE_SERVERPLAYERVIEWDIR = "treeServerPlayerViewDir";
/* /*
Entity categories Entity categories

View File

@ -19,6 +19,7 @@ public class EntityTags {
public static final String DRAWABLE = "drawable"; //is it drawable public static final String DRAWABLE = "drawable"; //is it drawable
public static final String DRAW_INSTANCED = "drawInstanced"; //if it's instanced, but not necessarily managed by a service (ie a tree branch) public static final String DRAW_INSTANCED = "drawInstanced"; //if it's instanced, but not necessarily managed by a service (ie a tree branch)
public static final String DRAW_INSTANCED_MANAGED = "drawInstancedManaged"; //if it's managed by a service (ie foliage manager) public static final String DRAW_INSTANCED_MANAGED = "drawInstancedManaged"; //if it's managed by a service (ie foliage manager)
public static final String POSEABLE = "poseable"; //is it poseable on server
public static final String LIGHT = "light"; public static final String LIGHT = "light";
public static final String ITEM = "item"; public static final String ITEM = "item";
public static final String GRAVITY = "gravity"; public static final String GRAVITY = "gravity";

View File

@ -1,32 +1,21 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package electrosphere.entity; package electrosphere.entity;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorUtils; import electrosphere.renderer.actor.ActorUtils;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.datacell.utils.EntityLookupUtils; import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseActorUtils;
import electrosphere.util.MathUtils;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
/** /**
* * Utilties for dealing with entities
* @author amaterasu
*/ */
public class EntityUtils { public class EntityUtils {
@ -74,7 +63,7 @@ public class EntityUtils {
Entity rVal = new Entity(); Entity rVal = new Entity();
rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(modelPath)); rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(modelPath));
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().rotateAxis(0, new Vector3d(1,0,0))); rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().rotateAxis(0, MathUtils.getOriginVector()));
rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
rVal.putData(EntityDataStrings.DRAW_SOLID_PASS, true); rVal.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
@ -90,7 +79,7 @@ public class EntityUtils {
*/ */
protected static Entity spawnPoseableEntity(String modelPath){ protected static Entity spawnPoseableEntity(String modelPath){
Entity rVal = new Entity(); Entity rVal = new Entity();
rVal.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath)); rVal.putData(EntityDataStrings.POSE_ACTOR, PoseActorUtils.createPoseActorFromModelPath(modelPath));
// rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath); // rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity()); rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());
@ -104,7 +93,7 @@ public class EntityUtils {
Entity rVal = new Entity(); Entity rVal = new Entity();
rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorFromModelPath(modelPath)); rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorFromModelPath(modelPath));
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().rotateAxis(0, new Vector3d(1,0,0))); rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().rotateAxis(0, MathUtils.getOriginVector()));
rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
rVal.putData(EntityDataStrings.DATA_STRING_UI_ELEMENT, true); rVal.putData(EntityDataStrings.DATA_STRING_UI_ELEMENT, true);
Globals.clientScene.registerEntity(rVal); Globals.clientScene.registerEntity(rVal);

View File

@ -3,44 +3,31 @@ package electrosphere.entity.state.attack;
import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.equip.ClientEquipState; import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.rotator.RotatorTree; import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.hitbox.HitboxUtils;
import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.projectile.ProjectileUtils;
import electrosphere.game.data.creature.type.attack.AttackMove; import electrosphere.game.data.creature.type.attack.AttackMove;
import electrosphere.game.data.creature.type.equip.EquipPoint;
import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum; import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.anim.Animation;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f;
@SynchronizedBehaviorTree(name = "clientAttackTree", isServer = false, correspondingTree="serverAttackTree") @SynchronizedBehaviorTree(name = "clientAttackTree", isServer = false, correspondingTree="serverAttackTree")
/** /**
@ -108,8 +95,8 @@ public class ClientAttackTree implements BehaviorTree {
String attackingPoint = null; String attackingPoint = null;
public ClientAttackTree(Entity e){ public ClientAttackTree(Entity e){
state = AttackTreeState.IDLE; setState(AttackTreeState.IDLE);
driftState = AttackTreeDriftState.NO_DRIFT; setDriftState(AttackTreeDriftState.NO_DRIFT);
parent = e; parent = e;
} }
@ -123,6 +110,9 @@ public class ClientAttackTree implements BehaviorTree {
return state; return state;
} }
/**
* Starts an attack
*/
public void start(){ public void start(){
currentMoveCanHold = false; currentMoveCanHold = false;
currentMoveHasWindup = false; currentMoveHasWindup = false;
@ -135,8 +125,8 @@ public class ClientAttackTree implements BehaviorTree {
String attackType = getAttackType(); String attackType = getAttackType();
//if we can attack, setup doing so //if we can attack, setup doing so
if(canAttack(attackType)){ if(canAttack(attackType)){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType); setAttackMoveTypeActive(attackType);
currentMoveset = (List<AttackMove>)parent.getData(attackType); currentMoveset = getMoveset(attackType);
if(currentMoveset != null){ if(currentMoveset != null){
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructstartAttackMessage()); Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructstartAttackMessage());
} }
@ -148,23 +138,30 @@ public class ClientAttackTree implements BehaviorTree {
} }
public void interrupt(){ public void interrupt(){
state = AttackTreeState.IDLE; setState(AttackTreeState.IDLE);
} }
public void slowdown(){ public void slowdown(){
state = AttackTreeState.COOLDOWN; setState(AttackTreeState.COOLDOWN);
} }
@Override @Override
public void simulate(float deltaTime){ public void simulate(float deltaTime){
frameCurrent = frameCurrent + (float)Globals.timekeeper.getSimFrameTime(); frameCurrent = frameCurrent + (float)Globals.timekeeper.getDeltaFrames();
float velocity = CreatureUtils.getVelocity(parent);
Actor entityActor = EntityUtils.getActor(parent); Actor entityActor = EntityUtils.getActor(parent);
Vector3d position = EntityUtils.getPosition(parent);
Vector3d movementVector = CreatureUtils.getFacingVector(parent); Vector3d movementVector = CreatureUtils.getFacingVector(parent);
//
//synchronize move from server //synchronize move from server
if(this.currentMove == null && this.currentMoveId != null){ if(this.currentMoveset == null){
this.currentMoveset = getMoveset(getAttackType());
}
if(
this.currentMoveset != null &&
(this.currentMove == null && this.currentMoveId != null)
||
(this.currentMove != null && this.currentMove.getAttackMoveId() != this.currentMoveId)
){
for(AttackMove move : currentMoveset){ for(AttackMove move : currentMoveset){
if(move.getAttackMoveId().equals(currentMoveId)){ if(move.getAttackMoveId().equals(currentMoveId)){
currentMove = move; currentMove = move;
@ -172,6 +169,7 @@ public class ClientAttackTree implements BehaviorTree {
} }
} }
//
//parse attached network messages //parse attached network messages
for(EntityMessage message : networkMessageQueue){ for(EntityMessage message : networkMessageQueue){
networkMessageQueue.remove(message); networkMessageQueue.remove(message);
@ -183,23 +181,23 @@ public class ClientAttackTree implements BehaviorTree {
lastUpdateTime = updateTime; lastUpdateTime = updateTime;
switch(message.gettreeState()){ switch(message.gettreeState()){
case 0: case 0:
state = AttackTreeState.WINDUP; setState(AttackTreeState.WINDUP);
frameCurrent = 0; frameCurrent = 0;
// System.out.println("Set state STARTUP"); // System.out.println("Set state STARTUP");
break; break;
case 1: case 1:
frameCurrent = currentMove.getWindupFrames()+1; frameCurrent = currentMove.getWindupFrames()+1;
state = AttackTreeState.ATTACK; setState(AttackTreeState.ATTACK);
// System.out.println("Set state MOVE"); // System.out.println("Set state MOVE");
break; break;
case 2: case 2:
frameCurrent = currentMove.getWindupFrames()+currentMove.getAttackFrames()+1; frameCurrent = currentMove.getWindupFrames()+currentMove.getAttackFrames()+1;
state = AttackTreeState.COOLDOWN; setState(AttackTreeState.COOLDOWN);
// System.out.println("Set state SLOWDOWN"); // System.out.println("Set state SLOWDOWN");
break; break;
case 3: case 3:
frameCurrent = 60; frameCurrent = 60;
state = AttackTreeState.IDLE; setState(AttackTreeState.IDLE);
// System.out.println("Set state IDLE"); // System.out.println("Set state IDLE");
break; break;
} }
@ -207,17 +205,7 @@ public class ClientAttackTree implements BehaviorTree {
EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ())); CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
break; break;
case ATTACHENTITYTOENTITY: default:
case CREATE:
case DESTROY:
case MOVE:
case MOVEUPDATE:
case SETBEHAVIORTREE:
case SETFACING:
case SETPOSITION:
case SETPROPERTY:
case KILL:
case SPAWNCREATURE:
//silently ignore //silently ignore
break; break;
} }
@ -230,30 +218,26 @@ public class ClientAttackTree implements BehaviorTree {
//calculate the vector of movement //calculate the vector of movement
CollisionObjUtils.getCollidable(parent).addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), currentMove.getDriftGoal() * Globals.timekeeper.getSimFrameTime(), "movement")); CollisionObjUtils.getCollidable(parent).addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), currentMove.getDriftGoal() * Globals.timekeeper.getSimFrameTime(), "movement"));
if(frameCurrent > currentMove.getDriftFrameEnd()){ if(frameCurrent > currentMove.getDriftFrameEnd()){
driftState = AttackTreeDriftState.NO_DRIFT; setDriftState(AttackTreeDriftState.NO_DRIFT);
} }
} }
break; break;
case NO_DRIFT: case NO_DRIFT:
if(currentMove != null){ if(currentMove != null){
if(frameCurrent > currentMove.getDriftFrameStart() && frameCurrent < currentMove.getDriftFrameEnd()){ if(frameCurrent > currentMove.getDriftFrameStart() && frameCurrent < currentMove.getDriftFrameEnd()){
driftState = AttackTreeDriftState.DRIFT; setDriftState(AttackTreeDriftState.DRIFT);
} }
} }
break; break;
} }
// if(state != AttackTreeState.IDLE){
// System.out.println(frameCurrent);
// }
//state machine //state machine
switch(state){ switch(state){
case WINDUP: case WINDUP: {
if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){ if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){
RotatorTree.getClientRotatorTree(parent).setActive(true); RotatorTree.getClientRotatorTree(parent).setActive(true);
} }
if(currentMove != null && frameCurrent > currentMove.getWindupFrames()){ if(currentMove != null){
if(entityActor != null){ if(entityActor != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getWindupAnimationName())){ if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getWindupAnimationName())){
entityActor.playAnimation(currentMove.getWindupAnimationName(),1); entityActor.playAnimation(currentMove.getWindupAnimationName(),1);
@ -261,98 +245,54 @@ public class ClientAttackTree implements BehaviorTree {
} }
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonWindup().getName()); FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonWindup().getName());
} }
if(currentMoveCanHold && stillHold){ }
state = AttackTreeState.HOLD; } break;
} else { case HOLD: {
state = AttackTreeState.ATTACK; if(entityActor != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getHoldAnimationName())){
entityActor.playAnimation(currentMove.getHoldAnimationName(),1);
entityActor.incrementAnimationTime(0.0001);
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonHold().getName());
}
} break;
case ATTACK: {
if(entityActor != null && currentMove != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getAttackAnimationName())){
entityActor.playAnimation(currentMove.getAttackAnimationName(),1);
entityActor.incrementAnimationTime(0.0001);
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonAttack().getName());
}
//activate hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(HitboxCollectionState.hasHitboxState(currentAttached)){
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
currentState.setActive(true);
} }
} }
break; } break;
case HOLD: case COOLDOWN: {
if(entityActor != null){ //deactive hitboxes
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationName)){ List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
entityActor.playAnimation(animationName,1); for(Entity currentAttached : attachedEntities){
entityActor.incrementAnimationTime(0.0001); if(HitboxCollectionState.hasHitboxState(currentAttached)){
} HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonHold().getName()); currentState.setActive(false);
}
if(!stillHold){
state = AttackTreeState.ATTACK;
}
break;
case ATTACK:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(true);
}
}
}
}
if(firesProjectile && projectileToFire != null){
//spawn projectile
//TODO: solve spawnPosition, initialVector
Vector3d spawnPosition = new Vector3d(0,0,0);
Quaterniond arrowRotation = new Quaterniond();
String targetBone = null;
ClientEquipState equipState = ClientEquipState.getEquipState(parent);
EquipPoint weaponPoint = null;
if((weaponPoint = equipState.getEquipPoint(attackingPoint)) != null){
targetBone = weaponPoint.getBone();
}
if(targetBone != null){
Actor parentActor = EntityUtils.getActor(parent);
//transform bone space
spawnPosition = new Vector3d(parentActor.getBonePosition(targetBone));
spawnPosition = spawnPosition.mul(((Vector3f)EntityUtils.getScale(parent)));
Quaterniond rotation = EntityUtils.getRotation(parent);
spawnPosition = spawnPosition.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w));
//transform worldspace
spawnPosition.add(new Vector3d(EntityUtils.getPosition(parent)));
//set
// EntityUtils.getPosition(currentEntity).set(position);
//set rotation
// Quaternionf rotation = parentActor.getBoneRotation(targetBone);
// EntityUtils.getRotation(currentEntity).set(rotation).normalize();
// Vector3d facingAngle = CreatureUtils.getFacingVector(parent);
arrowRotation = parentActor.getBoneRotation(targetBone);
// EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize();
}
Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize();
ProjectileUtils.clientSpawnBasicProjectile(projectileToFire, spawnPosition, arrowRotation, 750, initialVector, 0.03f);
projectileToFire = null;
}
if(currentMove != null && frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames()){
state = AttackTreeState.COOLDOWN;
}
break;
case COOLDOWN:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
} }
} }
if(currentMove != null && frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){ if(currentMove != null && frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){
state = AttackTreeState.IDLE;
frameCurrent = 0; frameCurrent = 0;
if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){ if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){
RotatorTree.getClientRotatorTree(parent).setActive(false); RotatorTree.getClientRotatorTree(parent).setActive(false);
} }
} }
break; } break;
case IDLE: case IDLE: {
currentMove = null; currentMove = null;
currentMoveset = null; currentMoveset = null;
break; } break;
} }
} }
@ -360,11 +300,15 @@ public class ClientAttackTree implements BehaviorTree {
networkMessageQueue.add(networkMessage); networkMessageQueue.add(networkMessage);
} }
/**
* Gets the current attack type
* @return The current attack type
*/
String getAttackType(){ String getAttackType(){
String rVal = null; String rVal = null;
if(ClientEquipState.hasEquipState(parent)){ if(ClientEquipState.hasEquipState(parent)){
ClientEquipState equipState = ClientEquipState.getEquipState(parent); ClientEquipState equipState = ClientEquipState.getEquipState(parent);
for(String point : equipState.equippedPoints()){ for(String point : equipState.getEquippedPoints()){
Entity item = equipState.getEquippedItemAtPoint(point); Entity item = equipState.getEquippedItemAtPoint(point);
if(ItemUtils.isWeapon(item)){ if(ItemUtils.isWeapon(item)){
attackingPoint = point; attackingPoint = point;
@ -399,7 +343,7 @@ public class ClientAttackTree implements BehaviorTree {
} }
} else { } else {
if(ClientEquipState.hasEquipState(parent)){ if(ClientEquipState.hasEquipState(parent)){
ClientEquipState equipState = ClientEquipState.getEquipState(parent); // ClientEquipState equipState = ClientEquipState.getEquipState(parent);
// if(equipState.hasEquipPrimary()){ // if(equipState.hasEquipPrimary()){
// switch(attackType){ // switch(attackType){
// case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND: // case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND:
@ -423,6 +367,12 @@ public class ClientAttackTree implements BehaviorTree {
return rVal; return rVal;
} }
/**
* Gets the object for next move in the current attack chain
* @param moveset The moveset to search
* @param nextMoveId The id of the next move
* @return The object that corresponds to the id if it exists, otherwise false
*/
AttackMove getNextMove(List<AttackMove> moveset, String nextMoveId){ AttackMove getNextMove(List<AttackMove> moveset, String nextMoveId){
AttackMove rVal = null; AttackMove rVal = null;
for(AttackMove move : moveset){ for(AttackMove move : moveset){
@ -433,6 +383,23 @@ public class ClientAttackTree implements BehaviorTree {
} }
return rVal; return rVal;
} }
/**
* Sets the current attack type of the entity
* @param attackType the current attack type
*/
public void setAttackMoveTypeActive(String attackType){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
}
/**
* Gets the current moveset
* @param attackType the attack type
* @return The moveset if it exists
*/
public List<AttackMove> getMoveset(String attackType){
return (List<AttackMove>)parent.getData(attackType);
}
/** /**
* <p> Automatically generated </p> * <p> Automatically generated </p>

View File

@ -9,26 +9,22 @@ import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeDriftState; import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeDriftState;
import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState; import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.equip.ServerEquipState; import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree; import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree;
import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.state.rotator.ServerRotatorTree; import electrosphere.entity.state.rotator.ServerRotatorTree;
import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.hitbox.HitboxUtils;
import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.projectile.ProjectileUtils; import electrosphere.entity.types.projectile.ProjectileUtils;
import electrosphere.game.data.creature.type.attack.AttackMove; import electrosphere.game.data.creature.type.attack.AttackMove;
@ -37,17 +33,14 @@ import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.anim.Animation;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import electrosphere.util.MathUtils;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
@ -58,9 +51,11 @@ import org.joml.Vector3f;
public class ServerAttackTree implements BehaviorTree { public class ServerAttackTree implements BehaviorTree {
@SyncedField @SyncedField
//the state of the attack tree
AttackTreeState state; AttackTreeState state;
@SyncedField @SyncedField
//the state of drifting caused by the attack animation
AttackTreeDriftState driftState; AttackTreeDriftState driftState;
Entity parent; Entity parent;
@ -77,8 +72,8 @@ public class ServerAttackTree implements BehaviorTree {
List<AttackMove> currentMoveset = null; List<AttackMove> currentMoveset = null;
@SyncedField @SyncedField
String currentMoveId = null; String currentMoveId = null; //the id of the current move -- used to synchronize the move to client
AttackMove currentMove = null; AttackMove currentMove = null; //the actual current move object
Entity currentWeapon = null; Entity currentWeapon = null;
boolean currentMoveHasWindup; boolean currentMoveHasWindup;
boolean currentMoveCanHold; boolean currentMoveCanHold;
@ -115,8 +110,8 @@ public class ServerAttackTree implements BehaviorTree {
String attackType = getAttackType(); String attackType = getAttackType();
//if we can attack, setup doing so //if we can attack, setup doing so
if(canAttack(attackType)){ if(canAttack(attackType)){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType); setAttackMoveTypeActive(attackType);
currentMoveset = (List<AttackMove>)parent.getData(attackType); currentMoveset = getMoveset(attackType);
if(currentMoveset != null){ if(currentMoveset != null){
if(currentMove == null){ if(currentMove == null){
currentMove = currentMoveset.get(0); currentMove = currentMoveset.get(0);
@ -145,8 +140,8 @@ public class ServerAttackTree implements BehaviorTree {
} }
} }
Vector3d movementVector = CreatureUtils.getFacingVector(parent); Vector3d movementVector = CreatureUtils.getFacingVector(parent);
EntityUtils.getRotation(parent).rotationTo(new Vector3d(0,0,1), new Vector3d(movementVector.x,movementVector.y,movementVector.z)); EntityUtils.getRotation(parent).rotationTo(MathUtils.getOriginVector(), new Vector3d(movementVector.x,movementVector.y,movementVector.z));
//set initial stuff //set initial stuff (this alerts the client as well)
setCurrentMoveId(currentMove.getAttackMoveId()); setCurrentMoveId(currentMove.getAttackMoveId());
setState(AttackTreeState.WINDUP); setState(AttackTreeState.WINDUP);
frameCurrent = 0; frameCurrent = 0;
@ -171,7 +166,7 @@ public class ServerAttackTree implements BehaviorTree {
@Override @Override
public void simulate(float deltaTime){ public void simulate(float deltaTime){
frameCurrent = frameCurrent + (float)Globals.timekeeper.getSimFrameTime(); frameCurrent = frameCurrent + (float)Globals.timekeeper.getDeltaFrames();
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
PoseActor entityPoseActor = EntityUtils.getPoseActor(parent); PoseActor entityPoseActor = EntityUtils.getPoseActor(parent);
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
@ -180,37 +175,9 @@ public class ServerAttackTree implements BehaviorTree {
//parse attached network messages //parse attached network messages
for(EntityMessage message : networkMessageQueue){ for(EntityMessage message : networkMessageQueue){
networkMessageQueue.remove(message); networkMessageQueue.remove(message);
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
long updateTime = message.gettime();
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case ATTACKUPDATE: case ATTACKUPDATE:
if(updateTime > lastUpdateTime){
lastUpdateTime = updateTime;
switch(message.gettreeState()){
case 0:
setState(AttackTreeState.WINDUP);
frameCurrent = 0;
// System.out.println("Set state STARTUP");
break;
case 1:
frameCurrent = currentMove.getWindupFrames()+1;
setState(AttackTreeState.ATTACK);
// System.out.println("Set state MOVE");
break;
case 2:
frameCurrent = currentMove.getWindupFrames()+currentMove.getAttackFrames()+1;
setState(AttackTreeState.COOLDOWN);
// System.out.println("Set state SLOWDOWN");
break;
case 3:
frameCurrent = 60;
setState(AttackTreeState.IDLE);
// System.out.println("Set state IDLE");
break;
}
}
EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
break; break;
case STARTATTACK: { case STARTATTACK: {
start(); start();
@ -247,7 +214,7 @@ public class ServerAttackTree implements BehaviorTree {
//state machine //state machine
switch(state){ switch(state){
case WINDUP: case WINDUP: {
if(parent.containsKey(EntityDataStrings.SERVER_ROTATOR_TREE)){ if(parent.containsKey(EntityDataStrings.SERVER_ROTATOR_TREE)){
ServerRotatorTree.getServerRotatorTree(parent).setActive(true); ServerRotatorTree.getServerRotatorTree(parent).setActive(true);
} }
@ -278,28 +245,32 @@ public class ServerAttackTree implements BehaviorTree {
0 0
) )
); );
break; } break;
case HOLD: case HOLD: {
if(entityPoseActor != null){ if(entityPoseActor != null){
if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){ if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){
entityPoseActor.playAnimation(animationName,1); entityPoseActor.playAnimation(animationName,1);
entityPoseActor.incrementAnimationTime(0.0001); entityPoseActor.incrementAnimationTime(0.0001);
}
} }
} if(!stillHold){
if(!stillHold){ setState(AttackTreeState.ATTACK);
setState(AttackTreeState.ATTACK); }
} } break;
break; case ATTACK: {
case ATTACK: if(entityPoseActor != null && currentMove != null){
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(currentMove.getAttackAnimationName())){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent); entityPoseActor.playAnimation(currentMove.getAttackAnimationName(),1);
for(Entity currentAttached : attachedEntities){ entityPoseActor.incrementAnimationTime(0.0001);
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){ }
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached); FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonAttack().getName());
for(Entity hitbox : hitboxes){ }
HitboxUtils.getHitboxData(hitbox).setActive(true); //activate hitboxes
} List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
} for(Entity currentAttached : attachedEntities){
if(HitboxCollectionState.hasHitboxState(currentAttached)){
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
currentState.setActive(true);
} }
} }
if(firesProjectile && projectileToFire != null){ if(firesProjectile && projectileToFire != null){
@ -329,7 +300,7 @@ public class ServerAttackTree implements BehaviorTree {
// EntityUtils.getRotation(currentEntity).set(rotation).normalize(); // EntityUtils.getRotation(currentEntity).set(rotation).normalize();
// Vector3d facingAngle = CreatureUtils.getFacingVector(parent); // Vector3d facingAngle = CreatureUtils.getFacingVector(parent);
arrowRotation = parentActor.getBoneRotation(targetBone); arrowRotation = parentActor.getBoneRotation(targetBone);
// EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); // EntityUtils.getRotation(currentEntity).rotationTo(MathUtils.ORIGIN_VECTORF, new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize();
} }
Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize(); Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize();
Realm parentRealm = Globals.realmManager.getEntityRealm(parent); Realm parentRealm = Globals.realmManager.getEntityRealm(parent);
@ -353,17 +324,14 @@ public class ServerAttackTree implements BehaviorTree {
1 1
) )
); );
break; } break;
case COOLDOWN: case COOLDOWN: {
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ //deactive hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent); List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){ for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){ if(HitboxCollectionState.hasHitboxState(currentAttached)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached); HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
for(Entity hitbox : hitboxes){ currentState.setActive(false);
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
} }
} }
if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){ if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){
@ -387,11 +355,11 @@ public class ServerAttackTree implements BehaviorTree {
2 2
) )
); );
break; } break;
case IDLE: case IDLE: {
currentMove = null; currentMove = null;
currentMoveset = null; currentMoveset = null;
break; } break;
} }
} }
@ -422,6 +390,11 @@ public class ServerAttackTree implements BehaviorTree {
return rVal; return rVal;
} }
/**
* Checks whether the entity can attack or not
* @param attackType The type of attack to perform
* @return true if it can attack, false otherwise
*/
boolean canAttack(String attackType){ boolean canAttack(String attackType){
boolean rVal = true; boolean rVal = true;
if(attackType == null){ if(attackType == null){
@ -437,7 +410,7 @@ public class ServerAttackTree implements BehaviorTree {
} }
} else { } else {
if(ServerEquipState.hasEquipState(parent)){ if(ServerEquipState.hasEquipState(parent)){
ServerEquipState equipState = ServerEquipState.getEquipState(parent); // ServerEquipState equipState = ServerEquipState.getEquipState(parent);
// if(equipState.hasEquipPrimary()){ // if(equipState.hasEquipPrimary()){
// switch(attackType){ // switch(attackType){
// case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND: // case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND:
@ -471,6 +444,23 @@ public class ServerAttackTree implements BehaviorTree {
} }
return rVal; return rVal;
} }
/**
* Sets the current attack type of the entity
* @param attackType the current attack type
*/
public void setAttackMoveTypeActive(String attackType){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
}
/**
* Gets the current moveset
* @param attackType the attack type
* @return The moveset if it exists
*/
public List<AttackMove> getMoveset(String attackType){
return (List<AttackMove>)parent.getData(attackType);
}
/** /**
* <p> Automatically generated </p> * <p> Automatically generated </p>

View File

@ -0,0 +1,27 @@
package electrosphere.entity.state.block;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
@SynchronizedBehaviorTree(name = "clientBlockTree", isServer = false, correspondingTree="serverBlockTree")
/**
* Client block tree
*/
public class ClientBlockTree {
@SynchronizableEnum
/**
* The state of the block tree
*/
public enum BlockState {
BLOCKING,
NOT_BLOCKING,
}
@SyncedField
BlockState state;
}

View File

@ -0,0 +1,16 @@
package electrosphere.entity.state.block;
import electrosphere.entity.state.block.ClientBlockTree.BlockState;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
@SynchronizedBehaviorTree(name = "serverBlockTree", isServer = true, correspondingTree="clientBlockTree")
/**
* Server block tree
*/
public class ServerBlockTree {
@SyncedField
BlockState state;
}

View File

@ -115,7 +115,7 @@ public class FirstPersonTree implements BehaviorTree {
* @param animationName the name of the animation * @param animationName the name of the animation
*/ */
public static void conditionallyPlayAnimation(Entity entity, String animationName){ public static void conditionallyPlayAnimation(Entity entity, String animationName){
if(hasTree(entity)){ if(entity != null && hasTree(entity)){
getTree(entity).playAnimation(animationName); getTree(entity).playAnimation(animationName);
} }
} }

View File

@ -48,7 +48,7 @@ public class ClientEquipState implements BehaviorTree {
* @param parent the entity this is attached to * @param parent the entity this is attached to
* @param equipPoints the list of available points * @param equipPoints the list of available points
*/ */
public ClientEquipState(Entity parent, List<EquipPoint> equipPoints){ private ClientEquipState(Entity parent, List<EquipPoint> equipPoints){
this.parent = parent; this.parent = parent;
for(EquipPoint point : equipPoints){ for(EquipPoint point : equipPoints){
this.equipPoints.add(point); this.equipPoints.add(point);
@ -59,10 +59,19 @@ public class ClientEquipState implements BehaviorTree {
* Gets the list of equipped points * Gets the list of equipped points
* @return the list * @return the list
*/ */
public List<String> equippedPoints(){ public List<String> getEquippedPoints(){
return new LinkedList<String>(equipMap.keySet()); return new LinkedList<String>(equipMap.keySet());
} }
/**
* Gets the list of all equip points
* @return The list of all equip points
*/
public List<EquipPoint> getAllEquipPoints(){
return equipPoints;
}
/** /**
* Attempts to equip the item * Attempts to equip the item
* @param toEquip the item to equip * @param toEquip the item to equip
@ -72,7 +81,6 @@ public class ClientEquipState implements BehaviorTree {
boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId()); boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId());
boolean targetIsItem = ItemUtils.isItem(toEquip); boolean targetIsItem = ItemUtils.isItem(toEquip);
boolean targetIsAttached = AttachUtils.isAttached(toEquip); boolean targetIsAttached = AttachUtils.isAttached(toEquip);
boolean targetHasWhitelist = ItemUtils.hasEquipList(toEquip);
String equipItemClass = ItemUtils.getEquipClass(toEquip); String equipItemClass = ItemUtils.getEquipClass(toEquip);
List<String> pointEquipClassList = point.getEquipClassWhitelist(); List<String> pointEquipClassList = point.getEquipClassWhitelist();
boolean itemIsInPointWhitelist = pointEquipClassList.contains(equipItemClass); boolean itemIsInPointWhitelist = pointEquipClassList.contains(equipItemClass);
@ -90,7 +98,7 @@ public class ClientEquipState implements BehaviorTree {
* @param toEquip The entity to equip * @param toEquip The entity to equip
* @param point The equipment point to equip to * @param point The equipment point to equip to
*/ */
public void clientAttemptEquip(Entity toEquip, EquipPoint point){ public void attemptEquip(Entity toEquip, EquipPoint point){
boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId()); boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId());
boolean targetIsItem = ItemUtils.isItem(toEquip); boolean targetIsItem = ItemUtils.isItem(toEquip);
boolean targetIsAttached = AttachUtils.isAttached(toEquip); boolean targetIsAttached = AttachUtils.isAttached(toEquip);
@ -222,7 +230,7 @@ public class ClientEquipState implements BehaviorTree {
* @return True if the entity contains an equip state, false otherwise * @return True if the entity contains an equip state, false otherwise
*/ */
public static boolean hasEquipState(Entity entity){ public static boolean hasEquipState(Entity entity){
return entity.containsKey(EntityDataStrings.EQUIP_STATE); return entity.containsKey(EntityDataStrings.TREE_CLIENTEQUIPSTATE);
} }
/** /**
@ -231,7 +239,7 @@ public class ClientEquipState implements BehaviorTree {
* @return The equip state on the entity * @return The equip state on the entity
*/ */
public static ClientEquipState getEquipState(Entity entity){ public static ClientEquipState getEquipState(Entity entity){
return (ClientEquipState)entity.getData(EntityDataStrings.EQUIP_STATE); return (ClientEquipState)entity.getData(EntityDataStrings.TREE_CLIENTEQUIPSTATE);
} }
/** /**
@ -240,7 +248,7 @@ public class ClientEquipState implements BehaviorTree {
* @param equipState The equip state to attach * @param equipState The equip state to attach
*/ */
public static void setEquipState(Entity entity, ClientEquipState equipState){ public static void setEquipState(Entity entity, ClientEquipState equipState){
entity.putData(EntityDataStrings.EQUIP_STATE, equipState); entity.putData(EntityDataStrings.TREE_CLIENTEQUIPSTATE, equipState);
} }
// public void drop(Entity entity){ // public void drop(Entity entity){

View File

@ -190,7 +190,7 @@ public class ServerEquipState implements BehaviorTree {
* @return True if the entity contains an equip state, false otherwise * @return True if the entity contains an equip state, false otherwise
*/ */
public static boolean hasEquipState(Entity entity){ public static boolean hasEquipState(Entity entity){
return entity.containsKey(EntityDataStrings.EQUIP_STATE); return entity.containsKey(EntityDataStrings.TREE_SERVEREQUIPSTATE);
} }
/** /**
@ -199,7 +199,7 @@ public class ServerEquipState implements BehaviorTree {
* @return The equip state on the entity * @return The equip state on the entity
*/ */
public static ServerEquipState getEquipState(Entity entity){ public static ServerEquipState getEquipState(Entity entity){
return (ServerEquipState)entity.getData(EntityDataStrings.EQUIP_STATE); return (ServerEquipState)entity.getData(EntityDataStrings.TREE_SERVEREQUIPSTATE);
} }
/** /**
@ -208,7 +208,7 @@ public class ServerEquipState implements BehaviorTree {
* @param equipState The equip state to attach * @param equipState The equip state to attach
*/ */
public static void setEquipState(Entity entity, ServerEquipState equipState){ public static void setEquipState(Entity entity, ServerEquipState equipState){
entity.putData(EntityDataStrings.EQUIP_STATE, equipState); entity.putData(EntityDataStrings.TREE_SERVEREQUIPSTATE, equipState);
} }
// public void drop(Entity entity){ // public void drop(Entity entity){

View File

@ -52,7 +52,7 @@ public class AmbientFoliage implements BehaviorTree {
//rotate to face cameras //rotate to face cameras
// Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); // Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera);
// EntityUtils.getRotation(parent).rotateTo(new Vector3d(1,0,0), new Vector3d(cameraEyeVector)); // EntityUtils.getRotation(parent).rotateTo(MathUtils.ORIGIN_VECTOR, new Vector3d(cameraEyeVector));
//TODO: simulate wind offset //TODO: simulate wind offset

View File

@ -0,0 +1,594 @@
package electrosphere.entity.state.hitbox;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.collision.hitbox.HitboxUtils.HitboxPositionCallback;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.HitboxShapeType;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.util.MathUtils;
/**
* The state of the collection of all hitboxes on this entity
* Ie, it stores the state of each hitbox that is attached to this entity
*/
public class HitboxCollectionState {
/**
* Types of hitboxes
*/
public enum HitboxType {
HIT, // damages another entity
HURT, // receives damage from another entity
BLOCK, // blocks a hit from another entity
}
//the parent entity of the hitbox state
Entity parent;
//the body that contains all the hitbox shapes
DBody body;
//The collidable associated with the body
Collidable collidable;
//the list of all geoms in the collection state
List<DGeom> geoms = new LinkedList<DGeom>();
//the map of bone -> hitbox shape in ode4j
Map<String,DGeom> hitboxGeomMap = new HashMap<String,DGeom>();
//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>();
//callback to provide a position for the hitbox each frame
HitboxPositionCallback positionCallback;
//controls whether the hitbox state is active or not
boolean active = true;
//the associated manager
HitboxManager manager;
//controls whether this hitbox collection thinks its on the server or client
boolean isServer = true;
/**
* Create hitbox state for an entity
* @param collisionEngine the collision engine
* @param entity The entity to attach the state to
* @param hitboxListRaw The list of hitbox data to apply
* @return The hitbox state that has been attached to the entity
*/
public static HitboxCollectionState attachHitboxState(HitboxManager manager, boolean isServer, Entity entity, List<HitboxData> hitboxListRaw){
HitboxCollectionState rVal = new HitboxCollectionState();
rVal.isServer = isServer;
//create the shapes
for(HitboxData hitboxDataRaw : hitboxListRaw){
DGeom geom = null;
HitboxType type = HitboxType.HIT;
HitboxShapeType shapeType = HitboxShapeType.SPHERE;
switch(hitboxDataRaw.getType()){
case HitboxData.HITBOX_TYPE_HIT: {
type = HitboxType.HIT;
shapeType = HitboxShapeType.SPHERE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HURT: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.SPHERE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
type = HitboxType.HIT;
shapeType = HitboxShapeType.CAPSULE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.CAPSULE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_STATIC_CAPSULE: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.STATIC_CAPSULE;
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), hitboxDataRaw.getLength(), Collidable.TYPE_OBJECT_BIT);
} break;
}
if(hitboxDataRaw.getBone() != null){
rVal.hitboxGeomMap.put(hitboxDataRaw.getBone(),geom);
}
rVal.geoms.add(geom);
rVal.geomStateMap.put(geom,new HitboxState(hitboxDataRaw.getBone(), hitboxDataRaw, type, shapeType, true));
}
//create body with all the shapes
DGeom[] geomArray = rVal.geoms.toArray(new DGeom[rVal.geoms.size()]);
rVal.body = CollisionBodyCreation.createBodyWithShapes(manager.getCollisionEngine(), geomArray);
//register collidable with collision engine
Collidable collidable = new Collidable(entity, Collidable.TYPE_OBJECT);
manager.getCollisionEngine().registerCollisionObject(rVal.body, collidable);
//attach
entity.putData(EntityDataStrings.HITBOX_DATA, rVal);
rVal.parent = entity;
//register
manager.registerHitbox(rVal);
rVal.manager = manager;
return rVal;
}
/**
* Create hitbox state for an entity
* @param collisionEngine the collision engine
* @param entity The entity to attach the state to
* @param data The hitbox data to apply
* @param callback The callback that provides a position for the hitbox each frame
* @return The hitbox state that has been attached to the entity
*/
public static HitboxCollectionState attachHitboxStateWithCallback(HitboxManager manager, CollisionEngine collisionEngine, Entity entity, HitboxData data, HitboxPositionCallback callback){
HitboxCollectionState rVal = new HitboxCollectionState();
//create the shapes
rVal.hitboxGeomMap.put(data.getBone(),CollisionBodyCreation.createShapeSphere(collisionEngine, data.getRadius(), Collidable.TYPE_OBJECT_BIT));
//create body with all the shapes
DGeom[] geomArray = rVal.hitboxGeomMap.values().toArray(new DGeom[rVal.hitboxGeomMap.values().size()]);
rVal.body = CollisionBodyCreation.createBodyWithShapes(collisionEngine, geomArray);
//register collidable with collision engine
Collidable collidable = new Collidable(entity, Collidable.TYPE_OBJECT);
collisionEngine.registerCollisionObject(rVal.body, collidable);
//attach
entity.putData(EntityDataStrings.HITBOX_DATA, rVal);
rVal.parent = entity;
//register
manager.registerHitbox(rVal);
rVal.manager = manager;
return rVal;
}
/**
* Clears the collision status of all shapes
*/
public void clearCollisions(){
for(DGeom geom : this.geoms){
HitboxState shapeStatus = this.geomStateMap.get(geom);
shapeStatus.setHadCollision(false);
}
}
/**
* Updates the positions of all hitboxes
*/
public void updateHitboxPositions(CollisionEngine collisionEngine){
if(parent != null && !isServer && EntityUtils.getActor(parent) != null){
if(!this.hitboxGeomMap.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
for(String boneName : this.hitboxGeomMap.keySet()){
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
DGeom geom = this.hitboxGeomMap.get(boneName);
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,bonePosition);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,bonePosition);
} break;
case STATIC_CAPSULE: {
} break;
}
}
} 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);
}
} else if(parent != null && isServer && EntityUtils.getPoseActor(parent) != null){
if(!this.hitboxGeomMap.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
for(String boneName : this.hitboxGeomMap.keySet()){
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
DGeom geom = this.hitboxGeomMap.get(boneName);
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,bonePosition);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,bonePosition);
} break;
case STATIC_CAPSULE: {
} break;
}
}
} 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);
}
} else if(parent != null && isServer){
for(DGeom geom : this.geoms){
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
} break;
case CAPSULE: {
} break;
case STATIC_CAPSULE: {
this.updateStaticCapsulePosition(collisionEngine, geom, shapeStatus);
} break;
}
}
}
}
/**
* Updates the position of the geom for a static capsule
* @param collisionEngine The collision engine
* @param boneName The name of the bone the static capsule is attached to
* @param bonePosition The position of the bone
*/
private void updateStaticCapsulePosition(CollisionEngine collisionEngine, DGeom geom, HitboxState shapeStatus){
Vector3d parentPos = EntityUtils.getPosition(parent);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, parentPos, new Quaterniond(0.707,0,0,0.707));
}
/**
* Updates the position of a sphere-shape-type hitbox
* @param collisionEngine The collision engine
* @param boneName The name of the bone
* @param bonePosition the position of the bone
*/
private void updateSphereShapePosition(CollisionEngine collisionEngine, String boneName, Vector3f bonePosition){
DGeom geom = this.hitboxGeomMap.get(boneName);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3d parentPos = EntityUtils.getPosition(parent);
Quaterniond rotation = new Quaterniond(parentRotation);
//calculate new world pos
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
}
/**
* Updates the position of a capsule-shape hitbox
* @param collisionEngine
* @param boneName
* @param bonePosition
*/
private void updateCapsuleShapePosition(CollisionEngine collisionEngine, String boneName, Vector3f bonePosition){
DGeom geom = this.hitboxGeomMap.get(boneName);
HitboxState shapeStatus = this.geomStateMap.get(geom);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3d parentPos = EntityUtils.getPosition(parent);
Quaterniond rotation = new Quaterniond(parentRotation);
Vector3d previousWorldPos = shapeStatus.getPreviousWorldPos();
//calculate new world pos
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
double length = shapeStatus.getHitboxData().getRadius();
double radius = shapeStatus.getHitboxData().getRadius();
if(previousWorldPos != null){
//called all subsequent updates to hitbox position
//destroy old capsule
this.geomStateMap.remove(geom);
this.geoms.remove(geom);
CollisionBodyCreation.destroyShape(collisionEngine, geom);
//calculate position between new world point and old world point
Vector3d bodyPosition = new Vector3d(worldPosition).lerp(previousWorldPos, 0.5);
//calculate rotation from old position to new position
//the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space
//ode is Z-axis-up
rotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0,0.707,0.707));
//create new capsule
length = previousWorldPos.distance(worldPosition) / 2.0;
if(length > 5000 || Double.isNaN(length) || Double.isInfinite(length) || length <= 0){
length = 0.1;
System.out.println("HitboxState --- THIS IS NAN WHEN YOU SPAWN A KATANA BECAUSE THE BONE POSITION IS NAN???");
}
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), shapeStatus.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, bodyPosition, rotation);
} else {
//called first time the hitbox updates position
this.geomStateMap.remove(geom);
this.geoms.remove(geom);
CollisionBodyCreation.destroyShape(collisionEngine, geom);
//create new capsule
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), shapeStatus.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
}
//update maps and other variables for next frame
this.hitboxGeomMap.put(boneName,geom);
this.geomStateMap.put(geom,shapeStatus);
this.geoms.add(geom);
shapeStatus.setPreviousWorldPos(worldPosition);
}
/**
* Gets the status of a shape in the hitbox object
* @param geom The geometry that is the shape within the hitbox data
* @return The status of the shape
*/
public HitboxState getShapeStatus(DGeom geom){
return this.geomStateMap.get(geom);
}
/**
* Gets the hitbox state of the entity
* @param entity the entity
* @return the hitbox state if it exists
*/
public static HitboxCollectionState getHitboxState(Entity entity){
return (HitboxCollectionState)entity.getData(EntityDataStrings.HITBOX_DATA);
}
/**
* Checks whether the entity has hitbox state or not
* @param entity the entity to check
* @return true if there is hitbox state, false otherwise
*/
public static boolean hasHitboxState(Entity entity){
return entity.containsKey(EntityDataStrings.HITBOX_DATA);
}
/**
* Destroys the hitbox state and removes it from the entity
* @param entity the entity
* @return The hitbox state if it exists, null otherwise
*/
public static HitboxCollectionState destroyHitboxState(Entity entity){
HitboxCollectionState state = null;
if(hasHitboxState(entity)){
state = getHitboxState(entity);
state.manager.deregisterHitbox(state);
}
return state;
}
/**
* Gets whether the hitbox state is active or not
* @return true if active, false otherwise
*/
public boolean isActive(){
return active;
}
/**
* Sets the active state of the hitbox
* @param state true to make it active, false otherwise
*/
public void setActive(boolean state){
this.active = state;
}
/**
* Gets the list of all DGeoms in the data
* @return the list of all DGeoms
*/
public List<DGeom> getGeometries(){
return this.geoms;
}
/**
* Gets the set of bone names in the state data
* @return The set of bone names in the state data
*/
public Set<String> getBones(){
return this.hitboxGeomMap.keySet();
}
/**
* Gets geometry on a single hitbox based on its bone name
* @param boneName the bone name
* @return the hitbox geometry
*/
public DGeom getGeometry(String boneName){
return this.hitboxGeomMap.get(boneName);
}
/**
* The status of a single shape inside the overall hitbox data
* IE a single sphere on the overall body
*/
public static class HitboxState {
/**
* Types of geometry that can be used as individual shapes within a hitbox
*/
public enum HitboxShapeType {
//this is a true sphere. It will teleport every frame to its new position
SPHERE,
//for this one, the shape is a capsule in the collision engine, however
//the capsule is used to have continuity between the last position the hitbox occupied and the current one
CAPSULE,
//this is a true static capsule, it doesn't act as two connected spheres but is instead a capsule that teleports between frames
STATIC_CAPSULE,
}
//the name of the bone the hitbox is attached to
String boneName;
//the type of hitbox
HitboxType type;
//the type of geometry
HitboxShapeType shapeType;
//controls whether the hitbox is active
boolean isActive;
//the previous position of this hitbox shape
Vector3d previousWorldPos = null;
//if true, just had a collision
boolean hadCollision = false;
//the data of the hitbox
HitboxData data;
/**
* Creates a status object for a hitbox
* @param boneName The name of the bone the hitbox is attached to, if any
* @param data the hitbox data object
* @param type The type of hitbox
* @param shapeType The type of shape the hitbox is
* @param isActive if the hitbox is active or not
*/
public HitboxState(String boneName, HitboxData data, HitboxType type, HitboxShapeType shapeType, boolean isActive){
this.boneName = boneName;
this.data = data;
this.type = type;
this.shapeType = shapeType;
this.isActive = isActive;
}
/**
* Gets the name of the bone the hitbox is attached to
* @return The name of the bone
*/
public String getBoneName(){
return boneName;
}
/**
* Sets the name of the bone the hitbox is attached to
* @param boneName The bone name
*/
public void setBoneName(String boneName){
this.boneName = boneName;
}
/**
* Gets the hitbox data for this shape
* @return The data
*/
public HitboxData getHitboxData(){
return this.data;
}
/**
* Sets the hitbox data for this shape
* @param data The data
*/
public void setHitboxData(HitboxData data){
this.data = data;
}
/**
* Gets the type of hitbox
* @return The type
*/
public HitboxType getType(){
return type;
}
/**
* Sets the type of hitbox
* @param type The type
*/
public void setType(HitboxType type){
this.type = type;
}
/**
* Gets whether the hitbox is active or not
* @return true if active, false otherwise
*/
public boolean isActive(){
return isActive;
}
/**
* Sets whether the hitbox is active or not
* @param active true for active, false otherwise
*/
public void setActive(boolean active){
this.isActive = active;
}
/**
* Gets the previous world position of this hitbox
* @return The previous world position
*/
public Vector3d getPreviousWorldPos(){
return this.previousWorldPos;
}
/**
* sets the previous world position of this hitbox shape
* @param previousWorldPos The previous world position
*/
public void setPreviousWorldPos(Vector3d previousWorldPos){
this.previousWorldPos = previousWorldPos;
}
/**
* Sets the status of whether this hitbox just had a collision or not
* @param hadCollision true if had a collision, false otherwise
*/
public void setHadCollision(boolean hadCollision){
this.hadCollision = hadCollision;
}
/**
* Gets the collision status of the hitbox
* @return true if had a collision, false otherwise
*/
public boolean getHadCollision(){
return this.hadCollision;
}
}
}

View File

@ -28,7 +28,7 @@ import electrosphere.renderer.anim.Animation;
/** /**
* Tree for playing an idle animation when an entity isn't doing anything * Tree for playing an idle animation when an entity isn't doing anything
*/ */
public class IdleTree implements BehaviorTree { public class ClientIdleTree implements BehaviorTree {
@SynchronizableEnum @SynchronizableEnum
public static enum IdleTreeState { public static enum IdleTreeState {
@ -42,11 +42,19 @@ public class IdleTree implements BehaviorTree {
Entity parent; Entity parent;
IdleData idleData; IdleData idleData;
public IdleTree(Entity e){ /**
* Creates an idle tree
* @param e the entity to attach the tree to
*/
public ClientIdleTree(Entity e){
state = IdleTreeState.IDLE; state = IdleTreeState.IDLE;
parent = e; parent = e;
//check if this is a creature, if so add its idle data
CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(parent)); CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(parent));
idleData = creatureType.getIdleData(); if(creatureType != null){
idleData = creatureType.getIdleData();
}
//TODO: if object, check if object has idle data and add accordingly
} }
/** /**
@ -139,8 +147,8 @@ public class IdleTree implements BehaviorTree {
* @param entity The entity to attach to * @param entity The entity to attach to
* @param tree The behavior tree to attach * @param tree The behavior tree to attach
*/ */
public static IdleTree attachTree(Entity parent){ public static ClientIdleTree attachTree(Entity parent){
IdleTree rVal = new IdleTree(parent); ClientIdleTree rVal = new ClientIdleTree(parent);
//put manual code here (setting params, etc) //put manual code here (setting params, etc)
@ -194,8 +202,8 @@ public class IdleTree implements BehaviorTree {
* @param entity the entity * @param entity the entity
* @return The IdleTree * @return The IdleTree
*/ */
public static IdleTree getIdleTree(Entity entity){ public static ClientIdleTree getIdleTree(Entity entity){
return (IdleTree)entity.getData(EntityDataStrings.TREE_IDLE); return (ClientIdleTree)entity.getData(EntityDataStrings.TREE_IDLE);
} }
/** /**
* <p> Automatically generated </p> * <p> Automatically generated </p>

View File

@ -2,7 +2,7 @@ package electrosphere.entity.state.idle;
import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState; import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState;
import electrosphere.entity.state.attack.ServerAttackTree; import electrosphere.entity.state.attack.ServerAttackTree;
import electrosphere.entity.state.idle.IdleTree.IdleTreeState; import electrosphere.entity.state.idle.ClientIdleTree.IdleTreeState;
import electrosphere.entity.state.movement.AirplaneMovementTree; import electrosphere.entity.state.movement.AirplaneMovementTree;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState;
import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree; import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree;
@ -12,6 +12,7 @@ import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.creature.type.CreatureType;
import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.SynchronizationMessage; import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.net.synchronization.BehaviorTreeIdEnums;
@ -39,6 +40,10 @@ public class ServerIdleTree implements BehaviorTree {
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>();
/**
* Creates a server idle tree
* @param e The entity to attach it to
*/
public ServerIdleTree(Entity e){ public ServerIdleTree(Entity e){
state = IdleTreeState.IDLE; state = IdleTreeState.IDLE;
parent = e; parent = e;
@ -68,7 +73,7 @@ public class ServerIdleTree implements BehaviorTree {
} }
public void simulate(float deltaTime){ public void simulate(float deltaTime){
PoseActor entityActor = EntityUtils.getPoseActor(parent); PoseActor poseActor = EntityUtils.getPoseActor(parent);
boolean movementTreeIsIdle = movementTreeIsIdle(); boolean movementTreeIsIdle = movementTreeIsIdle();
@ -83,12 +88,12 @@ public class ServerIdleTree implements BehaviorTree {
//state machine //state machine
switch(state){ switch(state){
case IDLE: case IDLE:
if(entityActor != null){ if(poseActor != null){
if( if(
(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(Animation.ANIMATION_IDLE_1)) (!poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(Animation.ANIMATION_IDLE_1))
){ ){
entityActor.playAnimation(Animation.ANIMATION_IDLE_1,3); poseActor.playAnimation(Animation.ANIMATION_IDLE_1,3);
entityActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
isIdle = true; isIdle = true;
@ -184,7 +189,7 @@ public class ServerIdleTree implements BehaviorTree {
*/ */
public void setState(IdleTreeState state){ public void setState(IdleTreeState state){
this.state = state; this.state = state;
int value = IdleTree.getIdleTreeStateEnumAsShort(state); int value = ClientIdleTree.getIdleTreeStateEnumAsShort(state);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), 7, 9, value)); DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), 7, 9, value));
} }

View File

@ -5,7 +5,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Vector3d; import org.joml.Vector3d;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
@ -17,6 +16,9 @@ import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.datacell.utils.DataCellSearchUtils;
/**
* The status of the life value of a given entity
*/
public class LifeState implements BehaviorTree { public class LifeState implements BehaviorTree {
@ -108,7 +110,6 @@ public class LifeState implements BehaviorTree {
public void damage(int damage){ public void damage(int damage){
if(!isInvincible){ if(!isInvincible){
lifeCurrent = lifeCurrent - damage; lifeCurrent = lifeCurrent - damage;
System.out.println(lifeCurrent);
isInvincible = true; isInvincible = true;
if(lifeCurrent < 0){ if(lifeCurrent < 0){
lifeCurrent = 0; lifeCurrent = 0;
@ -148,16 +149,7 @@ public class LifeState implements BehaviorTree {
deathFrameCurrent = frameskip; deathFrameCurrent = frameskip;
} }
break; break;
case ATTACHENTITYTOENTITY: default:
case ATTACKUPDATE:
case CREATE:
case DESTROY:
case SETBEHAVIORTREE:
case SETPOSITION:
case SETPROPERTY:
case MOVE:
case SETFACING:
case MOVEUPDATE:
//silently ignore //silently ignore
break; break;
} }

View File

@ -20,7 +20,9 @@ import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.anim.Animation; import electrosphere.renderer.anim.Animation;
import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.util.MathUtils;
@Deprecated
public class AirplaneMovementTree implements BehaviorTree { public class AirplaneMovementTree implements BehaviorTree {
public static enum AirplaneMovementTreeState { public static enum AirplaneMovementTreeState {
@ -82,7 +84,7 @@ public class AirplaneMovementTree implements BehaviorTree {
Actor entityActor = EntityUtils.getActor(parent); Actor entityActor = EntityUtils.getActor(parent);
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent); Vector3d facingVector = CreatureUtils.getFacingVector(parent);
Quaterniond movementQuaternion = new Quaterniond().rotationTo(new Vector3d(0,0,1), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
// //
//handle network messages //handle network messages
@ -91,11 +93,6 @@ public class AirplaneMovementTree implements BehaviorTree {
networkMessageQueue.remove(message); networkMessageQueue.remove(message);
long updateTime = message.gettime(); long updateTime = message.gettime();
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case MOVE: {
if(Globals.RUN_CLIENT){
position.set(message.getpositionX(), message.getpositionY(), message.getpositionZ());
}
} break;
//received a message to update the tree //received a message to update the tree
case MOVEUPDATE: { case MOVEUPDATE: {
if(updateTime > lastUpdateTime){ if(updateTime > lastUpdateTime){
@ -120,15 +117,6 @@ public class AirplaneMovementTree implements BehaviorTree {
//we want to always update the server facing vector with where the client says they're facing //we want to always update the server facing vector with where the client says they're facing
CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ())); CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
} }
} break;
case SETBEHAVIORTREE: {
} break;
case SETFACING: {
} break;
case SETPOSITION: {
} break; } break;
case ATTACHENTITYTOENTITY: case ATTACHENTITYTOENTITY:
case ATTACKUPDATE: case ATTACKUPDATE:
@ -200,15 +188,15 @@ public class AirplaneMovementTree implements BehaviorTree {
Quaterniond yawQuat = new Quaterniond().fromAxisAngleRad(new Vector3d(0,1,0), yaw); Quaterniond yawQuat = new Quaterniond().fromAxisAngleRad(new Vector3d(0,1,0), yaw);
Quaterniond pitchQuat = new Quaterniond().fromAxisAngleRad(new Vector3d(1,0,0), pitch); Quaterniond pitchQuat = new Quaterniond().fromAxisAngleRad(MathUtils.getOriginVector(), pitch);
Quaterniond rollQuat = new Quaterniond().fromAxisAngleRad(new Vector3d(0,0,1), rollVal); Quaterniond rollQuat = new Quaterniond().fromAxisAngleRad(MathUtils.getOriginVector(), rollVal);
rotation.slerp(yawQuat.mul(pitchQuat).mul(rollQuat),0.1); rotation.slerp(yawQuat.mul(pitchQuat).mul(rollQuat),0.1);
//rotate thrust vector //rotate thrust vector
rotationVector.set(rotation.transform(new Vector3d(0,0,1))); rotationVector.set(rotation.transform(MathUtils.getOriginVector()));
// rotationVector.set(new Vector3f((float)rotationVector.x,(float)rotationVector.y,(float)rotationVector.z).mul(1.0f - this.maxRotationSpeed).add(new Vector3f(cameraEyeVector).mul(-this.maxRotationSpeed))); // rotationVector.set(new Vector3f((float)rotationVector.x,(float)rotationVector.y,(float)rotationVector.z).mul(1.0f - this.maxRotationSpeed).add(new Vector3f(cameraEyeVector).mul(-this.maxRotationSpeed)));
@ -224,7 +212,7 @@ public class AirplaneMovementTree implements BehaviorTree {
* @param collidable The collidable of the entity * @param collidable The collidable of the entity
*/ */
void addMovementForce(float velocity, Quaterniond rotation, Collidable collidable){ void addMovementForce(float velocity, Quaterniond rotation, Collidable collidable){
Vector3d impulseDir = rotation.transform(new Vector3d(0,0,1)); Vector3d impulseDir = rotation.transform(MathUtils.getOriginVector());
collidable.addImpulse(new Impulse(new Vector3d(impulseDir), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Globals.timekeeper.getSimFrameTime(), "movement")); collidable.addImpulse(new Impulse(new Vector3d(impulseDir), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Globals.timekeeper.getSimFrameTime(), "movement"));
} }
@ -257,6 +245,7 @@ public class AirplaneMovementTree implements BehaviorTree {
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
0,
stateNumber stateNumber
) )
); );

View File

@ -5,6 +5,7 @@ import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.server.poseactor.PoseActor;
public class ServerFallTree implements BehaviorTree { public class ServerFallTree implements BehaviorTree {
@ -28,17 +29,17 @@ public class ServerFallTree implements BehaviorTree {
@Override @Override
public void simulate(float deltaTime) { public void simulate(float deltaTime) {
Actor entityActor = EntityUtils.getActor(parent); PoseActor poseActor = EntityUtils.getPoseActor(parent);
switch(state){ switch(state){
case ACTIVE: case ACTIVE:
if(entityActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && !poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay) &&
(jumpTree == null || !jumpTree.isJumping()) (jumpTree == null || !jumpTree.isJumping())
){ ){
entityActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
break; break;
@ -58,14 +59,14 @@ public class ServerFallTree implements BehaviorTree {
public void land(){ public void land(){
if(state != FallState.INACTIVE){ if(state != FallState.INACTIVE){
state = FallState.INACTIVE; state = FallState.INACTIVE;
Actor entityActor = EntityUtils.getActor(parent); PoseActor poseActor = EntityUtils.getPoseActor(parent);
if(entityActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) !poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay)
){ ){
entityActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
} }

View File

@ -14,6 +14,7 @@ import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.gravity.GravityUtils; import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.server.poseactor.PoseActor;
public class ServerJumpTree implements BehaviorTree { public class ServerJumpTree implements BehaviorTree {
@ -53,14 +54,14 @@ public class ServerJumpTree implements BehaviorTree {
@Override @Override
public void simulate(float deltaTime) { public void simulate(float deltaTime) {
Actor entityActor = EntityUtils.getActor(parent); PoseActor poseActor = EntityUtils.getPoseActor(parent);
switch(state){ switch(state){
case ACTIVE: case ACTIVE:
if(entityActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay)){ if(!poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay)){
entityActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
currentFrame++; currentFrame++;

View File

@ -3,20 +3,13 @@ package electrosphere.entity.state.movement.groundmove;
import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.GravityUtils; import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.creature.type.movement.GroundMovementSystem; import electrosphere.game.data.creature.type.movement.GroundMovementSystem;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
@ -28,24 +21,18 @@ import electrosphere.entity.state.movement.FallTree;
import electrosphere.entity.state.movement.JumpTree; import electrosphere.entity.state.movement.JumpTree;
import electrosphere.entity.state.movement.SprintTree; import electrosphere.entity.state.movement.SprintTree;
import electrosphere.entity.state.movement.SprintTree.SprintTreeState; import electrosphere.entity.state.movement.SprintTree.SprintTreeState;
import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.anim.Animation; import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Model; import electrosphere.util.MathUtils;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.math.DVector3;
import org.ode4j.math.DVector3C; import org.ode4j.math.DVector3C;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
@ -69,6 +56,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
* The relative facing of the character to its rotation * The relative facing of the character to its rotation
* (ie is it strafing, moveing straight forward, backpedaling, etc) * (ie is it strafing, moveing straight forward, backpedaling, etc)
*/ */
@SynchronizableEnum
public static enum MovementRelativeFacing { public static enum MovementRelativeFacing {
FORWARD, FORWARD,
LEFT, LEFT,
@ -81,8 +69,10 @@ public class ClientGroundMovementTree implements BehaviorTree {
} }
static final double STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD = 1.0; static final double STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD = 1.0;
static final double STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD = 0.2; static final double STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD = 0.1;
static final double SOFT_UPDATE_MULTIPLIER = 0.1; static final double SOFT_UPDATE_MULTIPLIER = 0.3;
static final double STATE_DIFFERENCE_CREEP_MULTIPLIER = 0.001; //while the movement tree is idle, slowly creep the position of the entity towards the true server position by this amount
static final double STATE_DIFFERENCE_CREEP_CUTOFF = 0.01; //the cutoff for creep when we say it's "close enough"
String animationStartUp = Animation.ANIMATION_MOVEMENT_STARTUP; String animationStartUp = Animation.ANIMATION_MOVEMENT_STARTUP;
String animationMain = Animation.ANIMATION_MOVEMENT_MOVE; String animationMain = Animation.ANIMATION_MOVEMENT_MOVE;
@ -107,18 +97,32 @@ public class ClientGroundMovementTree implements BehaviorTree {
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>();
//the last frame we got an update on true position from the server
long lastUpdateTime = 0; long lastUpdateTime = 0;
//the last position reported by the server
Vector3d lastServerPosition = null;
/**
* Constructor
* @param e The parent entity
*/
private ClientGroundMovementTree(Entity e){ private ClientGroundMovementTree(Entity e){
state = MovementTreeState.IDLE; state = MovementTreeState.IDLE;
parent = e; parent = e;
} }
/**
* Gets the state of the tree
* @return The state
*/
public MovementTreeState getState(){ public MovementTreeState getState(){
return state; return state;
} }
/**
* Requests to the server that the entity start moving
* @param facing The facing relative to the view direction that the entity should move in (ie strafe right vs walk straight forward)
*/
public void start(MovementRelativeFacing facing){ public void start(MovementRelativeFacing facing){
if(canStartMoving()){ if(canStartMoving()){
setFacing(facing); setFacing(facing);
@ -126,7 +130,6 @@ public class ClientGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to walk forward //if we aren't the server, alert the server we intend to walk forward
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
Globals.clientConnection.queueOutgoingMessage( Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
@ -140,23 +143,21 @@ public class ClientGroundMovementTree implements BehaviorTree {
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
0 //magic number corresponding to state startup 0 //magic number corresponding to state startup
) )
); );
} }
} }
public void interrupt(){ /**
state = MovementTreeState.IDLE; * Requests to the server that the movetree stop
CreatureUtils.setVelocity(parent, 0); */
}
public void slowdown(){ public void slowdown(){
state = MovementTreeState.SLOWDOWN; state = MovementTreeState.SLOWDOWN;
//if we aren't the server, alert the server we intend to slow down //if we aren't the server, alert the server we intend to slow down
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
Globals.clientConnection.queueOutgoingMessage( Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
@ -170,11 +171,13 @@ public class ClientGroundMovementTree implements BehaviorTree {
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
2 //magic number corresponding to state slowdown 2 //magic number corresponding to state slowdown
) )
); );
} }
@Override
public void simulate(float deltaTime){ public void simulate(float deltaTime){
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
float acceleration = CreatureUtils.getAcceleration(parent); float acceleration = CreatureUtils.getAcceleration(parent);
@ -215,7 +218,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
break; break;
} }
// float movementYaw = CameraEntityUtils.getCameraYaw(Globals.playerCamera); // float movementYaw = CameraEntityUtils.getCameraYaw(Globals.playerCamera);
Quaterniond movementQuaternion = new Quaterniond().rotationTo(new Vector3d(0,0,1), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
//TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later) //TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later)
if(facingVector.length() == 0){ if(facingVector.length() == 0){
@ -229,11 +232,6 @@ public class ClientGroundMovementTree implements BehaviorTree {
long updateTime = message.gettime(); long updateTime = message.gettime();
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); // System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case MOVE:
position.set(message.getpositionX(), message.getpositionY(), message.getpositionZ());
break;
case SETFACING:
break;
case MOVEUPDATE: case MOVEUPDATE:
if(updateTime > lastUpdateTime){ if(updateTime > lastUpdateTime){
lastUpdateTime = updateTime; lastUpdateTime = updateTime;
@ -258,14 +256,13 @@ public class ClientGroundMovementTree implements BehaviorTree {
// System.out.println("Set state IDLE"); // System.out.println("Set state IDLE");
break; break;
} }
// System.out.println(EntityUtils.getEntityPosition(parent));
// System.out.println(message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
//this should only fire on the client, we don't want the server snap updating due to client position reporting //this should only fire on the client, we don't want the server snap updating due to client position reporting
// if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD){ lastServerPosition = new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ());
// EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); if(position.distance(lastServerPosition) > STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD){
// } else if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD){ EntityUtils.getPosition(parent).set(lastServerPosition);
// EntityUtils.getPosition(parent).add(new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()).mul(SOFT_UPDATE_MULTIPLIER)); } else if(position.distance(lastServerPosition) > STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD){
// } EntityUtils.getPosition(parent).lerp(lastServerPosition,SOFT_UPDATE_MULTIPLIER);
}
//we want to always update the server facing vector with where the client says they're facing //we want to always update the server facing vector with where the client says they're facing
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW()); EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
CollisionObjUtils.clientPositionCharacter(parent, position); CollisionObjUtils.clientPositionCharacter(parent, position);
@ -282,7 +279,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
//state machine //state machine
switch(state){ switch(state){
case STARTUP: case STARTUP: {
if(entityActor != null){ if(entityActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
@ -313,9 +310,8 @@ public class ClientGroundMovementTree implements BehaviorTree {
rotation.set(movementQuaternion); rotation.set(movementQuaternion);
GravityUtils.clientAttemptActivateGravity(parent); GravityUtils.clientAttemptActivateGravity(parent);
} break;
break; case MOVE: {
case MOVE:
//check if can restart animation //check if can restart animation
//if yes, restart animation //if yes, restart animation
if(entityActor != null){ if(entityActor != null){
@ -343,9 +339,8 @@ public class ClientGroundMovementTree implements BehaviorTree {
rotation.set(movementQuaternion); rotation.set(movementQuaternion);
GravityUtils.clientAttemptActivateGravity(parent); GravityUtils.clientAttemptActivateGravity(parent);
} break;
break; case SLOWDOWN: {
case SLOWDOWN:
//run slowdown code //run slowdown code
if(entityActor != null){ if(entityActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
@ -382,10 +377,13 @@ public class ClientGroundMovementTree implements BehaviorTree {
rotation.set(movementQuaternion); rotation.set(movementQuaternion);
GravityUtils.clientAttemptActivateGravity(parent); GravityUtils.clientAttemptActivateGravity(parent);
} break;
break; case IDLE: {
case IDLE: Vector3d playerPos = EntityUtils.getPosition(parent);
break; if(lastServerPosition != null && lastServerPosition.distance(playerPos) > STATE_DIFFERENCE_CREEP_CUTOFF){
playerPos.lerp(lastServerPosition,STATE_DIFFERENCE_CREEP_MULTIPLIER);
}
} break;
} }
} }
@ -710,4 +708,74 @@ public class ClientGroundMovementTree implements BehaviorTree {
return (ClientGroundMovementTree)entity.getData(EntityDataStrings.TREE_CLIENTGROUNDMOVEMENTTREE); return (ClientGroundMovementTree)entity.getData(EntityDataStrings.TREE_CLIENTGROUNDMOVEMENTTREE);
} }
/**
* <p>
* Gets the ClientGroundMovementTree of the entity
* </p>
* @param entity the entity
* @return The ClientGroundMovementTree
*/
public static ClientGroundMovementTree getClientGroundMovementTree(Entity entity){
return (ClientGroundMovementTree)entity.getData(EntityDataStrings.TREE_CLIENTGROUNDMOVEMENTTREE);
}
/**
* <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 getMovementRelativeFacingEnumAsShort(MovementRelativeFacing enumVal){
switch(enumVal){
case FORWARD:
return 0;
case LEFT:
return 1;
case RIGHT:
return 2;
case BACKWARD:
return 3;
case FORWARD_LEFT:
return 4;
case FORWARD_RIGHT:
return 5;
case BACKWARD_LEFT:
return 6;
case BACKWARD_RIGHT:
return 7;
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 MovementRelativeFacing getMovementRelativeFacingShortAsEnum(short shortVal){
switch(shortVal){
case 0:
return MovementRelativeFacing.FORWARD;
case 1:
return MovementRelativeFacing.LEFT;
case 2:
return MovementRelativeFacing.RIGHT;
case 3:
return MovementRelativeFacing.BACKWARD;
case 4:
return MovementRelativeFacing.FORWARD_LEFT;
case 5:
return MovementRelativeFacing.FORWARD_RIGHT;
case 6:
return MovementRelativeFacing.BACKWARD_LEFT;
case 7:
return MovementRelativeFacing.BACKWARD_RIGHT;
default:
return MovementRelativeFacing.FORWARD;
}
}
} }

View File

@ -1,17 +1,14 @@
package electrosphere.entity.state.movement.groundmove; package electrosphere.entity.state.movement.groundmove;
import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.gravity.GravityUtils; import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
@ -25,38 +22,28 @@ import electrosphere.entity.state.movement.ServerSprintTree;
import electrosphere.entity.state.movement.ServerSprintTree.SprintTreeState; import electrosphere.entity.state.movement.ServerSprintTree.SprintTreeState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState;
import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.anim.Animation; import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import electrosphere.renderer.actor.Actor; import electrosphere.util.MathUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.math.DVector3C; import org.ode4j.math.DVector3C;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
@SynchronizedBehaviorTree(name = "serverGroundMovementTree", isServer = false, correspondingTree="clientGroundMovementTree") @SynchronizedBehaviorTree(name = "serverGroundMovementTree", isServer = true, correspondingTree="clientGroundMovementTree")
/* /*
Behavior tree for movement in an entity Behavior tree for movement in an entity
*/ */
public class ServerGroundMovementTree implements BehaviorTree { public class ServerGroundMovementTree implements BehaviorTree {
static final double STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD = 1.0;
static final double STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD = 0.2;
static final double SOFT_UPDATE_MULTIPLIER = 0.1;
String animationStartUp = Animation.ANIMATION_MOVEMENT_STARTUP; String animationStartUp = Animation.ANIMATION_MOVEMENT_STARTUP;
String animationMain = Animation.ANIMATION_MOVEMENT_MOVE; String animationMain = Animation.ANIMATION_MOVEMENT_MOVE;
String animationSlowDown = Animation.ANIMATION_MOVEMENT_MOVE; String animationSlowDown = Animation.ANIMATION_MOVEMENT_MOVE;
@ -81,7 +68,7 @@ public class ServerGroundMovementTree implements BehaviorTree {
long lastUpdateTime = 0; long lastUpdateTime = 0;
public ServerGroundMovementTree(Entity e){ private ServerGroundMovementTree(Entity e){
state = MovementTreeState.IDLE; state = MovementTreeState.IDLE;
facing = MovementRelativeFacing.FORWARD; facing = MovementRelativeFacing.FORWARD;
parent = e; parent = e;
@ -91,6 +78,10 @@ public class ServerGroundMovementTree implements BehaviorTree {
return state; return state;
} }
/**
* Starts the server movement tree
* @param facing The facing dir to start with
*/
public void start(MovementRelativeFacing facing){ public void start(MovementRelativeFacing facing){
if(canStartMoving()){ if(canStartMoving()){
setFacing(facing); setFacing(facing);
@ -98,7 +89,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to walk forward //if we aren't the server, alert the server we intend to walk forward
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
@ -112,23 +102,29 @@ public class ServerGroundMovementTree implements BehaviorTree {
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
0 //magic number corresponding to state startup 0 //magic number corresponding to state startup
) )
); );
} }
} }
/**
* Interrupts the tree
*/
public void interrupt(){ public void interrupt(){
state = MovementTreeState.IDLE; state = MovementTreeState.IDLE;
CreatureUtils.setVelocity(parent, 0); CreatureUtils.setVelocity(parent, 0);
} }
/**
* Triggers the move tree to slow down
*/
public void slowdown(){ public void slowdown(){
state = MovementTreeState.SLOWDOWN; state = MovementTreeState.SLOWDOWN;
//if we aren't the server, alert the server we intend to slow down //if we aren't the server, alert the server we intend to slow down
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent); float velocity = CreatureUtils.getVelocity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
@ -142,11 +138,13 @@ public class ServerGroundMovementTree implements BehaviorTree {
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
2 //magic number corresponding to state slowdown 2 //magic number corresponding to state slowdown
) )
); );
} }
@Override
public void simulate(float deltaTime){ public void simulate(float deltaTime){
float velocity = 0; float velocity = 0;
float acceleration = 0; float acceleration = 0;
@ -156,7 +154,7 @@ public class ServerGroundMovementTree implements BehaviorTree {
acceleration = CreatureUtils.getAcceleration(parent); acceleration = CreatureUtils.getAcceleration(parent);
maxNaturalVelocity = sprintTree != null && sprintTree.getState() == SprintTreeState.SPRINTING ? sprintTree.getMaxVelocity() : CreatureUtils.getMaxNaturalVelocity(parent); maxNaturalVelocity = sprintTree != null && sprintTree.getState() == SprintTreeState.SPRINTING ? sprintTree.getMaxVelocity() : CreatureUtils.getMaxNaturalVelocity(parent);
} }
PoseActor entityPoseActor = EntityUtils.getPoseActor(parent); PoseActor poseActor = EntityUtils.getPoseActor(parent);
// Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent)); // Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent));
Vector3d position = EntityUtils.getPosition(parent); Vector3d position = EntityUtils.getPosition(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent); Vector3d facingVector = CreatureUtils.getFacingVector(parent);
@ -192,7 +190,7 @@ public class ServerGroundMovementTree implements BehaviorTree {
break; break;
} }
// float movementYaw = CameraEntityUtils.getCameraYaw(Globals.playerCamera); // float movementYaw = CameraEntityUtils.getCameraYaw(Globals.playerCamera);
Quaterniond movementQuaternion = new Quaterniond().rotationTo(new Vector3d(0,0,1), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
//TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later) //TODO: optimize away and document (I know for the moment if this exception isn't here it will bite me in the ass later)
if(facingVector.length() == 0){ if(facingVector.length() == 0){
@ -206,16 +204,23 @@ public class ServerGroundMovementTree implements BehaviorTree {
long updateTime = message.gettime(); long updateTime = message.gettime();
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); // System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case MOVE: {
} break;
case SETFACING:
break;
case MOVEUPDATE: { case MOVEUPDATE: {
if(updateTime >= lastUpdateTime){ if(updateTime >= lastUpdateTime){
lastUpdateTime = updateTime; lastUpdateTime = updateTime;
switch(message.gettreeState()){
//0 is startup
case 0: {
start(ClientGroundMovementTree.getMovementRelativeFacingShortAsEnum((short)message.getpropertyValueInt()));
} break;
case 2: {
slowdown();
} break;
default: {
} break;
}
//we want to always update the server facing vector with where the client says they're facing //we want to always update the server facing vector with where the client says they're facing
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW()); EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
CreatureUtils.setFacingVector(parent, new Vector3d(0,0,1).rotate(EntityUtils.getRotation(parent)));
break; break;
} }
} break; } break;
@ -228,16 +233,16 @@ public class ServerGroundMovementTree implements BehaviorTree {
//state machine //state machine
switch(state){ switch(state){
case STARTUP: case STARTUP: {
if(entityPoseActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && !poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay) &&
(jumpTree == null || !jumpTree.isJumping()) && (jumpTree == null || !jumpTree.isJumping()) &&
(fallTree == null || !fallTree.isFalling()) (fallTree == null || !fallTree.isFalling())
){ ){
entityPoseActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityPoseActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
//run startup code //run startup code
@ -266,33 +271,34 @@ public class ServerGroundMovementTree implements BehaviorTree {
GravityUtils.serverAttemptActivateGravity(parent); GravityUtils.serverAttemptActivateGravity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
parent.getId(), parent.getId(),
Globals.timekeeper.getNumberOfSimFramesElapsed(), Globals.timekeeper.getNumberOfSimFramesElapsed(),
position.x, position.x,
position.y, position.y,
position.z, position.z,
rotation.x, rotation.x,
rotation.y, rotation.y,
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
0 ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
) 0
)
); );
break; } break;
case MOVE: case MOVE: {
//check if can restart animation //check if can restart animation
//if yes, restart animation //if yes, restart animation
if(entityPoseActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && !poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay) &&
(jumpTree == null || !jumpTree.isJumping()) && (jumpTree == null || !jumpTree.isJumping()) &&
(fallTree == null || !fallTree.isFalling()) (fallTree == null || !fallTree.isFalling())
){ ){
entityPoseActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityPoseActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
if(velocity != maxNaturalVelocity){ if(velocity != maxNaturalVelocity){
@ -316,32 +322,33 @@ public class ServerGroundMovementTree implements BehaviorTree {
GravityUtils.serverAttemptActivateGravity(parent); GravityUtils.serverAttemptActivateGravity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
parent.getId(), parent.getId(),
Globals.timekeeper.getNumberOfSimFramesElapsed(), Globals.timekeeper.getNumberOfSimFramesElapsed(),
position.x, position.x,
position.y, position.y,
position.z, position.z,
rotation.x, rotation.x,
rotation.y, rotation.y,
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
1 ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
) 1
)
); );
break; } break;
case SLOWDOWN: case SLOWDOWN: {
//run slowdown code //run slowdown code
if(entityPoseActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if( if(
!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && !poseActor.isPlayingAnimation() || !poseActor.isPlayingAnimation(animationToPlay) &&
(jumpTree == null || !jumpTree.isJumping()) && (jumpTree == null || !jumpTree.isJumping()) &&
(fallTree == null || !fallTree.isFalling()) (fallTree == null || !fallTree.isFalling())
){ ){
entityPoseActor.playAnimation(animationToPlay,1); poseActor.playAnimation(animationToPlay,1);
entityPoseActor.incrementAnimationTime(0.0001); poseActor.incrementAnimationTime(0.0001);
} }
} }
//velocity stuff //velocity stuff
@ -350,10 +357,10 @@ public class ServerGroundMovementTree implements BehaviorTree {
if(velocity <= 0){ if(velocity <= 0){
velocity = 0; velocity = 0;
state = MovementTreeState.IDLE; state = MovementTreeState.IDLE;
if(entityPoseActor != null){ if(poseActor != null){
String animationToPlay = determineCorrectAnimation(); String animationToPlay = determineCorrectAnimation();
if(entityPoseActor.isPlayingAnimation() && entityPoseActor.isPlayingAnimation(animationToPlay)){ if(poseActor.isPlayingAnimation() && poseActor.isPlayingAnimation(animationToPlay)){
entityPoseActor.stopAnimation(animationToPlay); poseActor.stopAnimation(animationToPlay);
} }
} }
} }
@ -375,23 +382,24 @@ public class ServerGroundMovementTree implements BehaviorTree {
GravityUtils.serverAttemptActivateGravity(parent); GravityUtils.serverAttemptActivateGravity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage( EntityMessage.constructmoveUpdateMessage(
parent.getId(), parent.getId(),
Globals.timekeeper.getNumberOfSimFramesElapsed(), Globals.timekeeper.getNumberOfSimFramesElapsed(),
position.x, position.x,
position.y, position.y,
position.z, position.z,
rotation.x, rotation.x,
rotation.y, rotation.y,
rotation.z, rotation.z,
rotation.w, rotation.w,
velocity, velocity,
2 ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing),
) 2
)
); );
break; } break;
case IDLE: case IDLE: {
break; } break;
} }
} }
@ -667,6 +675,8 @@ public class ServerGroundMovementTree implements BehaviorTree {
*/ */
public void setFacing(MovementRelativeFacing facing){ public void setFacing(MovementRelativeFacing facing){
this.facing = facing; this.facing = facing;
int value = ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(facing);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), 9, 11, value));
} }
/** /**

View File

@ -0,0 +1,85 @@
package electrosphere.entity.state.server;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.types.creature.CreatureUtils;
/**
* Stores the direction that the server thinks the player is looking
*/
public class ServerPlayerViewDirTree implements BehaviorTree {
//the direction of the view
Vector3d playerViewDir = new Vector3d();
//the last time this value was updated
long lastUpdateTime = 0;
//the parent entity
Entity parent;
@Override
public void simulate(float deltaTime) {
}
/**
* Constructor
* @param parent
*/
private ServerPlayerViewDirTree(Entity parent){
this.parent = parent;
}
/**
* Attaches a ServerPlayerViewDirTree to a given entity
* @param entity The entity to add to
*/
public static void attachServerPlayerViewDirTree(Entity entity){
ServerPlayerViewDirTree tree = new ServerPlayerViewDirTree(entity);
entity.putData(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR, tree);
}
/**
* Gets the server player view dir tree if it exists
* @param entity The entity to get from
* @return The ServerPlayerViewDirTree if it exists, null otherwise
*/
public static ServerPlayerViewDirTree getTree(Entity entity){
return (ServerPlayerViewDirTree)entity.getData(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR);
}
/**
* Checks whether the entity has a copy of this btree or not
* @param entity The entity
* @return true if the entity has the btree, false otherwise
*/
public static boolean hasTree(Entity entity){
return entity.containsKey(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR);
}
/**
* Gets the player view dir
* @return The player view dir
*/
public Vector3d getPlayerViewDir(){
return playerViewDir;
}
/**
* Sets the player view dir vector
* @param playerViewDir The player view dir vector
*/
public void setPlayerViewDir(Vector3d playerViewDir, long time){
if(time > lastUpdateTime){
this.playerViewDir = playerViewDir;
this.lastUpdateTime = time;
CreatureUtils.setFacingVector(parent, new Vector3d(-playerViewDir.x,0,-playerViewDir.z));
}
}
}

View File

@ -7,10 +7,10 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.ServerEntityTagUtils; import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import electrosphere.util.MathUtils;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -18,10 +18,8 @@ import java.util.List;
import org.joml.Matrix4d; import org.joml.Matrix4d;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector4d;
/** /**
* Utilities for attaching entities to entities * Utilities for attaching entities to entities
@ -39,7 +37,28 @@ public class AttachUtils {
// FUNCTIONS TO UPDATE ATTACHMENTS FOR CURRENT FRAME // FUNCTIONS TO UPDATE ATTACHMENTS FOR CURRENT FRAME
// //
///
///
/// SERVER
///
///
/**
* Updates positions of all attached entities in a data cell
* @param cell The data cell
*/
public static void serverUpdateAttachedEntityPositions(ServerDataCell cell){ public static void serverUpdateAttachedEntityPositions(ServerDataCell cell){
Globals.profiler.beginCpuSample("AttachUtils.serverUpdateAttachedEntityPositions");
serverUpdateBoneAttachedEntityPositions(cell);
serverUpdateNonBoneAttachments(cell);
Globals.profiler.endCpuSample();
}
/**
* Updates entities attached to bones of actors in a data cell
* @param cell The data cell
*/
public static void serverUpdateBoneAttachedEntityPositions(ServerDataCell cell){
for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){ for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){
Entity parent; Entity parent;
if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
@ -63,30 +82,102 @@ public class AttachUtils {
Vector3d facingAngle = CreatureUtils.getFacingVector(parent); Vector3d facingAngle = CreatureUtils.getFacingVector(parent);
//calculate rotation of model //calculate rotation of model
EntityUtils.getRotation(currentEntity) EntityUtils.getRotation(currentEntity)
.rotationTo(new Vector3d(0,0,1), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z)) .rotationTo(MathUtils.getOriginVector(), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z))
.mul(parentActor.getBoneRotation(targetBone)) .mul(parentActor.getBoneRotation(targetBone))
.mul(offsetRotation) .mul(offsetRotation)
.normalize(); .normalize();
} }
} else if(currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BASE)!=null){
Vector3d positionOffset = getAttachPositionOffset(currentEntity);
Vector3d parentPosition = EntityUtils.getPosition(parent);
EntityUtils.getPosition(currentEntity).set(new Vector3d(parentPosition).add(positionOffset));
} }
} }
} }
/**
* Updates entities that aren't attached to a bone directly in a data cell
* @param cell the data cell
*/
private static void serverUpdateNonBoneAttachments(ServerDataCell cell){
Globals.profiler.beginCpuSample("AttachUtils.serverUpdateNonBoneAttachments");
Matrix4d parentTransform = new Matrix4d().identity();
Vector3d position = new Vector3d();
Quaterniond rotation = new Quaterniond();
Vector3d scaleRaw = new Vector3d();
Vector3f scale = new Vector3f();
Entity parent;
Matrix4f transform;
//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){
//parent objects
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f parentScale = EntityUtils.getScale(parent);
// calculate new transform for current entity
parentTransform.identity()
.translate(parentPosition)
.rotate(parentRotation)
.scale(parentScale.x,parentScale.y,parentScale.z)
.mul(transform);
//transform bone space
parentTransform.getTranslation(position);
parentTransform.getUnnormalizedRotation(rotation).normalize();
parentTransform.getScale(scaleRaw);
scale.set((float)scaleRaw.x,(float)scaleRaw.y,(float)scaleRaw.z);
//transform worldspace
// position.add(new Vector3d(EntityUtils.getPosition(parent)));
//set
EntityUtils.getPosition(currentEntity).set(position);
EntityUtils.getRotation(currentEntity).set(rotation);
EntityUtils.getScale(currentEntity).set(scale);
}
}
}
Globals.profiler.endCpuSample();
}
///
///
/// CLIENT
///
///
/** /**
* Client version of attachment update functions * Client version of attachment update functions
*/ */
public static void clientUpdateAttachedEntityPositions(){ public static void clientUpdateAttachedEntityPositions(){
Globals.profiler.beginCpuSample("AttachUtils.clientUpdateAttachedEntityPositions"); Globals.profiler.beginCpuSample("AttachUtils.clientUpdateAttachedEntityPositions");
updateBoneAttachments(); clientUpdateBoneAttachments();
updateNonBoneAttachments(); clientUpdateNonBoneAttachments();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
/** /**
* Updates entities attached to bones * Updates entities attached to bones
*/ */
private static void updateBoneAttachments(){ private static void clientUpdateBoneAttachments(){
Globals.profiler.beginCpuSample("AttachUtils.updateBoneAttachments"); Globals.profiler.beginCpuSample("AttachUtils.clientUpdateBoneAttachments");
//update entities attached to bones of other entities //update entities attached to bones of other entities
for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){ for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){
Entity parent; Entity parent;
@ -110,11 +201,11 @@ public class AttachUtils {
// EntityUtils.getRotation(currentEntity).set(rotation).normalize(); // EntityUtils.getRotation(currentEntity).set(rotation).normalize();
Vector3d facingAngle = CreatureUtils.getFacingVector(parent); Vector3d facingAngle = CreatureUtils.getFacingVector(parent);
if(facingAngle == null){ if(facingAngle == null){
facingAngle = new Vector3d(0,0,1); facingAngle = MathUtils.getOriginVector();
} }
//calculate rotation of model //calculate rotation of model
EntityUtils.getRotation(currentEntity) EntityUtils.getRotation(currentEntity)
.rotationTo(new Vector3d(0,0,1), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z)) .rotationTo(MathUtils.getOriginVector(), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z))
.mul(parentActor.getBoneRotation(targetBone)) .mul(parentActor.getBoneRotation(targetBone))
.mul(offsetRotation) .mul(offsetRotation)
.normalize(); .normalize();
@ -128,7 +219,10 @@ public class AttachUtils {
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
private static void updateNonBoneAttachments(){ /**
* Updates entities that aren't attached to a bone directly
*/
private static void clientUpdateNonBoneAttachments(){
Globals.profiler.beginCpuSample("AttachUtils.updateNonBoneAttachments"); Globals.profiler.beginCpuSample("AttachUtils.updateNonBoneAttachments");
Matrix4d parentTransform = new Matrix4d().identity(); Matrix4d parentTransform = new Matrix4d().identity();
Vector3d position = new Vector3d(); Vector3d position = new Vector3d();
@ -212,6 +306,13 @@ public class AttachUtils {
} }
/**
* Attaches an entity to another entity at a given bone
* @param parent The parent entity
* @param toAttach The entity that will be attached
* @param boneName The name of the bone
* @param rotation The rotation applied
*/
public static void clientAttachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName, Quaterniond rotation){ public static void clientAttachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName, Quaterniond rotation){
Globals.clientSceneWrapper.getScene().registerEntityToTag(toAttach, EntityTags.BONE_ATTACHED); Globals.clientSceneWrapper.getScene().registerEntityToTag(toAttach, EntityTags.BONE_ATTACHED);
toAttach.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true); toAttach.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true);
@ -334,6 +435,11 @@ public class AttachUtils {
// FUNCTIONS TO DETATCH AN ENTITY // FUNCTIONS TO DETATCH AN ENTITY
// //
/**
* Detatches an entity on the server
* @param parent The parent entity
* @param toAttach The attached entity
*/
public static void serverDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){ public static void serverDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){
ServerEntityTagUtils.removeTagFromEntity(toAttach, EntityTags.BONE_ATTACHED); ServerEntityTagUtils.removeTagFromEntity(toAttach, EntityTags.BONE_ATTACHED);
toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED); toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);
@ -344,6 +450,11 @@ public class AttachUtils {
} }
} }
/**
* Detatches an entity on the client
* @param parent The parent entity
* @param toAttach The attached entity
*/
public static void clientDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){ public static void clientDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(toAttach, EntityTags.BONE_ATTACHED); Globals.clientSceneWrapper.getScene().removeEntityFromTag(toAttach, EntityTags.BONE_ATTACHED);
toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED); toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);
@ -385,6 +496,11 @@ public class AttachUtils {
// GETTERS // GETTERS
// //
/**
* Checks whether this entity is attached to another entity or not
* @param e The entity
* @return true if attached, false otherwise
*/
public static boolean isAttached(Entity e){ public static boolean isAttached(Entity e){
return e.containsKey(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED); return e.containsKey(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);
} }
@ -397,10 +513,24 @@ public class AttachUtils {
return (Entity)e.getData(EntityDataStrings.ATTACH_PARENT); return (Entity)e.getData(EntityDataStrings.ATTACH_PARENT);
} }
/**
* Gets the rotation offset of a given entity
* @param e The entity
* @return The rotation offset
*/
protected static Quaterniond getRotationOffset(Entity e){ protected static Quaterniond getRotationOffset(Entity e){
return (Quaterniond)e.getData(EntityDataStrings.ATTACH_ROTATION_OFFSET); return (Quaterniond)e.getData(EntityDataStrings.ATTACH_ROTATION_OFFSET);
} }
/**
* Sets the attached rotation offset
* @param e the attached entity
* @param rotation The rotation offset
*/
public static void setRotationOffset(Entity e, Quaterniond rotation){
e.putData(EntityDataStrings.ATTACH_ROTATION_OFFSET, rotation);
}
/** /**
* Gets the transform for a transform attached entity * Gets the transform for a transform attached entity
* @param e The entity * @param e The entity

View File

@ -12,6 +12,7 @@ import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils; import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityCreationUtils;
@ -29,7 +30,8 @@ import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.equip.ServerEquipState; import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.gravity.ClientGravityTree; import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree; import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.entity.state.idle.ServerIdleTree; import electrosphere.entity.state.idle.ServerIdleTree;
import electrosphere.entity.state.inventory.ClientInventoryState; import electrosphere.entity.state.inventory.ClientInventoryState;
import electrosphere.entity.state.inventory.InventoryUtils; import electrosphere.entity.state.inventory.InventoryUtils;
@ -50,9 +52,8 @@ import electrosphere.entity.state.rotator.RotatorHierarchyNode;
import electrosphere.entity.state.rotator.RotatorTree; import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.state.rotator.ServerRotatorTree; import electrosphere.entity.state.rotator.ServerRotatorTree;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.hitbox.HitboxData;
import electrosphere.entity.types.hitbox.HitboxUtils;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.creature.type.CreatureType; import electrosphere.game.data.creature.type.CreatureType;
import electrosphere.game.data.creature.type.SprintSystem; import electrosphere.game.data.creature.type.SprintSystem;
import electrosphere.game.data.creature.type.attack.AttackMove; import electrosphere.game.data.creature.type.attack.AttackMove;
@ -80,6 +81,7 @@ import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.datacell.utils.ServerEntityTagUtils; import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseActorUtils; import electrosphere.server.poseactor.PoseActorUtils;
import electrosphere.util.MathUtils;
import electrosphere.util.Utilities; import electrosphere.util.Utilities;
/** /**
@ -103,26 +105,26 @@ public class CreatureUtils {
Actor creatureActor = EntityUtils.getActor(rVal); Actor creatureActor = EntityUtils.getActor(rVal);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE); EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE);
EntityUtils.setEntitySubtype(rVal, type); EntityUtils.setEntitySubtype(rVal, type);
for(HitboxData hitboxdata : rawType.getHitboxes()){
List<Entity> hitboxList = new LinkedList<Entity>();
List<Entity> hurtboxList = new LinkedList<Entity>(); ///
if(hitboxdata.getType().equals("hit")){ ///
Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); /// HITBOX DATA
Globals.clientHitboxManager.registerHitbox(hitbox); ///
hitboxList.add(hitbox); ///
} else if(hitboxdata.getType().equals("hurt")){ HitboxCollectionState.attachHitboxState(Globals.clientSceneWrapper.getHitboxManager(), false, rVal, rawType.getHitboxes());
Entity hurtbox = HitboxUtils.clientSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
Globals.clientHitboxManager.registerHitbox(hurtbox);
hurtboxList.add(hurtbox); //
} //
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList); // PHYSICS
rVal.putData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST, hurtboxList); //
} //
//Physics object
if(rawType.getCollidable() != null){ if(rawType.getCollidable() != null){
CollidableTemplate physicsTemplate = rawType.getCollidable(); CollidableTemplate physicsTemplate = rawType.getCollidable();
PhysicsEntityUtils.clientAttachCollidableTemplate(rVal, physicsTemplate); PhysicsEntityUtils.clientAttachCollidableTemplate(rVal, physicsTemplate);
} }
// //
// //
// MOVEMENT SYSTEMS // MOVEMENT SYSTEMS
@ -165,7 +167,7 @@ public class CreatureUtils {
} }
//round out end of move system //round out end of move system
rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, moveTree); rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, moveTree);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity());
rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration());
rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f);
@ -217,14 +219,14 @@ public class CreatureUtils {
airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed()); airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed());
//register misc stuff //register misc stuff
rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, airplaneMovementTree); rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, airplaneMovementTree);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
Globals.clientScene.registerBehaviorTree(airplaneMovementTree); Globals.clientScene.registerBehaviorTree(airplaneMovementTree);
Globals.clientScene.registerEntityToTag(rVal, EntityTags.MOVEABLE); Globals.clientScene.registerEntityToTag(rVal, EntityTags.MOVEABLE);
} break; } break;
} }
} }
if(rawType.getEquipPoints() != null && rawType.getEquipPoints().size() > 0){ if(rawType.getEquipPoints() != null && rawType.getEquipPoints().size() > 0){
ClientEquipState.setEquipState(rVal, new ClientEquipState(rVal,rawType.getEquipPoints())); ClientEquipState.attachTree(rVal, rawType.getEquipPoints());
rVal.putData(EntityDataStrings.EQUIP_INVENTORY, RelationalInventoryState.buildRelationalInventoryStateFromEquipList(rawType.getEquipPoints())); rVal.putData(EntityDataStrings.EQUIP_INVENTORY, RelationalInventoryState.buildRelationalInventoryStateFromEquipList(rawType.getEquipPoints()));
} }
for(String token : rawType.getTokens()){ for(String token : rawType.getTokens()){
@ -366,11 +368,11 @@ public class CreatureUtils {
rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem()));
Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIFE_STATE); Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIFE_STATE);
//idle tree & generic stuff all creatures have //idle tree & generic stuff all creatures have
IdleTree idleTree = new IdleTree(rVal); ClientIdleTree idleTree = new ClientIdleTree(rVal);
rVal.putData(EntityDataStrings.TREE_IDLE, idleTree); rVal.putData(EntityDataStrings.TREE_IDLE, idleTree);
Globals.clientScene.registerBehaviorTree(idleTree); Globals.clientScene.registerBehaviorTree(idleTree);
Globals.clientScene.registerEntityToTag(rVal, EntityTags.CREATURE); Globals.clientScene.registerEntityToTag(rVal, EntityTags.CREATURE);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
return rVal; return rVal;
} }
@ -390,21 +392,17 @@ public class CreatureUtils {
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());
PoseActor creatureActor = EntityUtils.getPoseActor(rVal); PoseActor creatureActor = EntityUtils.getPoseActor(rVal);
for(HitboxData hitboxdata : rawType.getHitboxes()){ //
List<Entity> hitboxList = new LinkedList<Entity>(); //
List<Entity> hurtboxList = new LinkedList<Entity>(); // Hitbox stuff
if(hitboxdata.getType().equals("hit")){ //
Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); //
realm.getHitboxManager().registerHitbox(hitbox); HitboxCollectionState.attachHitboxState(realm.getHitboxManager(), true, rVal, rawType.getHitboxes());
hitboxList.add(hitbox); //
} else if(hitboxdata.getType().equals("hurt")){ //
Entity hurtbox = HitboxUtils.serverSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); // Physics stuff
realm.getHitboxManager().registerHitbox(hurtbox); //
hurtboxList.add(hurtbox); //
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList);
rVal.putData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST, hurtboxList);
}
if(rawType.getCollidable() != null){ if(rawType.getCollidable() != null){
CollidableTemplate physicsTemplate = rawType.getCollidable(); CollidableTemplate physicsTemplate = rawType.getCollidable();
PhysicsEntityUtils.serverAttachCollidableTemplate(realm, rVal, physicsTemplate); PhysicsEntityUtils.serverAttachCollidableTemplate(realm, rVal, physicsTemplate);
@ -451,7 +449,7 @@ public class CreatureUtils {
} }
//round out end of move system //round out end of move system
rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, moveTree); rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, moveTree);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity());
rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration());
rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f);
@ -509,7 +507,7 @@ public class CreatureUtils {
airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed()); airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed());
//register misc stuff //register misc stuff
rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, airplaneMovementTree); rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, airplaneMovementTree);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, airplaneMovementTree); ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, airplaneMovementTree);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.MOVEABLE); ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.MOVEABLE);
} break; } break;
@ -664,7 +662,7 @@ public class CreatureUtils {
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.CREATURE); ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.CREATURE);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE); EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE);
EntityUtils.setEntitySubtype(rVal, type); EntityUtils.setEntitySubtype(rVal, type);
CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
//position entity //position entity
@ -799,8 +797,8 @@ public class CreatureUtils {
return (ServerAttackTree)e.getData(EntityDataStrings.TREE_SERVERATTACKTREE); return (ServerAttackTree)e.getData(EntityDataStrings.TREE_SERVERATTACKTREE);
} }
public static IdleTree getIdleTree(Entity e){ public static ClientIdleTree getIdleTree(Entity e){
return (IdleTree)e.getData(EntityDataStrings.TREE_IDLE); return (ClientIdleTree)e.getData(EntityDataStrings.TREE_IDLE);
} }
public static SprintTree clientGetSprintTree(Entity e){ public static SprintTree clientGetSprintTree(Entity e){

View File

@ -12,7 +12,7 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.client.ambientaudio.ClientAmbientAudioTree; import electrosphere.entity.state.client.ambientaudio.ClientAmbientAudioTree;
import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.tree.ProceduralTree; import electrosphere.entity.types.tree.ProceduralTree;
import electrosphere.game.data.foliage.type.AmbientAudio; import electrosphere.game.data.foliage.type.AmbientAudio;

View File

@ -1,83 +0,0 @@
package electrosphere.entity.types.hitbox;
import java.util.List;
import electrosphere.entity.Entity;
import electrosphere.entity.types.hitbox.HitboxUtils.HitboxPositionCallback;
public class HitboxData {
String type;
String bone;
float radius;
boolean active = false;
//used for more advanced hitbox spawning to find hitbox position on frame update
HitboxPositionCallback positionCallback;
//used to filter this hitbox to hitting only certain parent entities
List<Entity> filter;
public String getType() {
return type;
}
public String getBone() {
return bone;
}
public float getRadius() {
return radius;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public void setBone(String bone) {
this.bone = bone;
}
public void setType(String type) {
this.type = type;
}
public void setRadius(float radius) {
this.radius = radius;
}
/**
* Gets the position callback
* @return The position callback
*/
public HitboxPositionCallback getPositionCallback(){
return positionCallback;
}
/**
* Sets the position callback
* @param positionCallback The position callback
*/
public void setPositionCallback(HitboxPositionCallback positionCallback){
this.positionCallback = positionCallback;
}
/**
* Sets an entity filter on the hitbox
* @param filter The list of parent entities to exclude from collisions
*/
public void setEntityFilter(List<Entity> filter){
this.filter = filter;
}
/**
* Gets the entity filter
* @return The list of parent entities to exclude from collisions
*/
public List<Entity> getEntityFilter(){
return filter;
}
}

View File

@ -1,35 +0,0 @@
package electrosphere.entity.types.hitbox;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
*
* @author amaterasu
*/
public class HitboxManager {
CopyOnWriteArrayList<Entity> hitboxes = new CopyOnWriteArrayList<Entity>();
long idIncrementer = 0;
public HitboxManager(){
}
public void registerHitbox(Entity hitbox){
hitboxes.add(hitbox);
idIncrementer++;
hitbox.putData(EntityDataStrings.COLLISION_ENTITY_ID, idIncrementer);
}
public CopyOnWriteArrayList<Entity> getAllHitboxes(){
return hitboxes;
}
public void deregisterHitbox(Entity hitbox){
hitboxes.remove(hitbox);
}
}

View File

@ -1,447 +0,0 @@
package electrosphere.entity.types.hitbox;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.state.attack.ShooterTree;
import electrosphere.entity.state.life.LifeState;
import electrosphere.entity.state.life.LifeUtils;
import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.game.server.effects.ParticleEffects;
import electrosphere.server.datacell.Realm;
import java.util.List;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
/**
*
* @author amaterasu
*/
public class HitboxUtils {
/**
* Spawns a hitbox entity on the client
* @param parent The parent entity to attach the hitbox to
* @param bone The bone on the parent to attach to
* @param size The radius of the hitsphere
* @return The hitbox entity
*/
public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(false);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
/**
* Spawns a hitbox entity on the server
* @param parent The parent entity to attach the hitbox to
* @param bone The bone to attach to the hitbox to
* @param size The radius of the hitsphere
* @return The hitbox entity
*/
public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(false);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
/**
* Spawns a hurtbox on the client
* @param parent The parent entity of the hurtbox
* @param bone The bone on the parent to attach the hurtbox to
* @param size The radius of the hurtsphere
* @return The hurtbox entity
*/
public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(true);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
/**
* Spawns a hurtbox on the server
* @param parent The parent entity of the hurtbox
* @param bone The bone on the parent to attach the hurtbox to
* @param size The radius of the hurtsphere
* @return The hurtbox entity
*/
public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(true);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
/**
* More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
* @param parent The parent entity of the hitbox
* @param positionCallback The position callback for keeping hitbox entity position up to date
* @param size The size of the hitbox
* @param hurtbox If true, it will instead be a hurtbox
* @param filter an optional list of parent entities to not colide with
* @return The hitbox entity
*/
public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(true);
data.setPositionCallback(positionCallback);
data.setRadius(size);
data.setEntityFilter(filter);
if(hurtbox){
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
} else {
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
}
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
/**
* More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
* @param parent The parent entity of the hitbox
* @param positionCallback The position callback for keeping hitbox entity position up to date
* @param size The size of the hitbox
* @param hurtbox If true, it will instead be a hurtbox
* @param filter an optional list of parent entities to not colide with
* @return The hitbox entity
*/
public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(true);
data.setPositionCallback(positionCallback);
data.setRadius(size);
data.setEntityFilter(filter);
if(hurtbox){
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
} else {
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
}
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
public static void clientUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
public static void serverUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3d(parentPos.x,parentPos.y,parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
public static void clientCollideEntities(Entity generatorHitbox){
// long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID);
//This is the entity the hitbox is attached to
Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
for(Entity receiverHitbox : Globals.clientHitboxManager.getAllHitboxes()){
Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
HitboxData generatorData = getHitboxData(generatorHitbox);
HitboxData receiverData = getHitboxData(receiverHitbox);
//check projectile filters
List<Entity> generatorFilter = generatorData.getEntityFilter();
if(generatorFilter != null && generatorFilter.contains(receiverParent)){
continue;
}
List<Entity> receiverFilter = receiverData.getEntityFilter();
if(receiverFilter != null && receiverFilter.contains(generatorParent)){
continue;
}
//if there is a collision
//and the collision isn't against itself
//and both hitboxes are active
if(
receiverParent != generatorParent &&
Globals.clientSceneWrapper.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) &&
generatorData.isActive() &&
receiverData.isActive()){
//if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc)
String generatorType = generatorData.getType();
String receiverType = receiverData.getType();
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
clientDamageHitboxColision(generatorHitbox, receiverHitbox);
}
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
clientDamageHitboxColision(receiverHitbox, generatorHitbox);
}
}
}
}
public static void serverCollideEntities(Entity generatorHitbox){
// long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID);
//This is the entity the hitbox is attached to
Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Realm generatorRealm = Globals.realmManager.getEntityRealm(generatorParent);
if(generatorRealm != null){
HitboxManager realmHitboxManager = generatorRealm.getHitboxManager();
for(Entity receiverHitbox : realmHitboxManager.getAllHitboxes()){
Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
HitboxData generatorData = getHitboxData(generatorHitbox);
HitboxData receiverData = getHitboxData(receiverHitbox);
//check projectile filters
List<Entity> generatorFilter = generatorData.getEntityFilter();
if(generatorFilter != null && generatorFilter.contains(receiverParent)){
continue;
}
List<Entity> receiverFilter = receiverData.getEntityFilter();
if(receiverFilter != null && receiverFilter.contains(generatorParent)){
continue;
}
//if there is a collision
//and the collision isn't against itself
//and both hitboxes are active
if(
receiverParent != generatorParent &&
generatorRealm.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) &&
generatorData.isActive() &&
receiverData.isActive()){
//if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc)
String generatorType = generatorData.getType();
String receiverType = receiverData.getType();
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
serverDamageHitboxColision(generatorHitbox, receiverHitbox);
}
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
serverDamageHitboxColision(receiverHitbox, generatorHitbox);
}
}
}
}
}
public static void clientDamageHitboxColision(Entity hitbox, Entity hurtbox){
Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
if(isItem){
if(hitboxAttachParent != hurtboxParent){
LifeState lifeState = LifeUtils.getLifeState(hurtboxParent);
int currentHp = lifeState.getLifeCurrent();
int damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(currentHp > lifeState.getLifeCurrent()){
Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox);
ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
}
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
} else {
int damage = 0;
//for entities using attacktree
if(CreatureUtils.clientGetAttackTree(hitboxParent) != null){
damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
} else {
//for entities using shooter tree
if(ProjectileTree.getProjectileTree(hitboxParent) != null){
damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
}
}
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
}
public static void serverDamageHitboxColision(Entity hitbox, Entity hurtbox){
Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
if(isItem){
if(hitboxAttachParent != hurtboxParent){
LifeState lifeState = LifeUtils.getLifeState(hurtboxParent);
int currentHp = lifeState.getLifeCurrent();
int damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(currentHp > lifeState.getLifeCurrent()){
Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox);
ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
}
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
} else {
int damage = 0;
//for entities using attacktree
if(CreatureUtils.serverGetAttackTree(hitboxParent) != null){
damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
} else {
//for entities using shooter tree
if(ProjectileTree.getProjectileTree(hitboxParent) != null){
damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
}
}
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
}
public static HitboxData getHitboxData(Entity e){
return (HitboxData)e.getData(EntityDataStrings.HITBOX_DATA);
}
public static List<Entity> getHitboxAssociatedList(Entity e){
return (List<Entity>)e.getData(EntityDataStrings.HITBOX_ASSOCIATED_LIST);
}
public static List<Entity> getHurtboxAssociatedList(Entity e){
return (List<Entity>)e.getData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST);
}
/**
* Intended to be implemented as an anonoymous class when needed
*/
public interface HitboxPositionCallback {
/**
* Gets the current position this hitbox should be at
* @return The position this hitbox should be at
*/
public Vector3d getPosition();
}
}

View File

@ -14,6 +14,7 @@ import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils; import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityCreationUtils;
@ -25,9 +26,9 @@ import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.gravity.ClientGravityTree; import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree; import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.types.hitbox.HitboxData; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.types.hitbox.HitboxUtils;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.item.type.EquipWhitelist; import electrosphere.game.data.item.type.EquipWhitelist;
import electrosphere.game.data.item.type.Item; import electrosphere.game.data.item.type.Item;
import electrosphere.game.data.item.type.WeaponData; import electrosphere.game.data.item.type.WeaponData;
@ -39,6 +40,7 @@ import electrosphere.renderer.actor.ActorUtils;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.datacell.utils.ServerEntityTagUtils; import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor;
/** /**
* Utilities for working with items * Utilities for working with items
@ -59,13 +61,7 @@ public class ItemUtils {
rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true); rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true);
WeaponData weaponData = item.getWeaponData(); WeaponData weaponData = item.getWeaponData();
if(weaponData.getHitboxes() != null){ if(weaponData.getHitboxes() != null){
List<Entity> hitboxList = new LinkedList<Entity>(); HitboxCollectionState.attachHitboxState(Globals.clientSceneWrapper.getHitboxManager(), false, rVal, weaponData.getHitboxes());
for(HitboxData hitboxdata : weaponData.getHitboxes()){
Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
Globals.clientHitboxManager.registerHitbox(hitbox);
hitboxList.add(hitbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList);
} }
rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass()); rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass());
rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData); rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData);
@ -138,13 +134,7 @@ public class ItemUtils {
rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true); rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true);
WeaponData weaponData = item.getWeaponData(); WeaponData weaponData = item.getWeaponData();
if(weaponData.getHitboxes() != null){ if(weaponData.getHitboxes() != null){
List<Entity> hitboxList = new LinkedList<Entity>(); HitboxCollectionState.attachHitboxState(realm.getHitboxManager(), true, rVal, weaponData.getHitboxes());
for(HitboxData hitboxdata : weaponData.getHitboxes()){
Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
realm.getHitboxManager().registerHitbox(hitbox);
hitboxList.add(hitbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList);
} }
rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass()); rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass());
rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData); rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData);
@ -233,12 +223,32 @@ public class ItemUtils {
} }
} }
/**
* Updates an item to play its idle animation
* @param item THe item entity
*/
public static void updateItemActorAnimation(Entity item){ public static void updateItemActorAnimation(Entity item){
Actor actor = EntityUtils.getActor(item); Actor actor = EntityUtils.getActor(item);
if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){ if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){
String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE); String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE);
if(!actor.isPlayingAnimation(idleAnim)){ if(!actor.isPlayingAnimation(idleAnim)){
actor.playAnimation(idleAnim,1); actor.playAnimation(idleAnim,1);
actor.incrementAnimationTime(0.0001);
}
}
}
/**
* Updates the item's pose actor to play its idle animation on the server
* @param item The item entity
*/
public static void updateItemPoseActorAnimation(Entity item){
PoseActor actor = EntityUtils.getPoseActor(item);
if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){
String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE);
if(!actor.isPlayingAnimation(idleAnim)){
actor.playAnimation(idleAnim,1);
actor.incrementAnimationTime(0.0001);
} }
} }
} }
@ -378,13 +388,7 @@ public class ItemUtils {
//this deregisters from all four & unhooks rigid bodies from the physics runtime //this deregisters from all four & unhooks rigid bodies from the physics runtime
Globals.clientSceneWrapper.getCollisionEngine().destroyEntityThatHasPhysics(item); Globals.clientSceneWrapper.getCollisionEngine().destroyEntityThatHasPhysics(item);
//destroy hitboxes //destroy hitboxes
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(item); HitboxCollectionState.destroyHitboxState(item);
if(hitboxes != null){
for(Entity hitbox : hitboxes){
Globals.clientHitboxManager.deregisterHitbox(hitbox);
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
//destroy graphics //destroy graphics
EntityUtils.cleanUpEntity(item); EntityUtils.cleanUpEntity(item);
} }
@ -401,13 +405,7 @@ public class ItemUtils {
if(itemRealm != null){ if(itemRealm != null){
itemRealm.getCollisionEngine().destroyEntityThatHasPhysics(item); itemRealm.getCollisionEngine().destroyEntityThatHasPhysics(item);
//destroy hitboxes //destroy hitboxes
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(item); HitboxCollectionState.destroyHitboxState(item);
if(hitboxes != null){
for(Entity hitbox : hitboxes){
itemRealm.getHitboxManager().deregisterHitbox(hitbox);
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
} }
//destroy graphics //destroy graphics
EntityUtils.cleanUpEntity(item); EntityUtils.cleanUpEntity(item);

View File

@ -22,7 +22,9 @@ import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.gravity.ClientGravityTree; import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree; import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.entity.state.idle.ServerIdleTree;
import electrosphere.entity.state.inventory.ClientInventoryState; import electrosphere.entity.state.inventory.ClientInventoryState;
import electrosphere.entity.state.inventory.InventoryUtils; import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.ServerInventoryState; import electrosphere.entity.state.inventory.ServerInventoryState;
@ -44,11 +46,17 @@ public class ObjectUtils {
//the entity type value //the entity type value
public static final int ENTITY_TYPE_OBJECT = 2; public static final int ENTITY_TYPE_OBJECT = 2;
/**
* Spawns an object in the client scene
* @param type The type of object
* @return The object entity
*/
public static Entity clientSpawnBasicObject(String type){ public static Entity clientSpawnBasicObject(String type){
ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type);
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); if(rawType.getModelPath() != null){
Actor creatureActor = EntityUtils.getActor(rVal); EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath());
}
//forward-searching tokens //forward-searching tokens
boolean collisionMakeDynamic = true; boolean collisionMakeDynamic = true;
for(String token : rawType.getTokens()){ for(String token : rawType.getTokens()){
@ -112,11 +120,14 @@ public class ObjectUtils {
} break; } break;
} }
} }
if(rawType.getHitboxData() != null){
HitboxCollectionState.attachHitboxState(Globals.clientSceneWrapper.getHitboxManager(), false, rVal, rawType.getHitboxData());
}
//add health system //add health system
// rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); // rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem()));
// Globals.entityManager.registerLifeStateEntity(rVal); // Globals.entityManager.registerLifeStateEntity(rVal);
//idle tree & generic stuff all objects have //idle tree & generic stuff all objects have
rVal.putData(EntityDataStrings.TREE_IDLE, new IdleTree(rVal)); rVal.putData(EntityDataStrings.TREE_IDLE, new ClientIdleTree(rVal));
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
rVal.putData(EntityDataStrings.ENTITY_TYPE, ENTITY_TYPE_OBJECT); rVal.putData(EntityDataStrings.ENTITY_TYPE, ENTITY_TYPE_OBJECT);
rVal.putData(EntityDataStrings.ENTITY_SUBTYPE, type); rVal.putData(EntityDataStrings.ENTITY_SUBTYPE, type);
@ -133,9 +144,10 @@ public class ObjectUtils {
public static Entity serverSpawnBasicObject(Realm realm, Vector3d position, String type){ public static Entity serverSpawnBasicObject(Realm realm, Vector3d position, String type){
ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type);
Entity rVal = EntityCreationUtils.createServerEntity(realm, position); Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());
PoseActor creatureActor = EntityUtils.getPoseActor(rVal); if(rawType.getModelPath() != null){
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());
}
//forward-searching tokens //forward-searching tokens
boolean collisionMakeDynamic = true; boolean collisionMakeDynamic = true;
for(String token : rawType.getTokens()){ for(String token : rawType.getTokens()){
@ -199,12 +211,11 @@ public class ObjectUtils {
} break; } break;
} }
} }
//add health system if(rawType.getHitboxData() != null){
// rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); HitboxCollectionState.attachHitboxState(realm.getHitboxManager(), true, rVal, rawType.getHitboxData());
// Globals.entityManager.registerLifeStateEntity(rVal); }
//idle tree & generic stuff all objects have //idle tree & generic stuff all objects have
rVal.putData(EntityDataStrings.TREE_IDLE, new IdleTree(rVal)); ServerIdleTree.attachTree(rVal);
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
//position entity //position entity

View File

@ -9,17 +9,20 @@ import org.joml.Quaternionfc;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.collision.hitbox.HitboxUtils.HitboxPositionCallback;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.movement.ProjectileTree; import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.game.data.collidable.HitboxData;
import electrosphere.entity.types.hitbox.HitboxUtils.HitboxPositionCallback;
import electrosphere.game.data.projectile.ProjectileType; import electrosphere.game.data.projectile.ProjectileType;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.util.MathUtils;
public class ProjectileUtils { public class ProjectileUtils {
@ -39,7 +42,7 @@ public class ProjectileUtils {
Globals.assetManager.addModelPathToQueue(model); Globals.assetManager.addModelPathToQueue(model);
ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity);
EntityUtils.getPosition(rVal).set(initialPosition); EntityUtils.getPosition(rVal).set(initialPosition);
EntityUtils.getRotation(rVal).rotationTo(new Vector3d(0,0,1), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize();
Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree);
return rVal; return rVal;
} }
@ -59,8 +62,8 @@ public class ProjectileUtils {
Globals.assetManager.addModelPathToQueue(model); Globals.assetManager.addModelPathToQueue(model);
ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity);
EntityUtils.getPosition(rVal).set(initialPosition); EntityUtils.getPosition(rVal).set(initialPosition);
// EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); // EntityUtils.getRotation(currentEntity).rotationTo(MathUtils.ORIGIN_VECTORF, new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize();
EntityUtils.getRotation(rVal).rotationTo(new Vector3d(0,0,1), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize();
// ParticleTree particleTree = new ParticleTree(rVal, maxLife, destination, velocity, acceleration, true); // ParticleTree particleTree = new ParticleTree(rVal, maxLife, destination, velocity, acceleration, true);
// rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree); // rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree);
// rVal.putData(EntityDataStrings.IS_PARTICLE, true); // rVal.putData(EntityDataStrings.IS_PARTICLE, true);
@ -82,7 +85,7 @@ public class ProjectileUtils {
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath());
//initial coordinates //initial coordinates
EntityUtils.getRotation(rVal).rotationTo(new Vector3d(0,0,1), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize();
EntityUtils.getPosition(rVal).set(initialPosition); EntityUtils.getPosition(rVal).set(initialPosition);
//projectile behavior tree //projectile behavior tree
ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage());
@ -92,11 +95,15 @@ public class ProjectileUtils {
List<Entity> filter = new LinkedList<Entity>(); List<Entity> filter = new LinkedList<Entity>();
filter.add(parent); filter.add(parent);
//collidable //collidable
HitboxUtils.clientSpawnRegularHitbox(rVal, new HitboxPositionCallback() { HitboxData hitboxData = new HitboxData();
public Vector3d getPosition(){ hitboxData.setRadius(rawType.getHitboxRadius());
return EntityUtils.getPosition(rVal); HitboxCollectionState.attachHitboxStateWithCallback(Globals.clientSceneWrapper.getHitboxManager(), Globals.clientSceneWrapper.getCollisionEngine(), rVal, hitboxData,
new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
}
} }
}, rawType.getHitboxRadius(), false, filter); );
return rVal; return rVal;
} }
@ -113,7 +120,7 @@ public class ProjectileUtils {
ProjectileType rawType = Globals.gameConfigCurrent.getProjectileMap().getType(projectileType); ProjectileType rawType = Globals.gameConfigCurrent.getProjectileMap().getType(projectileType);
Entity rVal = EntityCreationUtils.createServerEntity(realm, initialPosition); Entity rVal = EntityCreationUtils.createServerEntity(realm, initialPosition);
//initial coordinates //initial coordinates
EntityUtils.getRotation(rVal).rotationTo(new Vector3d(0,0,1), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize(); EntityUtils.getRotation(rVal).rotationTo(MathUtils.getOriginVector(), new Vector3d(initialVector.x,initialVector.y,initialVector.z)).normalize();
EntityUtils.getPosition(rVal).set(initialPosition); EntityUtils.getPosition(rVal).set(initialPosition);
//projectile behavior tree //projectile behavior tree
ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage());
@ -123,11 +130,15 @@ public class ProjectileUtils {
List<Entity> filter = new LinkedList<Entity>(); List<Entity> filter = new LinkedList<Entity>();
filter.add(parent); filter.add(parent);
//collidable //collidable
HitboxUtils.serverSpawnRegularHitbox(rVal, new HitboxPositionCallback() { HitboxData hitboxData = new HitboxData();
public Vector3d getPosition(){ hitboxData.setRadius(rawType.getHitboxRadius());
return EntityUtils.getPosition(rVal); HitboxCollectionState.attachHitboxStateWithCallback(realm.getHitboxManager(), realm.getCollisionEngine(), rVal, hitboxData,
new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
}
} }
}, rawType.getHitboxRadius(), false, filter); );
//position entity //position entity

View File

@ -5,8 +5,7 @@ import electrosphere.logger.LoggerInterface;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
/** /**
* * User-defined settings
* @author amaterasu
*/ */
public class UserSettings { public class UserSettings {
@ -41,7 +40,8 @@ public class UserSettings {
int renderResolutionY; int renderResolutionY;
//debug //debug
//debug visuals //debug visuals
boolean graphicsDebugDrawCollisionSpheres; boolean graphicsDebugDrawCollisionSpheresClient;
boolean graphicsDebugDrawCollisionSpheresServer;
boolean graphicsDebugDrawPhysicsObjects; boolean graphicsDebugDrawPhysicsObjects;
boolean graphicsDebugDrawMovementVectors; boolean graphicsDebugDrawMovementVectors;
boolean graphicsDebugDrawNavmesh; boolean graphicsDebugDrawNavmesh;
@ -82,8 +82,12 @@ public class UserSettings {
return graphicsPerformanceDrawShadows; return graphicsPerformanceDrawShadows;
} }
public boolean graphicsDebugDrawCollisionSpheres() { public boolean getGraphicsDebugDrawCollisionSpheresClient() {
return graphicsDebugDrawCollisionSpheres; return graphicsDebugDrawCollisionSpheresClient;
}
public boolean getGraphicsDebugDrawCollisionSpheresServer() {
return graphicsDebugDrawCollisionSpheresServer;
} }
public boolean graphicsDebugDrawPhysicsObjects() { public boolean graphicsDebugDrawPhysicsObjects() {
@ -131,8 +135,12 @@ public class UserSettings {
} }
public void setGraphicsDebugDrawCollisionSpheres(boolean draw){ public void setGraphicsDebugDrawCollisionSpheresClient(boolean draw){
this.graphicsDebugDrawCollisionSpheres = draw; this.graphicsDebugDrawCollisionSpheresClient = draw;
}
public void setGraphicsDebugDrawCollisionSpheresServer(boolean draw){
this.graphicsDebugDrawCollisionSpheresServer = draw;
} }
public void setGraphicsDebugDrawPhysicsObjects(boolean draw){ public void setGraphicsDebugDrawPhysicsObjects(boolean draw){
@ -178,7 +186,8 @@ public class UserSettings {
rVal.gameplayPhysicsCellRadius = 2; rVal.gameplayPhysicsCellRadius = 2;
//graphics settings //graphics settings
rVal.graphicsDebugDrawCollisionSpheres = false; rVal.graphicsDebugDrawCollisionSpheresClient = false;
rVal.graphicsDebugDrawCollisionSpheresServer = false;
rVal.graphicsDebugDrawMovementVectors = false; rVal.graphicsDebugDrawMovementVectors = false;
rVal.graphicsDebugDrawPhysicsObjects = false; rVal.graphicsDebugDrawPhysicsObjects = false;
rVal.graphicsDebugDrawNavmesh = false; rVal.graphicsDebugDrawNavmesh = false;

View File

@ -0,0 +1,145 @@
package electrosphere.game.data.collidable;
import java.util.List;
import electrosphere.collision.hitbox.HitboxUtils.HitboxPositionCallback;
import electrosphere.entity.Entity;
/**
* Data about a hitbox
*/
public class HitboxData {
//a hitbox sphere that teleports to its new position between frames
public static final String HITBOX_TYPE_HIT = "hit";
//a hurtbox sphere that teleports to its new position between frames
public static final String HITBOX_TYPE_HURT = "hurt";
//a hitbox sphere that is connected to its previous position by a capsule. The capsule is used for collision checks
public static final String HITBOX_TYPE_HIT_CONNECTED = "hit_connected";
//a hurtbox sphere that is connected to its previous position by a capsule. The capsule is used for collision checks
public static final String HITBOX_TYPE_HURT_CONNECTED = "hurt_connected";
//a block sphere that is connected to its previous position by a capsule. The capsule is used for collision checks
public static final String HITBOX_TYPE_BLOCK_CONNECTED = "block_connected";
//used for debugging -- to show whether a hitbox is colliding with it or not
public static final String HITBOX_TYPE_STATIC_CAPSULE = "static_capsule";
//the type of hitbox
String type;
//the bone it is attached to
String bone;
//the radius of the hitbox
float radius;
//the length of a static capsule hitbox
float length;
//controls whether the hitbox is active or not
boolean active = false;
//used for more advanced hitbox spawning to find hitbox position on frame update
HitboxPositionCallback positionCallback;
//used to filter this hitbox to hitting only certain parent entities
List<Entity> filter;
/**
* Gets the type of hitbox
* @return the type of hitbox
*/
public String getType() {
return type;
}
/**
* Gets the type of bone
* @return the type of bone
*/
public String getBone() {
return bone;
}
/**
* Gets the radius of the hitbox
* @return the radius of the hitbox
*/
public float getRadius() {
return radius;
}
/**
* Gets the length of hitbox if applicable
* @return The length
*/
public float getLength(){
return length;
}
/**
* Returns whether the hitbox is active or not
* @return true if the hitbox is active, false otherwise
*/
public boolean isActive() {
return active;
}
/**
* Toggles the active status
* @param active if true, the hitbox will be active, if false the hitbox will be inactive
*/
public void setActive(boolean active) {
this.active = active;
}
/**
* Sets the bone this hitbox is attached to
* @param bone the bone to attach the hitbox to
*/
public void setBone(String bone) {
this.bone = bone;
}
public void setType(String type) {
this.type = type;
}
public void setRadius(float radius) {
this.radius = radius;
}
/**
* Gets the position callback
* @return The position callback
*/
public HitboxPositionCallback getPositionCallback(){
return positionCallback;
}
/**
* Sets the position callback
* @param positionCallback The position callback
*/
public void setPositionCallback(HitboxPositionCallback positionCallback){
this.positionCallback = positionCallback;
}
/**
* Sets an entity filter on the hitbox
* @param filter The list of parent entities to exclude from collisions
*/
public void setEntityFilter(List<Entity> filter){
this.filter = filter;
}
/**
* Gets the entity filter
* @return The list of parent entities to exclude from collisions
*/
public List<Entity> getEntityFilter(){
return filter;
}
}

View File

@ -1,7 +1,7 @@
package electrosphere.game.data.creature.type; package electrosphere.game.data.creature.type;
import electrosphere.entity.types.hitbox.HitboxData;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.creature.type.attack.AttackMove; import electrosphere.game.data.creature.type.attack.AttackMove;
import electrosphere.game.data.creature.type.attack.AttackMoveResolver; import electrosphere.game.data.creature.type.attack.AttackMoveResolver;
import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.game.data.creature.type.equip.EquipPoint;

View File

@ -60,6 +60,14 @@ public class EquipPoint {
return offsetRotation; return offsetRotation;
} }
/**
* Sets the offset rotation (used primarily for debug and engine testing)
* @param offsetRotation The new offset rotation
*/
public void setOffsetRotation(List<Float> offsetRotation){
this.offsetRotation = offsetRotation;
}
/** /**
* Gets the equip classes that are whitelisted for this equip point * Gets the equip classes that are whitelisted for this equip point
* @return the classes * @return the classes

View File

@ -3,9 +3,14 @@ package electrosphere.game.data.graphics;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* A graphics template for an entity
*/
public class GraphicsTemplate { public class GraphicsTemplate {
//a list of shader overrides
List<String> shaderOverrideMeshList; List<String> shaderOverrideMeshList;
//??? TODO: investigate
Map<String,ShaderSet> shaderMap; Map<String,ShaderSet> shaderMap;
public List<String> getShaderOverrideMeshList(){ public List<String> getShaderOverrideMeshList(){

View File

@ -2,27 +2,50 @@ package electrosphere.game.data.item.type;
import java.util.List; import java.util.List;
import electrosphere.entity.types.hitbox.HitboxData; import electrosphere.game.data.collidable.HitboxData;
/**
* Data about a weapon
*/
public class WeaponData { public class WeaponData {
//the class of weapon (ie sword, bow, etc)
String weaponClass; String weaponClass;
//the hitboxes associated with the weapon
List<HitboxData> hitboxes; List<HitboxData> hitboxes;
//the damage the weapon does
int damage; int damage;
//the model for the projectile
String projectileModel; String projectileModel;
/**
* Gets the weapon class
* @return the weapon class
*/
public String getWeaponClass(){ public String getWeaponClass(){
return weaponClass; return weaponClass;
} }
/**
* Gets the list of hitbox data
* @return the list of hitbox data
*/
public List<HitboxData> getHitboxes(){ public List<HitboxData> getHitboxes(){
return hitboxes; return hitboxes;
} }
/**
* Gets the projectile model
* @return the projectile model
*/
public String getProjectileModel(){ public String getProjectileModel(){
return projectileModel; return projectileModel;
} }
/**
* Gets the damage dealt
* @return the damage dealt
*/
public int getDamage(){ public int getDamage(){
return damage; return damage;
} }

View File

@ -1,37 +1,75 @@
package electrosphere.game.data.object.type; package electrosphere.game.data.object.type;
import electrosphere.entity.types.hitbox.HitboxData;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.graphics.GraphicsTemplate; import electrosphere.game.data.graphics.GraphicsTemplate;
import java.util.List; import java.util.List;
/**
* Metadata about a type of object
*/
public class ObjectData { public class ObjectData {
//the id of the object
String objectId; String objectId;
//the path for the model for this object
String modelPath; String modelPath;
//tokens associated with this object
List<String> tokens; List<String> tokens;
//the collidable template for this object
CollidableTemplate collidable; CollidableTemplate collidable;
//the graphics template for this object
GraphicsTemplate graphicsTemplate; GraphicsTemplate graphicsTemplate;
//the hitbox data for this object
List<HitboxData> hitboxData;
/**
* Gets the id of the object
* @return the id
*/
public String getObjectId() { public String getObjectId() {
return objectId; return objectId;
} }
/**
* Gets the model path of the object
* @return the model path
*/
public String getModelPath() { public String getModelPath() {
return modelPath; return modelPath;
} }
/**
* Gets all tokens associated with this object
* @return the list of all tokens
*/
public List<String> getTokens() { public List<String> getTokens() {
return tokens; return tokens;
} }
/**
* Gets the collidable data for this object
* @return the collidable data
*/
public CollidableTemplate getCollidable(){ public CollidableTemplate getCollidable(){
return collidable; return collidable;
} }
/**
* Gets the graphics template for this object
* @return the graphics template
*/
public GraphicsTemplate getGraphicsTemplate(){ public GraphicsTemplate getGraphicsTemplate(){
return graphicsTemplate; return graphicsTemplate;
} }
/**
* Gets the hitbox data for this object
* @return the hitbox data
*/
public List<HitboxData> getHitboxData(){
return this.hitboxData;
}
} }

View File

@ -7,14 +7,40 @@ import java.util.Map;
import electrosphere.game.data.object.type.ObjectData; import electrosphere.game.data.object.type.ObjectData;
/**
* An interface for grabbing data about objects available to the game engine
*/
public class ObjectTypeLoader { public class ObjectTypeLoader {
//the map that stores all object types by name
Map<String,ObjectData> objectMap = new HashMap<String,ObjectData>(); Map<String,ObjectData> objectMap = new HashMap<String,ObjectData>();
public void putObject(String name, ObjectData type){ //the list of all object data
objectMap.put(name,type); List<ObjectData> objectList = new LinkedList<ObjectData>();
/**
* Gets the list of all object types loaded into memory
* @return The list
*/
public List<ObjectData> getAllObjectTypes(){
return objectList;
} }
/**
* Puts an object in the map
* @param name The name of the object
* @param type The object type data
*/
public void putObject(String name, ObjectData type){
objectMap.put(name,type);
objectList.add(type);
}
/**
* Gets object data by its name
* @param name The name of the object type
* @return The object data if it exists, otherwise null
*/
public ObjectData getObject(String name){ public ObjectData getObject(String name){
return objectMap.get(name); return objectMap.get(name);
} }

View File

@ -3,15 +3,29 @@ package electrosphere.game.data.object.type.model;
import electrosphere.game.data.object.type.ObjectData; import electrosphere.game.data.object.type.ObjectData;
import java.util.List; import java.util.List;
/**
* The raw list of object data read from disk
*/
public class ObjectTypeMap { public class ObjectTypeMap {
//the objects stored in this file
List<ObjectData> objects; List<ObjectData> objects;
//all children files to recursively parse for more object data
List<String> files; List<String> files;
/**
* Gets the list of all objects in this file
* @return the list
*/
public List<ObjectData> getObjects() { public List<ObjectData> getObjects() {
return objects; return objects;
} }
/**
* Gets the object data for an object in this file by its name
* @param name the name of the object
* @return The object data
*/
public ObjectData getObject(String name){ public ObjectData getObject(String name){
ObjectData rVal = null; ObjectData rVal = null;
for(ObjectData item : objects){ for(ObjectData item : objects){
@ -23,6 +37,10 @@ public class ObjectTypeMap {
return rVal; return rVal;
} }
/**
* Gets the list of all children files of this file
* @return The list of all children files
*/
public List<String> getFiles(){ public List<String> getFiles(){
return files; return files;
} }

View File

@ -1,46 +1,90 @@
package electrosphere.logger; package electrosphere.logger;
/** /**
* * A channel for logging messages
* @author amaterasu
*/ */
public class Logger { public class Logger {
/**
* The different logging levels
*/
public enum LogLevel { public enum LogLevel {
LOOP_DEBUG, //this should be used for debugging messages that are executed very rapidly/every frame
DEBUG, DEBUG,
INFO, INFO,
WARNING, WARNING,
ERROR, ERROR,
} }
//the level of this log
LogLevel level; LogLevel level;
/**
* Creates a logger channel
* @param level The level of message to report on this channel
*/
public Logger(LogLevel level){ public Logger(LogLevel level){
this.level = level; this.level = level;
} }
/**
* Logs a loop debug message.
* This should be used for debugging messages that are executed very rapidly/every frame
* @param message The message to report
*/
public void DEBUG_LOOP(String message){
if(level == LogLevel.LOOP_DEBUG){
System.out.println(message);
}
}
/**
* Logs a debug message.
* This should be used for debugging messages that are executed on a given condition that won't necessarily be every loop (ie all network messages)
* @param message The message to report
*/
public void DEBUG(String message){ public void DEBUG(String message){
if(level == LogLevel.DEBUG){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG){
System.out.println(message); System.out.println(message);
} }
} }
/**
* Logs an info message.
* This should be used for messages that would have interest to someone running a server (ie specific network messages, account creation, etc)
* @param message The message to report
*/
public void INFO(String message){ public void INFO(String message){
if(level == LogLevel.DEBUG || level == LogLevel.INFO){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG || level == LogLevel.INFO){
System.out.println(message); System.out.println(message);
} }
} }
/**
* Logs a warning message.
* This should be used for reporting events that happen in the engine that are concerning but don't mean the engine has failed to execute (ie a texture failed to load)
* @param message The message to report
*/
public void WARNING(String message){ public void WARNING(String message){
if(level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING){
System.out.println(message); System.out.println(message);
} }
} }
/**
* Logs an error message.
* This should be used every time we throw any kind of error in the engine
* @param message The message to report
*/
public void ERROR(String message, Exception e){ public void ERROR(String message, Exception e){
if(level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING || level == LogLevel.ERROR){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING || level == LogLevel.ERROR){
System.out.println(message); System.err.println(message);
e.printStackTrace(); e.printStackTrace();
} }
} }
} }

View File

@ -12,8 +12,15 @@ import electrosphere.renderer.ui.elementtypes.ContainerElement;
import electrosphere.renderer.ui.elementtypes.DrawableElement; import electrosphere.renderer.ui.elementtypes.DrawableElement;
import electrosphere.renderer.ui.elementtypes.Element; import electrosphere.renderer.ui.elementtypes.Element;
/**
* Utils for native windowing framework
*/
public class WindowUtils { public class WindowUtils {
/**
* Replaces the main menu contents
* @param newMenu The new contents
*/
public static void replaceMainMenuContents(Element newMenu){ public static void replaceMainMenuContents(Element newMenu){
Element mainMenuEl = Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN); Element mainMenuEl = Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN);
if(mainMenuEl != null && mainMenuEl instanceof Window){ if(mainMenuEl != null && mainMenuEl instanceof Window){
@ -26,6 +33,11 @@ public class WindowUtils {
} }
} }
/**
* Recursively sets a window as visible or not
* @param topLevelMenu The window element
* @param visible true for visible, false for invisible
*/
public static void recursiveSetVisible(Element topLevelMenu, boolean visible){ public static void recursiveSetVisible(Element topLevelMenu, boolean visible){
if(topLevelMenu instanceof DrawableElement){ if(topLevelMenu instanceof DrawableElement){
((DrawableElement)topLevelMenu).setVisible(visible); ((DrawableElement)topLevelMenu).setVisible(visible);
@ -40,6 +52,29 @@ public class WindowUtils {
} }
} }
/**
* Checks whether the window registered to the provided string is open
* @param windowString The window string
* @return true if the window is open, false otherwise
*/
public static boolean windowIsOpen(String windowString){
Element windowElement = Globals.elementManager.getWindow(windowString);
return Globals.elementManager.getWindowList().contains(windowElement);
}
/**
* Checks if a window is open or not
* @return The window
*/
public static boolean controlBlockingWindowIsOpen(){
return windowIsOpen(WindowStrings.LEVEL_EDTIOR_SIDE_PANEL);
}
/**
* Gets an inventory window string by the id of the inventory
* @param id the id
* @return the window string for said inventory window
*/
public static String getInventoryWindowID(int id){ public static String getInventoryWindowID(int id){
return "INVENTORY-" + id; return "INVENTORY-" + id;
} }
@ -76,8 +111,8 @@ public class WindowUtils {
} }
/** /**
* Tries to close a window * Cleans up a window visually and removes it from the element manager
* @param window the window to close * @param window the window to clean up
*/ */
public static void closeWindow(String window){ public static void closeWindow(String window){
Element windowEl = Globals.elementManager.getWindow(window); Element windowEl = Globals.elementManager.getWindow(window);

View File

@ -1,15 +1,27 @@
package electrosphere.menu.debug; package electrosphere.menu.debug;
import java.util.LinkedList;
import java.util.List;
import org.joml.Quaterniond;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils; import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.item.ItemUtils;
import electrosphere.renderer.RenderingEngine; import electrosphere.game.data.creature.type.equip.EquipPoint;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorMeshMask; import electrosphere.renderer.actor.ActorMeshMask;
import electrosphere.renderer.anim.AnimChannel;
import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Bone;
import electrosphere.renderer.model.Mesh; import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import imgui.ImGui; import imgui.ImGui;
@ -19,11 +31,17 @@ import imgui.ImGui;
*/ */
public class ImGuiEntityMacros { public class ImGuiEntityMacros {
//window for viewing main player entity's stats on both client and server
protected static ImGuiWindow clientEntityWindow; protected static ImGuiWindow clientEntityWindow;
private static boolean filterToCreatures = false; private static boolean filterToCreatures = false; //filters the entity list to just creatures
//views stats about an actor
protected static ImGuiWindow actorView; protected static ImGuiWindow actorView;
static Entity actorViewEntity; static Entity actorViewEntity; //the entity whose actor we're viewing in the actor window
//views stats about equip state
protected static ImGuiWindow equipStateView;
static Entity equipViewEntity; //the entity whose equip state we're viewing in the equip window
/** /**
* Creates the windows in this file * Creates the windows in this file
@ -31,6 +49,7 @@ public class ImGuiEntityMacros {
protected static void createClientEntityWindows(){ protected static void createClientEntityWindows(){
createClientEntityDebugWindow(); createClientEntityDebugWindow();
createActorViewDebugWindow(); createActorViewDebugWindow();
createEquipStateDebugWindow();
} }
/** /**
@ -54,9 +73,17 @@ public class ImGuiEntityMacros {
ImGui.beginGroup(); ImGui.beginGroup();
ImGui.text("Id: " + entity.getId() + " (" + getEntityName(entity) + ")"); ImGui.text("Id: " + entity.getId() + " (" + getEntityName(entity) + ")");
if(CreatureUtils.isCreature(entity)){ if(CreatureUtils.isCreature(entity)){
if(ImGui.button("Actor View")){ if(EntityUtils.getActor(entity) != null){
actorViewEntity = entity; if(ImGui.button("Actor View")){
actorView.setOpen(true); actorViewEntity = entity;
actorView.setOpen(true);
}
}
if(ClientEquipState.getClientEquipState(entity) != null){
if(ImGui.button("Client Equip State View")){
equipViewEntity = entity;
equipStateView.setOpen(true);
}
} }
} }
ImGui.endGroup(); ImGui.endGroup();
@ -64,7 +91,7 @@ public class ImGuiEntityMacros {
} }
}); });
clientEntityWindow.setOpen(false); clientEntityWindow.setOpen(false);
RenderingEngine.addImGuiWindow(clientEntityWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(clientEntityWindow);
} }
/** /**
@ -90,11 +117,88 @@ public class ImGuiEntityMacros {
ImGui.text(blocked); ImGui.text(blocked);
} }
} }
//print bone values
if(ImGui.button("Print current bone values")){
for(Bone bone : actor.getBoneValues()){
LoggerInterface.loggerRenderer.DEBUG(bone.boneID);
LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform());
}
}
//print animation keys
if(ImGui.button("Print animation keys")){
Model model = Globals.assetManager.fetchModel(actor.getModelPath());
model.describeAllAnimations();
}
//Browsable list of all animations with their data
if(ImGui.collapsingHeader("Animation Channel Data")){
Model model = Globals.assetManager.fetchModel(actor.getModelPath());
for(Animation animation : model.getAnimations()){
ImGui.text(" - " + animation.name);
for(AnimChannel channel : animation.channels){
ImGui.text("=" + channel.getNodeID() + "=");
ImGui.text("" + channel.getCurrentPosition());
ImGui.text("" + channel.getCurrentRotation());
ImGui.text("" + channel.getCurrentScale());
}
}
}
} }
} }
}); });
actorView.setOpen(false); actorView.setOpen(false);
RenderingEngine.addImGuiWindow(actorView); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(actorView);
}
/**
* Client scene equip state view
*/
protected static void createEquipStateDebugWindow(){
equipStateView = new ImGuiWindow("Client Equip State View");
equipStateView.setCallback(new ImGuiWindowCallback() {
//stores the edited rotation values
float[] rotationValues = new float[]{
0,0,0
};
@Override
public void exec() {
if(equipViewEntity != null && ClientEquipState.getClientEquipState(equipViewEntity) != null){
ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(equipViewEntity);
if(ImGui.collapsingHeader("All Equip Points")){
for(EquipPoint point : clientEquipState.getAllEquipPoints()){
if(ImGui.collapsingHeader(point.getEquipPointId())){
ImGui.text("Has item equipped: " + (clientEquipState.getEquippedItemAtPoint(point.getEquipPointId()) != null));
ImGui.text("Bone (Third Person): " + point.getBone());
ImGui.text("Bone (First Person): " + point.getFirstPersonBone());
ImGui.text("Rotation: " + AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation()));
if(ImGui.sliderFloat3("Rotation (In Euler along x,y,z)", rotationValues, 0, (float)(Math.PI * 2))){
Quaterniond rotation = new Quaterniond().rotateXYZ(rotationValues[0], rotationValues[1], rotationValues[2]);
List<Float> newValues = new LinkedList<Float>();
newValues.add((float)rotation.x);
newValues.add((float)rotation.y);
newValues.add((float)rotation.z);
newValues.add((float)rotation.w);
point.setOffsetRotation(newValues);
Entity equippedEntity = clientEquipState.getEquippedItemAtPoint(point.getEquipPointId());
if(equippedEntity != null){
AttachUtils.setRotationOffset(equippedEntity, AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation()));
}
}
}
}
}
}
}
});
equipStateView.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(equipStateView);
} }
/** /**

View File

@ -0,0 +1,8 @@
package electrosphere.menu.debug;
/**
* Utilities for dealing with imgui
*/
public class ImGuiUtils {
}

View File

@ -7,11 +7,13 @@ import org.ode4j.ode.DBody;
import electrosphere.audio.VirtualAudioSource; import electrosphere.audio.VirtualAudioSource;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot; import electrosphere.renderer.ui.imgui.ImGuiLinePlot;
import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot.ImGuiLinePlotDataset; import electrosphere.renderer.ui.imgui.ImGuiLinePlot.ImGuiLinePlotDataset;
@ -73,7 +75,15 @@ public class ImGuiWindowMacros {
initFramerateGraphSeries("controls"); initFramerateGraphSeries("controls");
globalFrametimeWindow.addElement(globalFrametimePlot); globalFrametimeWindow.addElement(globalFrametimePlot);
globalFrametimeWindow.setOpen(false); globalFrametimeWindow.setOpen(false);
RenderingEngine.addImGuiWindow(globalFrametimeWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(globalFrametimeWindow);
}
/**
* Gets the main debug window
* @return the main debug window
*/
public static ImGuiWindow getMainDebugWindow(){
return mainDebugWindow;
} }
/** /**
@ -156,7 +166,7 @@ public class ImGuiWindowMacros {
} }
}); });
audioDebugMenu.setOpen(false); audioDebugMenu.setOpen(false);
RenderingEngine.addImGuiWindow(audioDebugMenu); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(audioDebugMenu);
} }
@ -172,16 +182,35 @@ public class ImGuiWindowMacros {
ImGui.text("Player Entity Details"); ImGui.text("Player Entity Details");
if(Globals.playerEntity != null){ if(Globals.playerEntity != null){
ImGui.text("Position: " + EntityUtils.getPosition(Globals.playerEntity)); ImGui.text("Position: " + EntityUtils.getPosition(Globals.playerEntity));
//server pos
int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
ImGui.text("Position (Server): " + EntityUtils.getPosition(serverPlayerEntity));
//client-side tree stuff
DBody body = PhysicsEntityUtils.getDBody(Globals.playerEntity); DBody body = PhysicsEntityUtils.getDBody(Globals.playerEntity);
ClientAttackTree attackTree = ClientAttackTree.getClientAttackTree(Globals.playerEntity);
if(body != null){ if(body != null){
ImGui.text("Velocity: " + body.getLinearVel()); ImGui.text("Velocity: " + body.getLinearVel());
ImGui.text("Force: " + body.getForce()); ImGui.text("Force: " + body.getForce());
ImGui.text("Angular Velocity: " + body.getAngularVel()); ImGui.text("Angular Velocity: " + body.getAngularVel());
ImGui.text("Torque: " + body.getTorque()); ImGui.text("Torque: " + body.getTorque());
ImGui.text("Move Vector: " + CreatureUtils.getFacingVector(Globals.playerEntity)); ImGui.text("Move Vector: " + CreatureUtils.getFacingVector(Globals.playerEntity));
Entity serverEntity = EntityLookupUtils.getEntityById(Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId())); if(attackTree != null){
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(serverEntity)); ImGui.text("Attack Tree State: " + attackTree.getState());
}
} }
//server-side tree stuff
DBody serverBody = PhysicsEntityUtils.getDBody(serverPlayerEntity);
if(body != null){
ImGui.text("Velocity (Server): " + serverBody.getLinearVel());
ImGui.text("Force (Server): " + serverBody.getForce());
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(serverPlayerEntity));
ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(serverPlayerEntity));
}
ImGui.text("View dir (Server): " + ServerPlayerViewDirTree.getTree(serverPlayerEntity).getPlayerViewDir());
} }
if(ImGui.button("Toggle Player Camera Lock")){ if(ImGui.button("Toggle Player Camera Lock")){
Globals.cameraHandler.setTrackPlayerEntity(!Globals.cameraHandler.getTrackPlayerEntity()); Globals.cameraHandler.setTrackPlayerEntity(!Globals.cameraHandler.getTrackPlayerEntity());
@ -189,7 +218,7 @@ public class ImGuiWindowMacros {
} }
}); });
playerEntityWindow.setOpen(false); playerEntityWindow.setOpen(false);
RenderingEngine.addImGuiWindow(playerEntityWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(playerEntityWindow);
} }
/** /**
@ -208,7 +237,7 @@ public class ImGuiWindowMacros {
} }
}); });
fluidWindow.setOpen(false); fluidWindow.setOpen(false);
RenderingEngine.addImGuiWindow(fluidWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(fluidWindow);
} }
@ -247,7 +276,7 @@ public class ImGuiWindowMacros {
} }
}); });
mainDebugWindow.setOpen(false); mainDebugWindow.setOpen(false);
RenderingEngine.addImGuiWindow(mainDebugWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(mainDebugWindow);
} }
/** /**
@ -255,6 +284,11 @@ public class ImGuiWindowMacros {
*/ */
public static void toggleMainDebugMenu(){ public static void toggleMainDebugMenu(){
mainDebugWindow.setOpen(!mainDebugWindow.isOpen()); mainDebugWindow.setOpen(!mainDebugWindow.isOpen());
if(mainDebugWindow.isOpen()){
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
} else {
Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
}
} }
} }

View File

@ -51,11 +51,10 @@ public class MenuGeneratorsInGame {
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false); WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false);
Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN); Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN);
if(Globals.cameraHandler.getTrackPlayerEntity()){ if(Globals.cameraHandler.getTrackPlayerEntity()){
Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
} else { } else {
Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_FREE_CAMERA); Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_FREE_CAMERA);
} }
Globals.controlHandler.hideMouse();
return false; return false;
}}); }});
@ -76,11 +75,10 @@ public class MenuGeneratorsInGame {
WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false); WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false);
Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN); Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN);
if(Globals.cameraHandler.getTrackPlayerEntity()){ if(Globals.cameraHandler.getTrackPlayerEntity()){
Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
} else { } else {
Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_FREE_CAMERA); Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_FREE_CAMERA);
} }
Globals.controlHandler.hideMouse();
return false; return false;
}}); }});
@ -273,15 +271,27 @@ public class MenuGeneratorsInGame {
return false; return false;
}}); }});
//label (toggle draw collision spheres) //label (toggle draw client collision spheres)
Button toggleCollisionSpheresButton = new Button(); Button toggleClientCollisionSpheresButton = new Button();
Label toggleCollisionSpheresLabel = new Label(fontSize); Label toggleClientCollisionSpheresLabel = new Label(fontSize);
toggleCollisionSpheresLabel.setText("Toggle draw collision spheres"); toggleClientCollisionSpheresLabel.setText("Toggle draw client collision spheres");
toggleCollisionSpheresButton.addChild(toggleCollisionSpheresLabel); toggleClientCollisionSpheresButton.addChild(toggleClientCollisionSpheresLabel);
scrollable.addChild(toggleCollisionSpheresButton); scrollable.addChild(toggleClientCollisionSpheresButton);
toggleCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ toggleClientCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
// Main.running = false; // Main.running = false;
Globals.userSettings.setGraphicsDebugDrawCollisionSpheres(!Globals.userSettings.graphicsDebugDrawCollisionSpheres()); Globals.userSettings.setGraphicsDebugDrawCollisionSpheresClient(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresClient());
return false;
}});
//label (toggle draw server collision spheres)
Button toggleServerCollisionSpheresButton = new Button();
Label toggleServerCollisionSpheresLabel = new Label(fontSize);
toggleServerCollisionSpheresLabel.setText("Toggle draw server collision spheres");
toggleServerCollisionSpheresButton.addChild(toggleServerCollisionSpheresLabel);
scrollable.addChild(toggleServerCollisionSpheresButton);
toggleServerCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
// Main.running = false;
Globals.userSettings.setGraphicsDebugDrawCollisionSpheresServer(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresServer());
return false; return false;
}}); }});

View File

@ -50,8 +50,7 @@ public class MenuGeneratorsInventory {
// //
Globals.openInventoriesCount--; Globals.openInventoriesCount--;
if(Globals.openInventoriesCount == 0){ if(Globals.openInventoriesCount == 0){
Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
Globals.controlHandler.hideMouse();
} }
//play sound effect //play sound effect
Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false);
@ -223,8 +222,7 @@ public class MenuGeneratorsInventory {
// //
Globals.openInventoriesCount--; Globals.openInventoriesCount--;
if(Globals.openInventoriesCount == 0){ if(Globals.openInventoriesCount == 0){
Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
Globals.controlHandler.hideMouse();
} }
//play sound effect //play sound effect
Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false); Globals.virtualAudioSourceManager.createVirtualAudioSource("/Audio/closeMenu.ogg", VirtualAudioSourceType.UI, false);

View File

@ -17,6 +17,7 @@ import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.game.data.creature.type.CreatureType; import electrosphere.game.data.creature.type.CreatureType;
import electrosphere.game.data.foliage.type.FoliageType; import electrosphere.game.data.foliage.type.FoliageType;
import electrosphere.game.data.item.type.Item; import electrosphere.game.data.item.type.Item;
import electrosphere.game.data.object.type.ObjectData;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.menu.WindowStrings; import electrosphere.menu.WindowStrings;
import electrosphere.menu.WindowUtils; import electrosphere.menu.WindowUtils;
@ -114,6 +115,12 @@ public class MenuGeneratorsLevelEditor {
return false; return false;
}})); }}));
//spawn object button
scrollable.addChild(Button.createButton("Spawn Object", new ClickEventCallback() {public boolean execute(ClickEvent event){
fillInSpawnObjectContent(scrollable);
return false;
}}));
//select voxel button //select voxel button
scrollable.addChild(Button.createButton("Select Voxel Type", new ClickEventCallback() {public boolean execute(ClickEvent event){ scrollable.addChild(Button.createButton("Select Voxel Type", new ClickEventCallback() {public boolean execute(ClickEvent event){
if(voxelWindowOpen){ if(voxelWindowOpen){
@ -235,6 +242,37 @@ public class MenuGeneratorsLevelEditor {
} }
/**
* Level editor menu content for spawning objects
* @param scrollable
*/
private static void fillInSpawnObjectContent(VirtualScrollable scrollable){
scrollable.clearChildren();
//back button
scrollable.addChild(Button.createButton("Back", new ClickEventCallback() {public boolean execute(ClickEvent event){
fillInDefaultContent(scrollable);
return false;
}}));
//button for spawning all foliage types
for(ObjectData object : Globals.gameConfigCurrent.getObjectTypeLoader().getAllObjectTypes()){
//spawn foliage button
scrollable.addChild(Button.createButton("Spawn " + object.getObjectId(), new ClickEventCallback() {public boolean execute(ClickEvent event){
LoggerInterface.loggerEngine.INFO("spawn " + object.getObjectId() + "!");
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
ObjectUtils.serverSpawnBasicObject(realm, cursorPos, object.getObjectId());
return false;
}}));
}
mainSidePanel.applyYoga(0,0);
}
/** /**
* Creates tree view of entities in server * Creates tree view of entities in server
* @param scrollable * @param scrollable

View File

@ -125,6 +125,9 @@ public class MenuGeneratorsTerrainEditing {
voxelLabel.setText(type.getName()); voxelLabel.setText(type.getName());
//icon/model //icon/model
ImagePanel texturePanel = ImagePanel.createImagePanel(type.getTexture()); ImagePanel texturePanel = ImagePanel.createImagePanel(type.getTexture());
if(type.getTexture() != null){
Globals.assetManager.addTexturePathtoQueue(type.getTexture());
}
texturePanel.setWidth(VOXEL_BUTTON_TEXTURE_DIM); texturePanel.setWidth(VOXEL_BUTTON_TEXTURE_DIM);
texturePanel.setHeight(VOXEL_BUTTON_TEXTURE_DIM); texturePanel.setHeight(VOXEL_BUTTON_TEXTURE_DIM);
newButton.addChild(texturePanel); newButton.addChild(texturePanel);

View File

@ -0,0 +1,57 @@
package electrosphere.menu.mainmenu;
import org.lwjgl.util.yoga.Yoga;
import electrosphere.engine.Globals;
import electrosphere.engine.loadingthreads.LoadingThread;
import electrosphere.menu.WindowUtils;
import electrosphere.renderer.ui.elements.Button;
import electrosphere.renderer.ui.elements.FormElement;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elementtypes.ClickableElement;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.events.ClickEvent;
/**
* Generates menu items for the demo version of the engine
*/
public class MenuGeneratorsDemo {
/**
* Creates the title menu for the demo
* @return The content element to embed in a title window
*/
public static Element createTitleMenu(){
FormElement rVal = new FormElement();
//top-bottom
rVal.setJustifyContent(Yoga.YGJustifyCenter);
//left-right
rVal.setAlignItems(Yoga.YGAlignCenter);
rVal.setAlignContent(Yoga.YGAlignFlexStart);
//label (title)
Label titleLabel = new Label(1.0f);
titleLabel.setText("ORPG");
rVal.addChild(titleLabel);
//button (arena)
Button arenaButton = new Button();
Label arenaLabel = new Label(1.0f);
arenaLabel.setText("Start");
arenaButton.addChild(arenaLabel);
rVal.addChild(arenaButton);
arenaButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
LoadingThread serverThread = new LoadingThread(LoadingThread.LOAD_LEVEL);
Globals.loadingThreadsList.add(serverThread);
Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = true;
serverThread.start();
WindowUtils.replaceMainMenuContents(MenuGeneratorsArena.createArenaHostLoginMenu());
return false;
}});
arenaButton.setMarginTop(50);
return rVal;
}
}

View File

@ -11,7 +11,6 @@ import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityTags; import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ClientAttackTree; import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.attack.ServerAttackTree;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureTemplate; import electrosphere.entity.types.creature.CreatureTemplate;
@ -96,13 +95,6 @@ public class EntityProtocol {
// UPDATING PROPERTIES // UPDATING PROPERTIES
// //
// //
case MOVE: {
Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
LoggerInterface.loggerNetworking.DEBUG("ID: " + message.getentityID());
if(target != null){
EntityUtils.getPosition(target).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
}
} break;
case SETPROPERTY: { case SETPROPERTY: {
if(Globals.clientSceneWrapper.serverToClientMapContainsId(message.getentityID())){ if(Globals.clientSceneWrapper.serverToClientMapContainsId(message.getentityID())){
if(message.getpropertyType() == 0){ if(message.getpropertyType() == 0){
@ -143,18 +135,11 @@ public class EntityProtocol {
// TODO // TODO
// //
// //
case UPDATEENTITYVIEWDIR:
case KILL: case KILL:
case SETPOSITION:
case SETFACING:
//to be implemented //to be implemented
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
default:
case SETBEHAVIORTREE:
case SETBTREEPROPERTYDOUBLE:
case SETBTREEPROPERTYENUM:
case SETBTREEPROPERTYFLOAT:
case SETBTREEPROPERTYINT:
case SETBTREEPROPERTYSTRING:
//unused //unused
break; break;
} }

View File

@ -27,7 +27,7 @@ public class InventoryProtocol {
//translate equipper id //translate equipper id
Entity equipper = Globals.clientSceneWrapper.getEntityFromServerId(message.getequipperId()); Entity equipper = Globals.clientSceneWrapper.getEntityFromServerId(message.getequipperId());
//spawn in world id //spawn in world id
Entity inWorldEntity = ItemUtils.clientSpawnBasicItem(message.getitemTemplate()); Entity inWorldEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
if(inWorldEntity != null){ if(inWorldEntity != null){
//translate id //translate id
Globals.clientSceneWrapper.mapIdToId(inWorldEntity.getId(), message.getentityId()); Globals.clientSceneWrapper.mapIdToId(inWorldEntity.getId(), message.getentityId());
@ -38,7 +38,7 @@ public class InventoryProtocol {
String equipPointName = message.getequipPointId(); String equipPointName = message.getequipPointId();
EquipPoint equipPoint = equipState.getEquipPoint(equipPointName); EquipPoint equipPoint = equipState.getEquipPoint(equipPointName);
//attach //attach
equipState.clientAttemptEquip(inWorldEntity, equipPoint); equipState.attemptEquip(inWorldEntity, equipPoint);
} }
} }
break; break;

View File

@ -11,18 +11,11 @@ public class LoreProtocol {
protected static void handleLoreMessage(LoreMessage message){ protected static void handleLoreMessage(LoreMessage message){
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case RESPONSEDATA:
break;
case RESPONSERACES: case RESPONSERACES:
//we get back the race list as a json array, deserialize, and push into type loader //we get back the race list as a json array, deserialize, and push into type loader
List<String> playableRaces = new Gson().fromJson(message.getdata(), List.class); List<String> playableRaces = new Gson().fromJson(message.getdata(), List.class);
Globals.gameConfigCurrent.getCreatureTypeLoader().loadPlayableRaces(playableRaces); Globals.gameConfigCurrent.getCreatureTypeLoader().loadPlayableRaces(playableRaces);
break; break;
case RESPONSERACEDATA:
break;
case REQUESTDATA:
case REQUESTRACEDATA:
case REQUESTRACES: case REQUESTRACES:
//silently ignore //silently ignore
break; break;

View File

@ -9,10 +9,13 @@ public class SynchronizationProtocol {
Globals.profiler.beginCpuSample("SynchronizationProtocol.handleSynchronizationMessage"); Globals.profiler.beginCpuSample("SynchronizationProtocol.handleSynchronizationMessage");
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case UPDATECLIENTSTATE: case UPDATECLIENTSTATE:
case UPDATECLIENTSTRINGSTATE:
case ATTACHTREE: case ATTACHTREE:
case DETATCHTREE: case DETATCHTREE:
Globals.clientSynchronizationManager.pushMessage(message); Globals.clientSynchronizationManager.pushMessage(message);
break; break;
default:
throw new UnsupportedOperationException("Received synchronization message on the client of unsupported type: " + message.getMessageSubtype());
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }

View File

@ -11,23 +11,15 @@ public class EntityMessage extends NetworkMessage {
CREATE, CREATE,
SPAWNCREATURE, SPAWNCREATURE,
SPAWNITEM, SPAWNITEM,
SETPOSITION,
SETFACING,
MOVEUPDATE, MOVEUPDATE,
ATTACKUPDATE, ATTACKUPDATE,
STARTATTACK, STARTATTACK,
MOVE,
KILL, KILL,
DESTROY, DESTROY,
SETBEHAVIORTREE,
SETPROPERTY, SETPROPERTY,
SETBTREEPROPERTYINT,
SETBTREEPROPERTYFLOAT,
SETBTREEPROPERTYDOUBLE,
SETBTREEPROPERTYSTRING,
SETBTREEPROPERTYENUM,
ATTACHENTITYTOENTITY, ATTACHENTITYTOENTITY,
SPAWNFOLIAGESEED, SPAWNFOLIAGESEED,
UPDATEENTITYVIEWDIR,
} }
EntityMessageType messageType; EntityMessageType messageType;
@ -296,18 +288,6 @@ public class EntityMessage extends NetworkMessage {
return EntityMessage.canParseSpawnCreatureMessage(byteBuffer); return EntityMessage.canParseSpawnCreatureMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNITEM: case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNITEM:
return EntityMessage.canParseSpawnItemMessage(byteBuffer); return EntityMessage.canParseSpawnItemMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_SETFACING:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETFACING_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE: case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE){ if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE){
return true; return true;
@ -326,12 +306,6 @@ public class EntityMessage extends NetworkMessage {
} else { } else {
return false; return false;
} }
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVE:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_MOVE_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_KILL: case TypeBytes.ENTITY_MESSAGE_TYPE_KILL:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_KILL_SIZE){ if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_KILL_SIZE){
return true; return true;
@ -344,48 +318,22 @@ public class EntityMessage extends NetworkMessage {
} else { } else {
return false; return false;
} }
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY: case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE){ if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE){
return true; return true;
} else { } else {
return false; return false;
} }
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYINT:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYINT_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYFLOAT:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYFLOAT_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYDOUBLE:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYDOUBLE_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYSTRING:
return EntityMessage.canParsesetBTreePropertyStringMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM_SIZE){
return true;
} else {
return false;
}
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY: case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY:
return EntityMessage.canParseattachEntityToEntityMessage(byteBuffer); return EntityMessage.canParseattachEntityToEntityMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED: case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED:
return EntityMessage.canParseSpawnFoliageSeedMessage(byteBuffer); return EntityMessage.canParseSpawnFoliageSeedMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE){
return true;
} else {
return false;
}
} }
return false; return false;
} }
@ -554,50 +502,6 @@ public class EntityMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static EntityMessage parseSetPositionMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPOSITION);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructSetPositionMessage(int entityID,long time,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPOSITION);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
public static EntityMessage parsesetFacingMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETFACING);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetFacingMessage(int entityID,long time,double rotationX,double rotationY,double rotationZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETFACING);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setrotationX(rotationX);
rVal.setrotationY(rotationY);
rVal.setrotationZ(rotationZ);
rVal.serialize();
return rVal;
}
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){ public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE); EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
stripPacketHeader(byteBuffer); stripPacketHeader(byteBuffer);
@ -611,11 +515,12 @@ public class EntityMessage extends NetworkMessage {
rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setvelocity(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); rVal.setvelocity(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpropertyValueInt(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settreeState(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); rVal.settreeState(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal; return rVal;
} }
public static EntityMessage constructmoveUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double velocity,int treeState){ public static EntityMessage constructmoveUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double velocity,int propertyValueInt,int treeState){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE); EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
rVal.setentityID(entityID); rVal.setentityID(entityID);
rVal.settime(time); rVal.settime(time);
@ -627,6 +532,7 @@ public class EntityMessage extends NetworkMessage {
rVal.setrotationZ(rotationZ); rVal.setrotationZ(rotationZ);
rVal.setrotationW(rotationW); rVal.setrotationW(rotationW);
rVal.setvelocity(velocity); rVal.setvelocity(velocity);
rVal.setpropertyValueInt(propertyValueInt);
rVal.settreeState(treeState); rVal.settreeState(treeState);
rVal.serialize(); rVal.serialize();
return rVal; return rVal;
@ -676,28 +582,6 @@ public class EntityMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static EntityMessage parseMoveMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVE);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructMoveMessage(int entityID,long time,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVE);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer){ public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL); EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
stripPacketHeader(byteBuffer); stripPacketHeader(byteBuffer);
@ -728,26 +612,6 @@ public class EntityMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static EntityMessage parseSetBehaviorTreeMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBEHAVIORTREE);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.settreeType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settreeStatus(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructSetBehaviorTreeMessage(int entityID,long time,int treeType,int treeStatus){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBEHAVIORTREE);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.settreeType(treeType);
rVal.settreeStatus(treeStatus);
rVal.serialize();
return rVal;
}
public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer){ public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY); EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
stripPacketHeader(byteBuffer); stripPacketHeader(byteBuffer);
@ -768,147 +632,6 @@ public class EntityMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static EntityMessage parsesetBTreePropertyIntMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYINT);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setbTreeID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyValueInt(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetBTreePropertyIntMessage(int entityID,long time,int bTreeID,int propertyID,int propertyValueInt){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYINT);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setbTreeID(bTreeID);
rVal.setpropertyID(propertyID);
rVal.setpropertyValueInt(propertyValueInt);
rVal.serialize();
return rVal;
}
public static EntityMessage parsesetBTreePropertyFloatMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYFLOAT);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setbTreeID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyValueFloat(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetBTreePropertyFloatMessage(int entityID,long time,int bTreeID,int propertyID,float propertyValueFloat){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYFLOAT);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setbTreeID(bTreeID);
rVal.setpropertyID(propertyID);
rVal.setpropertyValueFloat(propertyValueFloat);
rVal.serialize();
return rVal;
}
public static EntityMessage parsesetBTreePropertyDoubleMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYDOUBLE);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setbTreeID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyValueDouble(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetBTreePropertyDoubleMessage(int entityID,long time,int bTreeID,int propertyID,double propertyValueDouble){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYDOUBLE);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setbTreeID(bTreeID);
rVal.setpropertyID(propertyID);
rVal.setpropertyValueDouble(propertyValueDouble);
rVal.serialize();
return rVal;
}
public static boolean canParsesetBTreePropertyStringMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 14){
return false;
}
if(currentStreamLength < 18){
return false;
}
if(currentStreamLength < 22){
return false;
}
int propertyValueStringSize = 0;
if(currentStreamLength < 26){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(22 + 0));
temporaryByteQueue.add(byteBuffer.peek(22 + 1));
temporaryByteQueue.add(byteBuffer.peek(22 + 2));
temporaryByteQueue.add(byteBuffer.peek(22 + 3));
propertyValueStringSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 26 + propertyValueStringSize){
return false;
}
return true;
}
public static EntityMessage parsesetBTreePropertyStringMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYSTRING);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setbTreeID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyValueString(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetBTreePropertyStringMessage(int entityID,long time,int bTreeID,int propertyID,String propertyValueString){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYSTRING);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setbTreeID(bTreeID);
rVal.setpropertyID(propertyID);
rVal.setpropertyValueString(propertyValueString);
rVal.serialize();
return rVal;
}
public static EntityMessage parsesetBTreePropertyEnumMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYENUM);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setbTreeID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setpropertyValueInt(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructsetBTreePropertyEnumMessage(int entityID,long time,int bTreeID,int propertyID,int propertyValueInt){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETBTREEPROPERTYENUM);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setbTreeID(bTreeID);
rVal.setpropertyID(propertyID);
rVal.setpropertyValueInt(propertyValueInt);
rVal.serialize();
return rVal;
}
public static boolean canParseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){ public static boolean canParseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining(); int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList(); List<Byte> temporaryByteQueue = new LinkedList();
@ -1010,6 +733,28 @@ public class EntityMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructupdateEntityViewDirMessage(int entityID,long time,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
@Override @Override
void serialize(){ void serialize(){
byte[] intValues = new byte[8]; byte[] intValues = new byte[8];
@ -1112,62 +857,8 @@ public class EntityMessage extends NetworkMessage {
rawBytes[26+creatureTemplate.length()+i] = intValues[i]; rawBytes[26+creatureTemplate.length()+i] = intValues[i];
} }
break; break;
case SETPOSITION:
rawBytes = new byte[2+4+8+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
for(int i = 0; i < 8; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
for(int i = 0; i < 8; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
for(int i = 0; i < 8; i++){
rawBytes[30+i] = intValues[i];
}
break;
case SETFACING:
rawBytes = new byte[2+4+8+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETFACING;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
for(int i = 0; i < 8; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
for(int i = 0; i < 8; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
for(int i = 0; i < 8; i++){
rawBytes[30+i] = intValues[i];
}
break;
case MOVEUPDATE: case MOVEUPDATE:
rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+4]; rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+4+4];
//message header //message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY; rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header //entity messaage header
@ -1212,10 +903,14 @@ public class EntityMessage extends NetworkMessage {
for(int i = 0; i < 8; i++){ for(int i = 0; i < 8; i++){
rawBytes[70+i] = intValues[i]; rawBytes[70+i] = intValues[i];
} }
intValues = ByteStreamUtils.serializeIntToBytes(treeState); intValues = ByteStreamUtils.serializeIntToBytes(propertyValueInt);
for(int i = 0; i < 4; i++){ for(int i = 0; i < 4; i++){
rawBytes[78+i] = intValues[i]; rawBytes[78+i] = intValues[i];
} }
intValues = ByteStreamUtils.serializeIntToBytes(treeState);
for(int i = 0; i < 4; i++){
rawBytes[82+i] = intValues[i];
}
break; break;
case ATTACKUPDATE: case ATTACKUPDATE:
rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+4]; rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+4];
@ -1271,33 +966,6 @@ public class EntityMessage extends NetworkMessage {
//entity messaage header //entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK; rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK;
break; break;
case MOVE:
rawBytes = new byte[2+4+8+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_MOVE;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
for(int i = 0; i < 8; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
for(int i = 0; i < 8; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
for(int i = 0; i < 8; i++){
rawBytes[30+i] = intValues[i];
}
break;
case KILL: case KILL:
rawBytes = new byte[2+8+4]; rawBytes = new byte[2+8+4];
//message header //message header
@ -1324,29 +992,6 @@ public class EntityMessage extends NetworkMessage {
rawBytes[2+i] = intValues[i]; rawBytes[2+i] = intValues[i];
} }
break; break;
case SETBEHAVIORTREE:
rawBytes = new byte[2+4+8+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(treeType);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(treeStatus);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
break;
case SETPROPERTY: case SETPROPERTY:
rawBytes = new byte[2+4+8+4+4]; rawBytes = new byte[2+4+8+4+4];
//message header //message header
@ -1370,144 +1015,6 @@ public class EntityMessage extends NetworkMessage {
rawBytes[18+i] = intValues[i]; rawBytes[18+i] = intValues[i];
} }
break; break;
case SETBTREEPROPERTYINT:
rawBytes = new byte[2+4+8+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYINT;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(bTreeID);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyID);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyValueInt);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
break;
case SETBTREEPROPERTYFLOAT:
rawBytes = new byte[2+4+8+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYFLOAT;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(bTreeID);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyID);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeFloatToBytes(propertyValueFloat);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
} break;
case SETBTREEPROPERTYDOUBLE:
rawBytes = new byte[2+4+8+4+4+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYDOUBLE;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(bTreeID);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyID);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(propertyValueDouble);
for(int i = 0; i < 8; i++){
rawBytes[22+i] = intValues[i];
}
break;
case SETBTREEPROPERTYSTRING:
rawBytes = new byte[2+4+8+4+4+4+propertyValueString.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYSTRING;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(bTreeID);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyID);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyValueString.length());
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
stringBytes = propertyValueString.getBytes();
for(int i = 0; i < propertyValueString.length(); i++){
rawBytes[26+i] = stringBytes[i];
}
break;
case SETBTREEPROPERTYENUM:
rawBytes = new byte[2+4+8+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(bTreeID);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyID);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(propertyValueInt);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
break;
case ATTACHENTITYTOENTITY: case ATTACHENTITYTOENTITY:
rawBytes = new byte[2+4+4+bone.length()+4]; rawBytes = new byte[2+4+4+bone.length()+4];
//message header //message header
@ -1566,6 +1073,33 @@ public class EntityMessage extends NetworkMessage {
rawBytes[34+creatureTemplate.length()+i] = intValues[i]; rawBytes[34+creatureTemplate.length()+i] = intValues[i];
} }
break; break;
case UPDATEENTITYVIEWDIR:
rawBytes = new byte[2+4+8+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
for(int i = 0; i < 8; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
for(int i = 0; i < 8; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
for(int i = 0; i < 8; i++){
rawBytes[30+i] = intValues[i];
}
break;
} }
serialized = true; serialized = true;
} }

View File

@ -10,10 +10,6 @@ public class LoreMessage extends NetworkMessage {
public enum LoreMessageType { public enum LoreMessageType {
REQUESTRACES, REQUESTRACES,
RESPONSERACES, RESPONSERACES,
REQUESTRACEDATA,
RESPONSERACEDATA,
REQUESTDATA,
RESPONSEDATA,
} }
LoreMessageType messageType; LoreMessageType messageType;
@ -50,18 +46,6 @@ public class LoreMessage extends NetworkMessage {
} }
case TypeBytes.LORE_MESSAGE_TYPE_RESPONSERACES: case TypeBytes.LORE_MESSAGE_TYPE_RESPONSERACES:
return LoreMessage.canParseResponseRacesMessage(byteBuffer); return LoreMessage.canParseResponseRacesMessage(byteBuffer);
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACEDATA:
if(byteBuffer.getRemaining() >= TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACEDATA_SIZE){
return true;
} else {
return false;
}
case TypeBytes.LORE_MESSAGE_TYPE_RESPONSERACEDATA:
return LoreMessage.canParseResponseRaceDataMessage(byteBuffer);
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTDATA:
return LoreMessage.canParseRequestDataMessage(byteBuffer);
case TypeBytes.LORE_MESSAGE_TYPE_RESPONSEDATA:
return LoreMessage.canParseResponseDataMessage(byteBuffer);
} }
return false; return false;
} }
@ -111,117 +95,6 @@ public class LoreMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static LoreMessage parseRequestRaceDataMessage(CircularByteBuffer byteBuffer){
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACEDATA);
stripPacketHeader(byteBuffer);
return rVal;
}
public static LoreMessage constructRequestRaceDataMessage(){
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACEDATA);
rVal.serialize();
return rVal;
}
public static boolean canParseResponseRaceDataMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
int dataSize = 0;
if(currentStreamLength < 6){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(2 + 0));
temporaryByteQueue.add(byteBuffer.peek(2 + 1));
temporaryByteQueue.add(byteBuffer.peek(2 + 2));
temporaryByteQueue.add(byteBuffer.peek(2 + 3));
dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 6 + dataSize){
return false;
}
return true;
}
public static LoreMessage parseResponseRaceDataMessage(CircularByteBuffer byteBuffer){
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACEDATA);
stripPacketHeader(byteBuffer);
rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
public static LoreMessage constructResponseRaceDataMessage(String data){
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACEDATA);
rVal.setdata(data);
rVal.serialize();
return rVal;
}
public static boolean canParseRequestDataMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
int dataSize = 0;
if(currentStreamLength < 6){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(2 + 0));
temporaryByteQueue.add(byteBuffer.peek(2 + 1));
temporaryByteQueue.add(byteBuffer.peek(2 + 2));
temporaryByteQueue.add(byteBuffer.peek(2 + 3));
dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 6 + dataSize){
return false;
}
return true;
}
public static LoreMessage parseRequestDataMessage(CircularByteBuffer byteBuffer){
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTDATA);
stripPacketHeader(byteBuffer);
rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
public static LoreMessage constructRequestDataMessage(String data){
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTDATA);
rVal.setdata(data);
rVal.serialize();
return rVal;
}
public static boolean canParseResponseDataMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
int dataSize = 0;
if(currentStreamLength < 6){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(2 + 0));
temporaryByteQueue.add(byteBuffer.peek(2 + 1));
temporaryByteQueue.add(byteBuffer.peek(2 + 2));
temporaryByteQueue.add(byteBuffer.peek(2 + 3));
dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 6 + dataSize){
return false;
}
return true;
}
public static LoreMessage parseResponseDataMessage(CircularByteBuffer byteBuffer){
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSEDATA);
stripPacketHeader(byteBuffer);
rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
public static LoreMessage constructResponseDataMessage(String data){
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSEDATA);
rVal.setdata(data);
rVal.serialize();
return rVal;
}
@Override @Override
void serialize(){ void serialize(){
byte[] intValues = new byte[8]; byte[] intValues = new byte[8];
@ -249,58 +122,6 @@ public class LoreMessage extends NetworkMessage {
rawBytes[6+i] = stringBytes[i]; rawBytes[6+i] = stringBytes[i];
} }
break; break;
case REQUESTRACEDATA:
rawBytes = new byte[2];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_LORE;
//entity messaage header
rawBytes[1] = TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACEDATA;
break;
case RESPONSERACEDATA:
rawBytes = new byte[2+4+data.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_LORE;
//entity messaage header
rawBytes[1] = TypeBytes.LORE_MESSAGE_TYPE_RESPONSERACEDATA;
intValues = ByteStreamUtils.serializeIntToBytes(data.length());
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
stringBytes = data.getBytes();
for(int i = 0; i < data.length(); i++){
rawBytes[6+i] = stringBytes[i];
}
break;
case REQUESTDATA:
rawBytes = new byte[2+4+data.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_LORE;
//entity messaage header
rawBytes[1] = TypeBytes.LORE_MESSAGE_TYPE_REQUESTDATA;
intValues = ByteStreamUtils.serializeIntToBytes(data.length());
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
stringBytes = data.getBytes();
for(int i = 0; i < data.length(); i++){
rawBytes[6+i] = stringBytes[i];
}
break;
case RESPONSEDATA:
rawBytes = new byte[2+4+data.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_LORE;
//entity messaage header
rawBytes[1] = TypeBytes.LORE_MESSAGE_TYPE_RESPONSEDATA;
intValues = ByteStreamUtils.serializeIntToBytes(data.length());
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
stringBytes = data.getBytes();
for(int i = 0; i < data.length(); i++){
rawBytes[6+i] = stringBytes[i];
}
break;
} }
serialized = true; serialized = true;
} }

View File

@ -56,16 +56,6 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parseSpawnItemMessage(byteBuffer); rVal = EntityMessage.parseSpawnItemMessage(byteBuffer);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseSetPositionMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETFACING:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetFacingMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE: case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer); rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer);
@ -81,11 +71,6 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parsestartAttackMessage(byteBuffer); rVal = EntityMessage.parsestartAttackMessage(byteBuffer);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseMoveMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_KILL: case TypeBytes.ENTITY_MESSAGE_TYPE_KILL:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseKillMessage(byteBuffer); rVal = EntityMessage.parseKillMessage(byteBuffer);
@ -96,41 +81,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parseDestroyMessage(byteBuffer); rVal = EntityMessage.parseDestroyMessage(byteBuffer);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseSetBehaviorTreeMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY: case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetPropertyMessage(byteBuffer); rVal = EntityMessage.parsesetPropertyMessage(byteBuffer);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYINT:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetBTreePropertyIntMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYFLOAT:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetBTreePropertyFloatMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYDOUBLE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetBTreePropertyDoubleMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYSTRING:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetBTreePropertyStringMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetBTreePropertyEnumMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY: case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer); rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer);
@ -141,6 +96,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parseSpawnFoliageSeedMessage(byteBuffer); rVal = EntityMessage.parseSpawnFoliageSeedMessage(byteBuffer);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer);
}
break;
} }
break; break;
case TypeBytes.MESSAGE_TYPE_LORE: case TypeBytes.MESSAGE_TYPE_LORE:
@ -156,26 +116,6 @@ SYNCHRONIZATION_MESSAGE,
rVal = LoreMessage.parseResponseRacesMessage(byteBuffer); rVal = LoreMessage.parseResponseRacesMessage(byteBuffer);
} }
break; break;
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACEDATA:
if(LoreMessage.canParseMessage(byteBuffer,secondByte)){
rVal = LoreMessage.parseRequestRaceDataMessage(byteBuffer);
}
break;
case TypeBytes.LORE_MESSAGE_TYPE_RESPONSERACEDATA:
if(LoreMessage.canParseMessage(byteBuffer,secondByte)){
rVal = LoreMessage.parseResponseRaceDataMessage(byteBuffer);
}
break;
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTDATA:
if(LoreMessage.canParseMessage(byteBuffer,secondByte)){
rVal = LoreMessage.parseRequestDataMessage(byteBuffer);
}
break;
case TypeBytes.LORE_MESSAGE_TYPE_RESPONSEDATA:
if(LoreMessage.canParseMessage(byteBuffer,secondByte)){
rVal = LoreMessage.parseResponseDataMessage(byteBuffer);
}
break;
} }
break; break;
case TypeBytes.MESSAGE_TYPE_PLAYER: case TypeBytes.MESSAGE_TYPE_PLAYER:
@ -206,11 +146,6 @@ SYNCHRONIZATION_MESSAGE,
rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer); rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTCHUNK:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestChunkMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer); rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer);

Some files were not shown because too many files have changed in this diff Show More