play audio on client when server has collision
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-08-08 14:10:26 -04:00
parent ab4b64942d
commit ee44f76dcc
18 changed files with 579 additions and 4 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -18,7 +18,6 @@ Things that feel bad:
Part of this may be cylinder collidable instead of capsule
Sound effect on hit
Sound effect on block
Allow block hotboxes to block damage
Server packet on damage collision

View File

@ -516,6 +516,7 @@ Sound effects on footstep
New sound effects for movement
Jump sound effects
Don't play walking audio when entity is jumping
Sound effect on sword hit
# TODO

73
net/combat.json Normal file
View File

@ -0,0 +1,73 @@
{
"outputPath" : "./src/main/java/electrosphere/net/parser/",
"packageName" : "electrosphere.net.parser",
"categories":[
{
"categoryName" : "Combat",
"data" : [
{
"name" : "entityID",
"type" : "FIXED_INT"
},
{
"name" : "receiverEntityID",
"type" : "FIXED_INT"
},
{
"name" : "positionX",
"type" : "FIXED_DOUBLE"
},
{
"name" : "positionY",
"type" : "FIXED_DOUBLE"
},
{
"name" : "positionZ",
"type" : "FIXED_DOUBLE"
},
{
"name" : "rotationX",
"type" : "FIXED_DOUBLE"
},
{
"name" : "rotationY",
"type" : "FIXED_DOUBLE"
},
{
"name" : "rotationZ",
"type" : "FIXED_DOUBLE"
},
{
"name" : "rotationW",
"type" : "FIXED_DOUBLE"
},
{
"name" : "time",
"type" : "FIXED_LONG"
},
{
"name" : "hitboxType",
"type" : "VAR_STRING"
},
{
"name" : "hurtboxType",
"type" : "VAR_STRING"
}
],
"messageTypes" : [
{
"messageName" : "serverReportHitboxCollision",
"description" : "Reports to clients that a hitbox collision happened",
"data" : [
"entityID",
"receiverEntityID",
"time",
"hitboxType",
"hurtboxType"
]
}
]
}
]
}

View File

@ -0,0 +1,89 @@
package electrosphere.audio.collision;
import java.util.Random;
import org.joml.Vector3d;
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.logger.LoggerInterface;
/**
* Client service to play audio when hitbox collisions happen
*/
public class HitboxAudioService {
/**
* Default audio files to play. Eventually should probably refactor into service that determines audio based on materials
*/
static String[] defaultHitboxAudio = new String[]{
"Audio/weapons/collisions/Massive Punch A.wav",
"Audio/weapons/collisions/Massive Punch B.wav",
"Audio/weapons/collisions/Massive Punch C.wav",
};
/**
* The random for selecting which file to play
*/
Random random = new Random();
/**
* Plays an interaction
* @param voxelType The voxel type
* @param type The interaction type
*/
public void playAudio(Entity senderEntity, Entity receiverEntity, String hitboxType, String hurtboxType){
String audioPath = this.getAudioPath(senderEntity, receiverEntity, hitboxType, hurtboxType);
if(audioPath != null){
Globals.virtualAudioSourceManager.createVirtualAudioSource(audioPath, VirtualAudioSourceType.CREATURE, false);
}
}
/**
* Plays an interaction at a given position
* @param voxelType The voxel type
* @param type The interaction type
* @param position The position of the audio
*/
public void playAudioPositional(Entity senderEntity, Entity receiverEntity, String hitboxType, String hurtboxType, Vector3d position){
String audioPath = this.getAudioPath(senderEntity, receiverEntity, hitboxType, hurtboxType);
if(audioPath != null){
Globals.virtualAudioSourceManager.createVirtualAudioSource(audioPath, VirtualAudioSourceType.CREATURE, false, position);
}
}
/**
* Gets the audio file to play when the given entities collide
* @param senderEntity The entity with the hitbox
* @param receiverEntity The entity with the hurtbox
* @param hitboxType The hitbox type
* @param hurtboxType The hurthox type
* @return The audio file to play
*/
private String getAudioPath(Entity senderEntity, Entity receiverEntity, String hitboxType, String hurtboxType){
if(ItemUtils.isWeapon(senderEntity)){
if(CreatureUtils.isCreature(receiverEntity)){
return this.getWeaponOnCreature();
} else {
LoggerInterface.loggerEngine.WARNING("Getting audio for unhandled hurtbox collision type!");
}
} else {
LoggerInterface.loggerEngine.WARNING("Getting audio for unhandled hitbox collision type!");
}
return null;
}
/**
* Gets the audio to play when a weapon collides with a creature
* @return The audio file to play
*/
private String getWeaponOnCreature(){
//return the audio
int roll = random.nextInt(defaultHitboxAudio.length);
return defaultHitboxAudio[roll];
}
}

