This commit is contained in:
parent
8e48250013
commit
8e6c9e97b0
BIN
assets/Audio/weapons/collisions/Sword Hit A.wav
Normal file
BIN
assets/Audio/weapons/collisions/Sword Hit A.wav
Normal file
Binary file not shown.
BIN
assets/Audio/weapons/collisions/Sword Hit B.wav
Normal file
BIN
assets/Audio/weapons/collisions/Sword Hit B.wav
Normal file
Binary file not shown.
BIN
assets/Audio/weapons/collisions/Sword Hit C.wav
Normal file
BIN
assets/Audio/weapons/collisions/Sword Hit C.wav
Normal file
Binary file not shown.
BIN
assets/Audio/weapons/collisions/Sword Hit D.wav
Normal file
BIN
assets/Audio/weapons/collisions/Sword Hit D.wav
Normal file
Binary file not shown.
BIN
assets/Audio/weapons/collisions/Sword Hit E.wav
Normal file
BIN
assets/Audio/weapons/collisions/Sword Hit E.wav
Normal file
Binary file not shown.
@ -9,7 +9,6 @@
|
||||
review combat code (lifestate, damage calculation, etc)
|
||||
- Allow block hotboxxes to block damage
|
||||
audio fx for everything
|
||||
- Block SFX
|
||||
|
||||
+ rearchitecture
|
||||
|
||||
@ -18,6 +17,4 @@
|
||||
Hitboxes between server and client feel wayyyy off
|
||||
|
||||
+ bug fixes
|
||||
On attack, the server weapon does not swing (it instead stops aligning)
|
||||
The server does not interrupt attack on animation end
|
||||
|
||||
|
||||
@ -539,6 +539,8 @@ Pass at client-server physics synchronization
|
||||
|
||||
(08/12/2024)
|
||||
Fix server animation playing at reduced timescale
|
||||
Block override concept for hitboxes
|
||||
Block sfx
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -9,6 +9,8 @@ import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.types.creature.CreatureUtils;
|
||||
import electrosphere.entity.types.item.ItemUtils;
|
||||
import electrosphere.entity.types.object.ObjectUtils;
|
||||
import electrosphere.game.data.collidable.HitboxData;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
|
||||
/**
|
||||
@ -25,6 +27,17 @@ public class HitboxAudioService {
|
||||
"Audio/weapons/collisions/Massive Punch C.wav",
|
||||
};
|
||||
|
||||
/**
|
||||
* Default audio files to play. Eventually should probably refactor into service that determines audio based on materials
|
||||
*/
|
||||
static String[] defaultBlockboxAudio = new String[]{
|
||||
"Audio/weapons/collisions/Sword Hit A.wav",
|
||||
"Audio/weapons/collisions/Sword Hit B.wav",
|
||||
"Audio/weapons/collisions/Sword Hit C.wav",
|
||||
"Audio/weapons/collisions/Sword Hit D.wav",
|
||||
"Audio/weapons/collisions/Sword Hit E.wav",
|
||||
};
|
||||
|
||||
/**
|
||||
* The random for selecting which file to play
|
||||
*/
|
||||
@ -64,11 +77,66 @@ public class HitboxAudioService {
|
||||
* @return The audio file to play
|
||||
*/
|
||||
private String getAudioPath(Entity senderEntity, Entity receiverEntity, String hitboxType, String hurtboxType){
|
||||
boolean isBlockSound = false;
|
||||
boolean isDamageSound = false;
|
||||
switch(hitboxType){
|
||||
case HitboxData.HITBOX_TYPE_HIT:
|
||||
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
|
||||
switch(hurtboxType){
|
||||
case HitboxData.HITBOX_TYPE_HIT:
|
||||
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
|
||||
isBlockSound = true;
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
isBlockSound = true;
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
isDamageSound = true;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
switch(hurtboxType){
|
||||
case HitboxData.HITBOX_TYPE_HIT:
|
||||
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
|
||||
isBlockSound = true;
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
isBlockSound = true;
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
|
||||
} break;
|
||||
}
|
||||
if(ItemUtils.isWeapon(senderEntity)){
|
||||
if(CreatureUtils.isCreature(receiverEntity)){
|
||||
if(isBlockSound){
|
||||
return this.getWeaponOnCreature();
|
||||
} else if(isDamageSound){
|
||||
return this.getWeaponOnCreature();
|
||||
}
|
||||
} else if(ItemUtils.isWeapon(receiverEntity)){
|
||||
if(isBlockSound){
|
||||
return this.getWeaponOnBlock();
|
||||
}
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.WARNING("Getting audio for unhandled hurtbox collision type!");
|
||||
String message = "Getting audio for unhandled hurtbox collision type!\n" +
|
||||
"Is creature: " + CreatureUtils.isCreature(receiverEntity) + "\n" +
|
||||
"Is item: " + ItemUtils.isItem(receiverEntity) + "\n" +
|
||||
"Is weapon: " + ItemUtils.isWeapon(receiverEntity) + "\n" +
|
||||
"Is object: " + ObjectUtils.isObject(receiverEntity);
|
||||
if(ItemUtils.isItem(receiverEntity)){
|
||||
message = message + "\nItem Type: " + ItemUtils.getType(receiverEntity);
|
||||
}
|
||||
LoggerInterface.loggerEngine.WARNING(message);
|
||||
}
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.WARNING("Getting audio for unhandled hitbox collision type!");
|
||||
@ -86,4 +154,13 @@ public class HitboxAudioService {
|
||||
return defaultHitboxAudio[roll];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the audio to play when a weapon collides with a block box
|
||||
* @return The audio file to play
|
||||
*/
|
||||
private String getWeaponOnBlock(){
|
||||
int roll = random.nextInt(defaultBlockboxAudio.length);
|
||||
return defaultBlockboxAudio[roll];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -25,7 +25,10 @@ public class ClientHitboxCollision {
|
||||
switch(hurtboxType){
|
||||
case HitboxData.HITBOX_TYPE_HURT:
|
||||
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
|
||||
Globals.hitboxAudioService.playAudio(senderEntity, receiverEntity, hitboxType, hurtboxType);
|
||||
Globals.hitboxAudioService.playAudioPositional(senderEntity, receiverEntity, hitboxType, hurtboxType, position);
|
||||
} break;
|
||||
case HitboxData.HITBOX_TYPE_BLOCK_CONNECTED: {
|
||||
Globals.hitboxAudioService.playAudioPositional(senderEntity, receiverEntity, hitboxType, hurtboxType, position);
|
||||
} break;
|
||||
default: {
|
||||
LoggerInterface.loggerEngine.WARNING("Client handling undefined hurtbox type: " + hurtboxType);
|
||||
|
||||
@ -478,6 +478,11 @@ public class Globals {
|
||||
"/Audio/weapons/collisions/Massive Punch A.wav",
|
||||
"/Audio/weapons/collisions/Massive Punch B.wav",
|
||||
"/Audio/weapons/collisions/Massive Punch C.wav",
|
||||
"Audio/weapons/collisions/Sword Hit A.wav",
|
||||
"Audio/weapons/collisions/Sword Hit B.wav",
|
||||
"Audio/weapons/collisions/Sword Hit C.wav",
|
||||
"Audio/weapons/collisions/Sword Hit D.wav",
|
||||
"Audio/weapons/collisions/Sword Hit E.wav",
|
||||
};
|
||||
LoggerInterface.loggerStartup.INFO("Loading default audio resources");
|
||||
for(String path : audioToInit){
|
||||
|
||||
@ -21,5 +21,14 @@ public class ClientEntityUtils {
|
||||
CollisionObjUtils.clientPositionCharacter(entity, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys an entity on the client
|
||||
* @param entity the entity to destroy
|
||||
*/
|
||||
public static void destroyEntity(Entity entity){
|
||||
//deregister all behavior trees
|
||||
EntityUtils.cleanUpEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -239,12 +239,19 @@ public class ServerAttackTree implements BehaviorTree {
|
||||
stillHold = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupts the tree
|
||||
*/
|
||||
public void interrupt(){
|
||||
setState(AttackTreeState.IDLE);
|
||||
//activate hitboxes
|
||||
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
|
||||
for(Entity currentAttached : attachedEntities){
|
||||
if(HitboxCollectionState.hasHitboxState(currentAttached)){
|
||||
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
|
||||
currentState.setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void slowdown(){
|
||||
setState(AttackTreeState.COOLDOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package electrosphere.entity.state.block;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
@ -12,6 +14,8 @@ import electrosphere.net.parser.net.message.SynchronizationMessage;
|
||||
|
||||
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||
import electrosphere.entity.state.block.ClientBlockTree.BlockState;
|
||||
import electrosphere.entity.state.hitbox.HitboxCollectionState;
|
||||
import electrosphere.entity.types.attach.AttachUtils;
|
||||
import electrosphere.game.data.creature.type.block.BlockSystem;
|
||||
import electrosphere.game.data.creature.type.block.BlockVariant;
|
||||
import electrosphere.net.synchronization.annotation.SyncedField;
|
||||
@ -96,6 +100,15 @@ public class ServerBlockTree implements BehaviorTree {
|
||||
public void stop(){
|
||||
this.stateTransitionUtil.reset();
|
||||
setState(BlockState.COOLDOWN);
|
||||
//activate hitboxes
|
||||
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
|
||||
for(Entity currentAttached : attachedEntities){
|
||||
if(HitboxCollectionState.hasHitboxState(currentAttached)){
|
||||
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
|
||||
currentState.setActive(false);
|
||||
currentState.setBlockOverride(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -105,9 +118,27 @@ public class ServerBlockTree implements BehaviorTree {
|
||||
this.stateTransitionUtil.simulate(BlockState.WIND_UP);
|
||||
} break;
|
||||
case BLOCKING: {
|
||||
//activate hitboxes
|
||||
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
|
||||
for(Entity currentAttached : attachedEntities){
|
||||
if(HitboxCollectionState.hasHitboxState(currentAttached)){
|
||||
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
|
||||
currentState.setActive(true);
|
||||
currentState.setBlockOverride(true);
|
||||
}
|
||||
}
|
||||
this.stateTransitionUtil.simulate(BlockState.BLOCKING);
|
||||
} break;
|
||||
case COOLDOWN: {
|
||||
//activate hitboxes
|
||||
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
|
||||
for(Entity currentAttached : attachedEntities){
|
||||
if(HitboxCollectionState.hasHitboxState(currentAttached)){
|
||||
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
|
||||
currentState.setActive(false);
|
||||
currentState.setBlockOverride(false);
|
||||
}
|
||||
}
|
||||
this.stateTransitionUtil.simulate(BlockState.COOLDOWN);
|
||||
} break;
|
||||
case NOT_BLOCKING: {
|
||||
|
||||
@ -73,6 +73,9 @@ public class HitboxCollectionState {
|
||||
//controls whether the hitbox state is active or not
|
||||
boolean active = true;
|
||||
|
||||
//controls whether active hitboxes should be overwritten with block boxes
|
||||
boolean blockOverride = false;
|
||||
|
||||
//the associated manager
|
||||
HitboxManager manager;
|
||||
|
||||
@ -153,7 +156,7 @@ public class HitboxCollectionState {
|
||||
rVal.hitboxGeomMap.put(hitboxDataRaw.getBone(),geom);
|
||||
}
|
||||
rVal.geoms.add(geom);
|
||||
rVal.geomStateMap.put(geom,new HitboxState(hitboxDataRaw.getBone(), hitboxDataRaw, type, subType, shapeType, true));
|
||||
rVal.geomStateMap.put(geom,new HitboxState(hitboxDataRaw.getBone(), hitboxDataRaw, type, subType, shapeType, false));
|
||||
}
|
||||
|
||||
//create body with all the shapes
|
||||
@ -467,6 +470,26 @@ public class HitboxCollectionState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block override status
|
||||
* @return true if should override hitboxes with blockboxes, false otherwise
|
||||
*/
|
||||
public boolean isBlockOverride(){
|
||||
return this.blockOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the block override of the hitbox
|
||||
* @param state true to override attack hitboxes with block boxes, false otherwise
|
||||
*/
|
||||
public void setBlockOverride(boolean state){
|
||||
this.blockOverride = state;
|
||||
for(DGeom geom : this.geoms){
|
||||
HitboxState shapeState = this.getShapeStatus(geom);
|
||||
shapeState.setBlockOverride(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all DGeoms in the data
|
||||
* @return the list of all DGeoms
|
||||
@ -526,6 +549,10 @@ public class HitboxCollectionState {
|
||||
//controls whether the hitbox is active
|
||||
boolean isActive;
|
||||
|
||||
//controls whether the block override is active or not
|
||||
//if it is active, hitboxes should behave like block boxes
|
||||
boolean blockOverride = false;
|
||||
|
||||
//the previous position of this hitbox shape
|
||||
Vector3d previousWorldPos = null;
|
||||
|
||||
@ -633,6 +660,22 @@ public class HitboxCollectionState {
|
||||
this.isActive = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the block override is active or not
|
||||
* @return true if the block override is active, false otherwise
|
||||
*/
|
||||
public boolean isBlockOverride(){
|
||||
return blockOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the block override is active or not
|
||||
* @param blockOverride true if the block override is active, false otherwise
|
||||
*/
|
||||
public void setBlockOverride(boolean blockOverride){
|
||||
this.blockOverride = blockOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous world position of this hitbox
|
||||
* @return The previous world position
|
||||
|
||||
@ -376,10 +376,17 @@ public class ItemUtils {
|
||||
*/
|
||||
public static Entity clientRecreateContainerItem(Entity item, Entity containingParent){
|
||||
if(isItem(item)){
|
||||
Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(ItemUtils.getType(item));
|
||||
Entity rVal = EntityCreationUtils.createClientNonSpatialEntity();
|
||||
if(getEquipWhitelist(item) != null){
|
||||
rVal.putData(EntityDataStrings.ITEM_EQUIP_WHITELIST, getEquipWhitelist(item));
|
||||
}
|
||||
if(itemData.getWeaponData() != null){
|
||||
rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true);
|
||||
WeaponData weaponData = itemData.getWeaponData();
|
||||
rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass());
|
||||
rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData);
|
||||
}
|
||||
rVal.putData(EntityDataStrings.ITEM_ICON,ItemUtils.getItemIcon(item));
|
||||
rVal.putData(EntityDataStrings.ITEM_EQUIP_CLASS, item.getData(EntityDataStrings.ITEM_EQUIP_CLASS));
|
||||
EntityUtils.setEntityType(rVal, ENTITY_TYPE_ITEM);
|
||||
|
||||
@ -50,6 +50,9 @@ public class HitboxData {
|
||||
//controls whether the hitbox is active or not
|
||||
boolean active = false;
|
||||
|
||||
//override when block state is active. Used to make hitboxes function as blockboxes while blocking
|
||||
boolean blockOverride = false;
|
||||
|
||||
//used for more advanced hitbox spawning to find hitbox position on frame update
|
||||
HitboxPositionCallback positionCallback;
|
||||
|
||||
@ -112,6 +115,22 @@ public class HitboxData {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block override status
|
||||
* @return true if should override hitboxes with block, false otherwise
|
||||
*/
|
||||
public boolean isBlockOverride(){
|
||||
return blockOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status of the block override
|
||||
* @param blockOverride true if should override hitboxes with block, false otherwise
|
||||
*/
|
||||
public void setBlockOverride(boolean blockOverride){
|
||||
this.blockOverride = blockOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bone this hitbox is attached to
|
||||
* @param bone the bone to attach the hitbox to
|
||||
|
||||
@ -358,6 +358,9 @@ public class DebugContentPipeline implements RenderPipeline {
|
||||
return "Textures/color/transparent_yellow.png";
|
||||
}
|
||||
if(shapeStatus.isActive()){
|
||||
if(shapeStatus.isBlockOverride()){
|
||||
return "Textures/transparent_blue.png";
|
||||
}
|
||||
return "Textures/transparent_red.png";
|
||||
}
|
||||
return "Textures/transparent_grey.png";
|
||||
|
||||
@ -16,6 +16,7 @@ import electrosphere.entity.state.movement.ProjectileTree;
|
||||
import electrosphere.entity.types.attach.AttachUtils;
|
||||
import electrosphere.entity.types.creature.CreatureUtils;
|
||||
import electrosphere.entity.types.item.ItemUtils;
|
||||
import electrosphere.game.data.collidable.HitboxData;
|
||||
import electrosphere.net.parser.net.message.CombatMessage;
|
||||
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||
|
||||
@ -45,6 +46,14 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
|
||||
AttachUtils.getParent(impactorParent) != receiverParent
|
||||
;
|
||||
|
||||
boolean isBlockEvent =
|
||||
impactorShapeStatus != null &&
|
||||
receiverShapeStatus != null &&
|
||||
impactorShapeStatus.getType() == HitboxType.HIT &&
|
||||
(receiverShapeStatus.getType() == HitboxType.BLOCK || (receiverShapeStatus.getType() == HitboxType.HIT && receiverShapeStatus.isBlockOverride())) &&
|
||||
AttachUtils.getParent(impactorParent) != receiverParent
|
||||
;
|
||||
|
||||
|
||||
if(impactorShapeStatus != null){
|
||||
impactorShapeStatus.setHadCollision(true);
|
||||
@ -103,6 +112,19 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isBlockEvent){
|
||||
//tell clients an impact just happened
|
||||
DataCellSearchUtils.getEntityDataCell(receiverParent).broadcastNetworkMessage(
|
||||
CombatMessage.constructserverReportHitboxCollisionMessage(
|
||||
impactorParent.getId(),
|
||||
receiverParent.getId(),
|
||||
Globals.timekeeper.getNumberOfSimFramesElapsed(),
|
||||
impactorShapeStatus.getHitboxData().getType(),
|
||||
HitboxData.HITBOX_TYPE_BLOCK_CONNECTED //TODO: more proper block override handling
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user