block sfx
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-08-12 13:07:40 -04:00
parent 8e48250013
commit 8e6c9e97b0
18 changed files with 236 additions and 11 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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

View File

@ -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)){
return this.getWeaponOnCreature();
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];
}
}

View File

@ -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);

View File

@ -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){

View File

@ -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);
}
}

View File

@ -239,12 +239,19 @@ public class ServerAttackTree implements BehaviorTree {
stillHold = false;
}
/**
* Interrupts the tree
*/
public void interrupt(){
setState(AttackTreeState.IDLE);
}
public void slowdown(){
setState(AttackTreeState.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);
}
}
}
@Override

View File

@ -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: {

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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";

View File

@ -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
)
);
}
}
}