View File

@ -0,0 +1,41 @@
package electrosphere.client.collision;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.logger.LoggerInterface;
/**
* Client methods for handling hitbox collisions reported by the server
*/
public class ClientHitboxCollision {
/**
* Performs client logic for a collision that the server reports
* @param position The real-space position of the collision
* @param hitboxType The type of hitbox
* @param hurtboxType The type of hurtbox
*/
public static void handleHitboxCollision(Entity senderEntity, Entity receiverEntity, Vector3d position, String hitboxType, String hurtboxType){
switch(hitboxType){
case HitboxData.HITBOX_TYPE_HIT_CONNECTED:
case HitboxData.HITBOX_TYPE_HIT: {
switch(hurtboxType){
case HitboxData.HITBOX_TYPE_HURT:
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
Globals.hitboxAudioService.playAudio(senderEntity, receiverEntity, hitboxType, hurtboxType);
} break;
default: {
LoggerInterface.loggerEngine.WARNING("Client handling undefined hurtbox type: " + hurtboxType);
} break;
}
} break;
default: {
LoggerInterface.loggerEngine.WARNING("Client handling undefined hitbox type: " + hitboxType);
} break;
}
}
}

View File

@ -9,6 +9,7 @@ import org.joml.Vector3f;
import electrosphere.audio.AudioEngine;
import electrosphere.audio.VirtualAudioSourceManager;
import electrosphere.audio.collision.HitboxAudioService;
import electrosphere.audio.movement.MovementAudioService;
import electrosphere.auth.AuthenticationManager;
import electrosphere.client.fluid.cells.FluidCellManager;
@ -106,6 +107,7 @@ public class Globals {
public static AudioEngine audioEngine;
public static VirtualAudioSourceManager virtualAudioSourceManager;
public static MovementAudioService movementAudioService = new MovementAudioService();
public static HitboxAudioService hitboxAudioService = new HitboxAudioService();
//
@ -473,7 +475,9 @@ public class Globals {
"/Audio/weapons/swordUnsheath1.ogg",
"/Audio/weapons/swoosh-03.ogg",
"/Audio/movement/Equip A.wav",
"/Audio/movement/landing-on-the-ground-4.wav",
"/Audio/weapons/collisions/Massive Punch A.wav",
"/Audio/weapons/collisions/Massive Punch B.wav",
"/Audio/weapons/collisions/Massive Punch C.wav",
};
LoggerInterface.loggerStartup.INFO("Loading default audio resources");
for(String path : audioToInit){

View File

@ -7,6 +7,7 @@ import java.util.concurrent.Semaphore;
import electrosphere.engine.Globals;
import electrosphere.net.client.protocol.AuthProtocol;
import electrosphere.net.client.protocol.CharacterProtocol;
import electrosphere.net.client.protocol.CombatProtocol;
import electrosphere.net.client.protocol.EntityProtocol;
import electrosphere.net.client.protocol.InventoryProtocol;
import electrosphere.net.client.protocol.LoreProtocol;
@ -16,6 +17,7 @@ import electrosphere.net.client.protocol.SynchronizationProtocol;
import electrosphere.net.client.protocol.TerrainProtocol;
import electrosphere.net.parser.net.message.AuthMessage;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.CombatMessage;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.LoreMessage;
@ -45,6 +47,7 @@ public class MessageProtocol {
//The individual protocols
AuthProtocol authProtocol = new AuthProtocol();
CharacterProtocol characterProtocol = new CharacterProtocol();
CombatProtocol combatProtocol = new CombatProtocol();
EntityProtocol entityProtocol = new EntityProtocol();
InventoryProtocol inventoryProtocol = new InventoryProtocol();
LoreProtocol loreProtocol = new LoreProtocol();
@ -67,6 +70,9 @@ public class MessageProtocol {
case CHARACTER_MESSAGE:
result = this.characterProtocol.handleAsyncMessage((CharacterMessage)message);
break;
case COMBAT_MESSAGE: {
result = this.combatProtocol.handleAsyncMessage((CombatMessage)message);
} break;
case ENTITY_MESSAGE:
result = this.entityProtocol.handleAsyncMessage((EntityMessage)message);
break;
@ -109,6 +115,9 @@ public class MessageProtocol {
case CHARACTER_MESSAGE:
this.characterProtocol.handleSyncMessage((CharacterMessage)message);
break;
case COMBAT_MESSAGE: {
this.combatProtocol.handleSyncMessage((CombatMessage)message);
} break;
case ENTITY_MESSAGE:
this.entityProtocol.handleSyncMessage((EntityMessage)message);
break;

View File

@ -0,0 +1,33 @@
package electrosphere.net.client.protocol;
import org.joml.Vector3d;
import electrosphere.client.collision.ClientHitboxCollision;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.net.parser.net.message.CombatMessage;
import electrosphere.net.template.ClientProtocolTemplate;
/**
* Client protocl for dealing with combat messages
*/
public class CombatProtocol implements ClientProtocolTemplate<CombatMessage> {
@Override
public CombatMessage handleAsyncMessage(CombatMessage message) {
return message;
}
@Override
public void handleSyncMessage(CombatMessage message) {
switch(message.getMessageSubtype()){
case SERVERREPORTHITBOXCOLLISION: {
Vector3d position = new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ());
Entity senderEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
Entity receiverEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getreceiverEntityID());
ClientHitboxCollision.handleHitboxCollision(senderEntity, receiverEntity, position, message.gethitboxType(), message.gethurtboxType());
} break;
}
}
}

View File

@ -0,0 +1,252 @@
package electrosphere.net.parser.net.message;
import electrosphere.net.parser.util.ByteStreamUtils;
import electrosphere.net.parser.net.raw.CircularByteBuffer;
import java.util.LinkedList;
import java.util.List;
public class CombatMessage extends NetworkMessage {
public enum CombatMessageType {
SERVERREPORTHITBOXCOLLISION,
}
CombatMessageType messageType;
int entityID;
int receiverEntityID;
double positionX;
double positionY;
double positionZ;
double rotationX;
double rotationY;
double rotationZ;
double rotationW;
long time;
String hitboxType;
String hurtboxType;
CombatMessage(CombatMessageType messageType){
this.type = MessageType.COMBAT_MESSAGE;
this.messageType = messageType;
}
public CombatMessageType getMessageSubtype(){
return this.messageType;
}
public int getentityID() {
return entityID;
}
public void setentityID(int entityID) {
this.entityID = entityID;
}
public int getreceiverEntityID() {
return receiverEntityID;
}
public void setreceiverEntityID(int receiverEntityID) {
this.receiverEntityID = receiverEntityID;
}
public double getpositionX() {
return positionX;
}
public void setpositionX(double positionX) {
this.positionX = positionX;
}
public double getpositionY() {
return positionY;
}
public void setpositionY(double positionY) {
this.positionY = positionY;
}
public double getpositionZ() {
return positionZ;
}
public void setpositionZ(double positionZ) {
this.positionZ = positionZ;
}
public double getrotationX() {
return rotationX;
}
public void setrotationX(double rotationX) {
this.rotationX = rotationX;
}
public double getrotationY() {
return rotationY;
}
public void setrotationY(double rotationY) {
this.rotationY = rotationY;
}
public double getrotationZ() {
return rotationZ;
}
public void setrotationZ(double rotationZ) {
this.rotationZ = rotationZ;
}
public double getrotationW() {
return rotationW;
}
public void setrotationW(double rotationW) {
this.rotationW = rotationW;
}
public long gettime() {
return time;
}
public void settime(long time) {
this.time = time;
}
public String gethitboxType() {
return hitboxType;
}
public void sethitboxType(String hitboxType) {
this.hitboxType = hitboxType;
}
public String gethurtboxType() {
return hurtboxType;
}
public void sethurtboxType(String hurtboxType) {
this.hurtboxType = hurtboxType;
}
static void stripPacketHeader(CircularByteBuffer byteBuffer){
byteBuffer.read(2);
}
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
switch(secondByte){
case TypeBytes.COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION:
return CombatMessage.canParseserverReportHitboxCollisionMessage(byteBuffer);
}
return false;
}
public static boolean canParseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 10){
return false;
}
if(currentStreamLength < 18){
return false;
}
int hitboxTypeSize = 0;
if(currentStreamLength < 22){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(18 + 0));
temporaryByteQueue.add(byteBuffer.peek(18 + 1));
temporaryByteQueue.add(byteBuffer.peek(18 + 2));
temporaryByteQueue.add(byteBuffer.peek(18 + 3));
hitboxTypeSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 22 + hitboxTypeSize){
return false;
}
int hurtboxTypeSize = 0;
if(currentStreamLength < 26){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(22 + hitboxTypeSize + 0));
temporaryByteQueue.add(byteBuffer.peek(22 + hitboxTypeSize + 1));
temporaryByteQueue.add(byteBuffer.peek(22 + hitboxTypeSize + 2));
temporaryByteQueue.add(byteBuffer.peek(22 + hitboxTypeSize + 3));
hurtboxTypeSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 26 + hitboxTypeSize + hurtboxTypeSize){
return false;
}
return true;
}
public static CombatMessage parseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setreceiverEntityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.sethitboxType(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
rVal.sethurtboxType(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
public static CombatMessage constructserverReportHitboxCollisionMessage(int entityID,int receiverEntityID,long time,String hitboxType,String hurtboxType){
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
rVal.setentityID(entityID);
rVal.setreceiverEntityID(receiverEntityID);
rVal.settime(time);
rVal.sethitboxType(hitboxType);
rVal.sethurtboxType(hurtboxType);
rVal.serialize();
return rVal;
}
@Override
void serialize(){
byte[] intValues = new byte[8];
byte[] stringBytes;
switch(this.messageType){
case SERVERREPORTHITBOXCOLLISION:
rawBytes = new byte[2+4+4+8+4+hitboxType.length()+4+hurtboxType.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_COMBAT;
//entity messaage header
rawBytes[1] = TypeBytes.COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(receiverEntityID);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeLongToBytes(time);
for(int i = 0; i < 8; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(hitboxType.length());
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
stringBytes = hitboxType.getBytes();
for(int i = 0; i < hitboxType.length(); i++){
rawBytes[22+i] = stringBytes[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(hurtboxType.length());
for(int i = 0; i < 4; i++){
rawBytes[22+hitboxType.length()+i] = intValues[i];
}
stringBytes = hurtboxType.getBytes();
for(int i = 0; i < hurtboxType.length(); i++){
rawBytes[26+hitboxType.length()+i] = stringBytes[i];
}
break;
}
serialized = true;
}
}

View File

@ -17,6 +17,7 @@ AUTH_MESSAGE,
CHARACTER_MESSAGE,
INVENTORY_MESSAGE,
SYNCHRONIZATION_MESSAGE,
COMBAT_MESSAGE,
}
MessageType type;
@ -393,6 +394,16 @@ SYNCHRONIZATION_MESSAGE,
break;
}
break;
case TypeBytes.MESSAGE_TYPE_COMBAT:
secondByte = byteBuffer.peek(1);
switch(secondByte){
case TypeBytes.COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION:
if(CombatMessage.canParseMessage(byteBuffer,secondByte)){
rVal = CombatMessage.parseserverReportHitboxCollisionMessage(byteBuffer);
}
break;
}
break;
}
}
return rVal;

View File

@ -14,6 +14,7 @@ Message categories
public static final byte MESSAGE_TYPE_CHARACTER = 6;
public static final byte MESSAGE_TYPE_INVENTORY = 7;
public static final byte MESSAGE_TYPE_SYNCHRONIZATION = 8;
public static final byte MESSAGE_TYPE_COMBAT = 9;
/*
Entity subcategories
*/
@ -168,5 +169,12 @@ Message categories
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION_SIZE = 18;
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE_SIZE = 10;
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE_SIZE = 10;
/*
Combat subcategories
*/
public static final byte COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION = 0;
/*
Combat packet sizes
*/
}

View File

@ -8,6 +8,7 @@ import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.AuthMessage;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.CombatMessage;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.LoreMessage;
@ -18,6 +19,7 @@ import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.protocol.AuthProtocol;
import electrosphere.net.server.protocol.CharacterProtocol;
import electrosphere.net.server.protocol.CombatProtocol;
import electrosphere.net.server.protocol.EntityProtocol;
import electrosphere.net.server.protocol.InventoryProtocol;
import electrosphere.net.server.protocol.LoreProtocol;
@ -43,6 +45,7 @@ public class MessageProtocol {
//The individual protocols
AuthProtocol authProtocol = new AuthProtocol();
CharacterProtocol characterProtocol = new CharacterProtocol();
CombatProtocol combatProtocol = new CombatProtocol();
EntityProtocol entityProtocol = new EntityProtocol();
InventoryProtocol inventoryProtocol = new InventoryProtocol();
LoreProtocol loreProtocol = new LoreProtocol();
@ -74,6 +77,9 @@ public class MessageProtocol {
case CHARACTER_MESSAGE:
result = this.characterProtocol.handleAsyncMessage(serverConnectionHandler, (CharacterMessage)message);
break;
case COMBAT_MESSAGE: {
result = this.combatProtocol.handleAsyncMessage(serverConnectionHandler, (CombatMessage)message);
} break;
case ENTITY_MESSAGE:
result = this.entityProtocol.handleAsyncMessage(serverConnectionHandler, (EntityMessage)message);
break;
@ -116,6 +122,9 @@ public class MessageProtocol {
case CHARACTER_MESSAGE:
this.characterProtocol.handleSyncMessage(serverConnectionHandler, (CharacterMessage)message);
break;
case COMBAT_MESSAGE: {
this.combatProtocol.handleSyncMessage(serverConnectionHandler, (CombatMessage)message);
} break;
case ENTITY_MESSAGE:
this.entityProtocol.handleSyncMessage(serverConnectionHandler, (EntityMessage)message);
break;

View File

@ -0,0 +1,31 @@
package electrosphere.net.server.protocol;
import electrosphere.net.parser.net.message.CombatMessage;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.template.ServerProtocolTemplate;
/**
* Server protocol for dealing with combat messages
*/
public class CombatProtocol implements ServerProtocolTemplate<CombatMessage> {
@Override
public CombatMessage handleAsyncMessage(ServerConnectionHandler connectionHandler, CombatMessage message) {
switch(message.getMessageSubtype()){
case SERVERREPORTHITBOXCOLLISION: {
//silently ignore
} break;
}
return null;
}
@Override
public void handleSyncMessage(ServerConnectionHandler connectionHandler, CombatMessage message) {
switch(message.getMessageSubtype()){
case SERVERREPORTHITBOXCOLLISION: {
//silently ignore
} break;
}
}
}

View File

@ -6,6 +6,7 @@ import org.ode4j.ode.DGeom;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState;
@ -15,6 +16,8 @@ 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.net.parser.net.message.CombatMessage;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
/**
* Callback for managing collisions on the server
@ -55,7 +58,18 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(impactorParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(impactorParent);
//tell clients an impact just happened
DataCellSearchUtils.getEntityDataCell(receiverParent).broadcastNetworkMessage(
CombatMessage.constructserverReportHitboxCollisionMessage(
impactorParent.getId(),
receiverParent.getId(),
Globals.timekeeper.getNumberOfSimFramesElapsed(),
impactorShapeStatus.getHitboxData().getType(),
receiverShapeStatus.getHitboxData().getType()
)
);
if(isItem){
if(hitboxAttachParent != receiverParent){
int damage = ItemUtils.getWeaponDataRaw(impactorParent).getDamage();

View File

@ -14,7 +14,8 @@
"./net/server.json",
"./net/character.json",
"./net/inventory.json",
"./net/synchronization.json"
"./net/synchronization.json",
"./net/combat.json"
]
}