mirror of https://github.com/basinserver/basin/
entity refactoring
This commit is contained in:
parent
749cc72b59
commit
6f2a750652
|
@ -455,7 +455,7 @@ void entitymeta_read(struct entity* ent, uint8_t* meta, size_t size);
|
|||
|
||||
void entitymeta_write(struct entity* entity, uint8_t** data, size_t* size, struct mempool* pool);
|
||||
|
||||
void updateMetadata(struct entity* ent);
|
||||
void entity_broadcast_metadata(struct entity* entity);
|
||||
|
||||
void entity_jump(struct entity* entity);
|
||||
|
||||
|
@ -471,12 +471,8 @@ double entity_dist_block(struct entity* ent1, double x, double y, double z);
|
|||
|
||||
void entity_collision_bounding_box(struct entity* entity, struct boundingbox* bb);
|
||||
|
||||
int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float shrink);
|
||||
|
||||
int tick_itemstack(struct world* world, struct entity* entity);
|
||||
int entity_move(struct entity* entity, double* motionX, double* motionY, double* motionZ, float shrink);
|
||||
|
||||
void tick_entity(struct world* world, struct entity* entity);
|
||||
|
||||
void freeEntity(struct entity* entity);
|
||||
|
||||
#endif /* BASIN_ENTITY_H_ */
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#ifndef BASIN_ENTITY_IMPL_H
|
||||
#define BASIN_ENTITY_IMPL_H
|
||||
|
||||
#include "entity_impl.h"
|
||||
#include <basin/world.h>
|
||||
#include <basin/entity.h>
|
||||
#include <basin/player.h>
|
||||
#include <basin/inventory.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void onSpawned_minecart(struct world* world, struct entity* entity);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ void player_openInventory(struct player* player, struct inventory* inv);
|
|||
|
||||
float game_rand_float();
|
||||
|
||||
void playSound(struct world* world, int32_t soundID, int32_t soundCategory, float x, float y, float z, float volume, float pitch);
|
||||
void playSound(struct world* world, int32_t soundID, int32_t soundCategory, double x, double y, double z, float volume, float pitch);
|
||||
|
||||
void dropPlayerItem(struct player* player, struct slot* drop);
|
||||
|
||||
|
|
401
src/entity.c
401
src/entity.c
|
@ -450,46 +450,45 @@ void entitymeta_write(struct entity* entity, uint8_t** data, size_t* size, struc
|
|||
(*data)[(*size)++] = 0xFF;
|
||||
}
|
||||
|
||||
void updateMetadata(struct entity* ent) {
|
||||
BEGIN_BROADCAST(ent->loadingPlayers)
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA;
|
||||
pkt->data.play_client.entitymetadata.entity_id = ent->id;
|
||||
entitymeta_write(ent, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size);
|
||||
add_queue(bc_player->outgoing_packets, pkt);
|
||||
END_BROADCAST(ent->loadingPlayers)
|
||||
void entity_broadcast_metadata(struct entity* entity) {
|
||||
BEGIN_BROADCAST(entity->loadingPlayers)
|
||||
struct packet* packet = packet_new(mempool_new(), PKT_PLAY_CLIENT_ENTITYMETADATA);
|
||||
packet->data.play_client.entitymetadata.entity_id = entity->id;
|
||||
entitymeta_write(entity, &packet->data.play_client.entitymetadata.metadata.metadata, &packet->data.play_client.entitymetadata.metadata.metadata_size, packet->pool);
|
||||
queue_push(bc_player->outgoing_packets, packet);
|
||||
END_BROADCAST(entity->loadingPlayers)
|
||||
}
|
||||
|
||||
int getSwingTime(struct entity* ent) {
|
||||
for (size_t i = 0; i < ent->effect_count; i++) {
|
||||
if (ent->effects[i].effectID == 3) {
|
||||
return 6 - (1 + ent->effects[i].amplifier);
|
||||
} else if (ent->effects[i].effectID == 4) {
|
||||
return 6 + (1 + ent->effects[i].amplifier) * 2;
|
||||
int entity_swing_time(struct entity* entity) {
|
||||
for (size_t i = 0; i < entity->effect_count; i++) {
|
||||
if (entity->effects[i].effectID == 3) {
|
||||
return 6 - (1 + entity->effects[i].amplifier);
|
||||
} else if (entity->effects[i].effectID == 4) {
|
||||
return 6 + (1 + entity->effects[i].amplifier) * 2;
|
||||
}
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
block entity_adjustCollision(struct world* world, struct entity* ent, struct chunk* ch, block b, int32_t x, int32_t y, int32_t z) {
|
||||
if (b >> 4 == BLK_DOORIRON >> 4 || b >> 4 == BLK_DOOROAK >> 4 || b >> 4 == BLK_DOORSPRUCE >> 4 || b >> 4 == BLK_DOORBIRCH >> 4 || b >> 4 == BLK_DOORJUNGLE >> 4 || b >> 4 == BLK_DOORACACIA >> 4 || b >> 4 == BLK_DOORDARKOAK >> 4) {
|
||||
if (b & 0b1000) return world_get_block_guess(world, ch, x, y - 1, z);
|
||||
block entity_adjustCollision(struct world* world, struct entity* entity, struct chunk* chunk, block block, int32_t x, int32_t y, int32_t z) {
|
||||
if (block >> 4 == BLK_DOORIRON >> 4 || block >> 4 == BLK_DOOROAK >> 4 || block >> 4 == BLK_DOORSPRUCE >> 4 || block >> 4 == BLK_DOORBIRCH >> 4 || block >> 4 == BLK_DOORJUNGLE >> 4 || block >> 4 == BLK_DOORACACIA >> 4 || block >> 4 == BLK_DOORDARKOAK >> 4) {
|
||||
if (block & 0b1000) return world_get_block_guess(world, chunk, x, y - 1, z);
|
||||
}
|
||||
return b;
|
||||
return block;
|
||||
}
|
||||
|
||||
void entity_adjustBoundingBox(struct world* world, struct entity* ent, struct chunk* ch, block b, int32_t x, int32_t y, int32_t z, struct boundingbox* in, struct boundingbox* out) {
|
||||
void entity_adjustBoundingBox(struct world* world, struct entity* entity, struct chunk* ch, block block, int32_t x, int32_t y, int32_t z, struct boundingbox* in, struct boundingbox* out) {
|
||||
memcpy(in, out, sizeof(struct boundingbox));
|
||||
if (b >> 4 == BLK_DOORIRON >> 4 || b >> 4 == BLK_DOOROAK >> 4 || b >> 4 == BLK_DOORSPRUCE >> 4 || b >> 4 == BLK_DOORBIRCH >> 4 || b >> 4 == BLK_DOORJUNGLE >> 4 || b >> 4 == BLK_DOORACACIA >> 4 || b >> 4 == BLK_DOORDARKOAK >> 4) {
|
||||
block lb = b;
|
||||
block ub = b;
|
||||
if (b & 0b1000) {
|
||||
lb = world_get_block_guess(world, ch, x, y - 1, z);
|
||||
if (block >> 4 == BLK_DOORIRON >> 4 || block >> 4 == BLK_DOOROAK >> 4 || block >> 4 == BLK_DOORSPRUCE >> 4 || block >> 4 == BLK_DOORBIRCH >> 4 || block >> 4 == BLK_DOORJUNGLE >> 4 || block >> 4 == BLK_DOORACACIA >> 4 || block >> 4 == BLK_DOORDARKOAK >> 4) {
|
||||
block low_block = block;
|
||||
block high_block = block;
|
||||
if (block & 0b1000) {
|
||||
low_block = world_get_block_guess(world, ch, x, y - 1, z);
|
||||
} else {
|
||||
ub = world_get_block_guess(world, ch, x, y + 1, z);
|
||||
high_block = world_get_block_guess(world, ch, x, y + 1, z);
|
||||
}
|
||||
if ((lb & 0b0010) && (ub & 0b0001)) {
|
||||
uint8_t face = lb & 0b0011;
|
||||
if ((low_block & 0b0010) && (high_block & 0b0001)) {
|
||||
uint8_t face = (uint8_t) (low_block & 0b0011);
|
||||
if (face == 3 || face == 1) {
|
||||
out->maxZ = 1. - in->maxZ;
|
||||
out->minZ = 1. - in->minZ;
|
||||
|
@ -501,14 +500,14 @@ void entity_adjustBoundingBox(struct world* world, struct entity* ent, struct ch
|
|||
}
|
||||
}
|
||||
|
||||
int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float shrink) {
|
||||
int entity_move(struct entity* entity, double* motionX, double* motionY, double* motionZ, float shrink) {
|
||||
if (entity->immovable) return 0;
|
||||
struct boundingbox obb;
|
||||
entity_collision_bounding_box(entity, &obb);
|
||||
if (entity->type == ENT_ARROW || entity->type == ENT_SPECTRALARROW || obb.minX == obb.maxX || obb.minZ == obb.maxZ || obb.minY == obb.maxY) {
|
||||
entity->x += *mx;
|
||||
entity->y += *my;
|
||||
entity->z += *mz;
|
||||
entity->x += *motionX;
|
||||
entity->y += *motionY;
|
||||
entity->z += *motionZ;
|
||||
return 0;
|
||||
}
|
||||
obb.minX += shrink;
|
||||
|
@ -517,20 +516,20 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
obb.maxY -= shrink;
|
||||
obb.minZ += shrink;
|
||||
obb.maxZ -= shrink;
|
||||
if (*mx < 0.) {
|
||||
obb.minX += *mx;
|
||||
if (*motionX < 0.) {
|
||||
obb.minX += *motionX;
|
||||
} else {
|
||||
obb.maxX += *mx;
|
||||
obb.maxX += *motionX;
|
||||
}
|
||||
if (*my < 0.) {
|
||||
obb.minY += *my;
|
||||
if (*motionY < 0.) {
|
||||
obb.minY += *motionY;
|
||||
} else {
|
||||
obb.maxY += *my;
|
||||
obb.maxY += *motionY;
|
||||
}
|
||||
if (*mz < 0.) {
|
||||
obb.minZ += *mz;
|
||||
if (*motionZ < 0.) {
|
||||
obb.minZ += *motionZ;
|
||||
} else {
|
||||
obb.maxZ += *mz;
|
||||
obb.maxZ += *motionZ;
|
||||
}
|
||||
struct boundingbox pbb;
|
||||
entity_collision_bounding_box(entity, &pbb);
|
||||
|
@ -540,7 +539,7 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
pbb.maxY -= shrink;
|
||||
pbb.minZ += shrink;
|
||||
pbb.maxZ -= shrink;
|
||||
double ny = *my;
|
||||
double ny = *motionY;
|
||||
struct chunk* ch = world_get_chunk(entity->world, (int32_t) entity->x / 16, (int32_t) entity->z / 16);
|
||||
for (int32_t x = (int32_t) floor(obb.minX); x < floor(obb.maxX + 1.); x++) {
|
||||
for (int32_t z = (int32_t) floor(obb.minZ); z < floor(obb.maxZ + 1.); z++) {
|
||||
|
@ -580,7 +579,7 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
entity->y += ny;
|
||||
pbb.minY += ny;
|
||||
pbb.maxY += ny;
|
||||
double nx = *mx;
|
||||
double nx = *motionX;
|
||||
for (int32_t x = (int32_t) floor(obb.minX); x < floor(obb.maxX + 1.); x++) {
|
||||
for (int32_t z = (int32_t) floor(obb.minZ); z < floor(obb.maxZ + 1.); z++) {
|
||||
for (int32_t y = (int32_t) floor(obb.minY); y < floor(obb.maxY + 1.); y++) {
|
||||
|
@ -619,7 +618,7 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
entity->x += nx;
|
||||
pbb.minX += nx;
|
||||
pbb.maxX += nx;
|
||||
double nz = *mz;
|
||||
double nz = *motionZ;
|
||||
for (int32_t x = (int32_t) floor(obb.minX); x < floor(obb.maxX + 1.); x++) {
|
||||
for (int32_t z = (int32_t) floor(obb.minZ); z < floor(obb.maxZ + 1.); z++) {
|
||||
for (int32_t y = (int32_t) floor(obb.minY); y < floor(obb.maxY + 1.); y++) {
|
||||
|
@ -659,9 +658,9 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
entity->z += nz;
|
||||
pbb.minZ += nz;
|
||||
pbb.maxZ += nz;
|
||||
entity->collidedHorizontally = *mx != nx || *mz != nz;
|
||||
entity->collidedVertically = *my != ny;
|
||||
entity->on_ground = entity->collidedVertically && *my < 0.;
|
||||
entity->collidedHorizontally = *motionX != nx || *motionZ != nz;
|
||||
entity->collidedVertically = *motionY != ny;
|
||||
entity->on_ground = entity->collidedVertically && *motionY < 0.;
|
||||
int32_t bx = (int32_t) floor(entity->x);
|
||||
int32_t by = (int32_t) floor(entity->y - .20000000298023224);
|
||||
int32_t bz = (int32_t) floor(entity->z);
|
||||
|
@ -674,77 +673,80 @@ int moveEntity(struct entity* entity, double* mx, double* my, double* mz, float
|
|||
by--;
|
||||
}
|
||||
}
|
||||
if (*mx != nx) *mx = 0.;
|
||||
if (*mz != nz) *mz = 0.;
|
||||
if (*my != ny) {
|
||||
if (*motionX != nx) *motionX = 0.;
|
||||
if (*motionZ != nz) *motionZ = 0.;
|
||||
if (*motionY != ny) {
|
||||
if (lb != BLK_SLIME || entity->sneaking) {
|
||||
*my = 0.;
|
||||
*motionY = 0.;
|
||||
} else {
|
||||
*my = -(*my);
|
||||
*motionY = -(*motionY);
|
||||
}
|
||||
}
|
||||
return ny != *my || nx != *mx || nz != *mz;
|
||||
return ny != *motionY || nx != *motionX || nz != *motionZ;
|
||||
}
|
||||
|
||||
void applyVelocity(struct entity* entity, double x, double y, double z) {
|
||||
void entity_apply_velocity(struct entity* entity, double x, double y, double z) {
|
||||
entity->motX += x;
|
||||
entity->motY += y;
|
||||
entity->motZ += z;
|
||||
BEGIN_BROADCAST(entity->loadingPlayers)
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_ENTITYVELOCITY;
|
||||
pkt->data.play_client.entityvelocity.entity_id = entity->id;
|
||||
pkt->data.play_client.entityvelocity.velocity_x = (int16_t)(entity->motX * 8000.);
|
||||
pkt->data.play_client.entityvelocity.velocity_y = (int16_t)(entity->motY * 8000.);
|
||||
pkt->data.play_client.entityvelocity.velocity_z = (int16_t)(entity->motZ * 8000.);
|
||||
add_queue(bc_player->outgoing_packets, pkt);
|
||||
END_BROADCAST(entity->loadingPlayers)
|
||||
BEGIN_BROADCAST(entity->loadingPlayers) {
|
||||
struct packet* packet = packet_new(mempool_new(), PKT_PLAY_CLIENT_ENTITYVELOCITY);
|
||||
packet->data.play_client.entityvelocity.entity_id = entity->id;
|
||||
packet->data.play_client.entityvelocity.velocity_x = (int16_t) (entity->motX * 8000.);
|
||||
packet->data.play_client.entityvelocity.velocity_y = (int16_t) (entity->motY * 8000.);
|
||||
packet->data.play_client.entityvelocity.velocity_z = (int16_t) (entity->motZ * 8000.);
|
||||
queue_push(bc_player->outgoing_packets, packet);
|
||||
END_BROADCAST(entity->loadingPlayers)
|
||||
}
|
||||
if (entity->type == ENT_PLAYER) {
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_ENTITYVELOCITY;
|
||||
pkt->data.play_client.entityvelocity.entity_id = entity->id;
|
||||
pkt->data.play_client.entityvelocity.velocity_x = (int16_t)(entity->motX * 8000.);
|
||||
pkt->data.play_client.entityvelocity.velocity_y = (int16_t)(entity->motY * 8000.);
|
||||
pkt->data.play_client.entityvelocity.velocity_z = (int16_t)(entity->motZ * 8000.);
|
||||
add_queue(entity->data.player.player->outgoing_packets, pkt);
|
||||
struct packet* packet = packet_new(mempool_new(), PKT_PLAY_CLIENT_ENTITYVELOCITY);
|
||||
packet->data.play_client.entityvelocity.entity_id = entity->id;
|
||||
packet->data.play_client.entityvelocity.velocity_x = (int16_t)(entity->motX * 8000.);
|
||||
packet->data.play_client.entityvelocity.velocity_y = (int16_t)(entity->motY * 8000.);
|
||||
packet->data.play_client.entityvelocity.velocity_z = (int16_t)(entity->motZ * 8000.);
|
||||
queue_push(entity->data.player.player->outgoing_packets, packet);
|
||||
}
|
||||
}
|
||||
|
||||
void applyKnockback(struct entity* entity, float yaw, float strength) {
|
||||
float kb_resistance = 0.;
|
||||
void entity_apply_knockback(struct entity* entity, float yaw, float strength) {
|
||||
float kb_resistance = 0f;
|
||||
if (game_rand_float() > kb_resistance) {
|
||||
float xr = sinf(yaw / 360. * 2 * M_PI);
|
||||
float zr = -cosf(yaw / 360. * 2 * M_PI);
|
||||
float m = sqrtf(xr * xr + zr * zr);
|
||||
float x_component = sinf((float) (yaw / 360f * 2f * M_PI));
|
||||
float z_component = -cosf((float) (yaw / 360f * 2f * M_PI));
|
||||
float m = sqrtf(x_component * x_component + z_component * z_component);
|
||||
entity->motX /= 2.;
|
||||
entity->motZ /= 2.;
|
||||
entity->motX -= xr / m * strength;
|
||||
entity->motZ -= zr / m * strength;
|
||||
entity->motX -= x_component / m * strength;
|
||||
entity->motZ -= z_component / m * strength;
|
||||
if (entity->on_ground) {
|
||||
entity->motY /= 2.;
|
||||
entity->motY += strength;
|
||||
if (entity->motY > .4) entity->motY = .4;
|
||||
}
|
||||
applyVelocity(entity, 0., 0., 0.);
|
||||
entity_apply_velocity(entity, 0., 0., 0.);
|
||||
}
|
||||
}
|
||||
|
||||
int damageEntityWithItem(struct entity* attacked, struct entity* attacker, uint8_t slot_index, struct slot* item) {
|
||||
if (attacked == NULL || attacked->invincibilityTicks > 0 || !entity_has_flag(entity_get_info(attacked->type), "livingbase") || attacked->health <= 0.) return 0;
|
||||
if (attacked->type == ENT_PLAYER && attacked->data.player.player->gamemode == 1) return 0;
|
||||
float damage = 1.;
|
||||
if (attacked == NULL || attacked->invincibilityTicks > 0 || !hashset_has(attacked->info->flags, "livingbase") || attacked->health <= 0.) {
|
||||
return 0;
|
||||
}
|
||||
if (attacked->type == ENT_PLAYER && attacked->data.player.player->gamemode == 1) {
|
||||
return 0;
|
||||
}
|
||||
float damage = 1f;
|
||||
if (item != NULL) {
|
||||
struct item_info* ii = getItemInfo(item->item);
|
||||
if (ii != NULL) {
|
||||
damage = ii->damage;
|
||||
struct item_info* info = getItemInfo(item->item);
|
||||
if (info != NULL) {
|
||||
damage = info->damage;
|
||||
if (attacker->type == ENT_PLAYER) {
|
||||
if (ii->onItemAttacked != NULL) {
|
||||
damage = (*ii->onItemAttacked)(attacker->world, attacker->data.player.player, attacker->data.player.player->currentItem + 36, item, attacked);
|
||||
if (info->onItemAttacked != NULL) {
|
||||
damage = (*info->onItemAttacked)(attacker->world, attacker->data.player.player, (uint8_t) (attacker->data.player.player->currentItem + 36), item, attacked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
float knockback_strength = 1.;
|
||||
float knockback_strength = 1f;
|
||||
if (attacker->sprinting) knockback_strength++;
|
||||
if (attacker->type == ENT_PLAYER) {
|
||||
struct player* player = attacker->data.player.player;
|
||||
|
@ -755,15 +757,18 @@ int damageEntityWithItem(struct entity* attacked, struct entity* attacker, uint8
|
|||
if (attacker->y > attacked->y && (attacker->last_y - attacker->y) > 0 && !attacker->on_ground && !attacker->sprinting) { // todo water/ladder
|
||||
damage *= 1.5;
|
||||
}
|
||||
BEGIN_HASHMAP_ITERATION (plugins)
|
||||
struct plugin* plugin = value;
|
||||
if (plugin->onEntityAttacked != NULL) damage = (*plugin->onEntityAttacked)(attacker->world, attacker, slot_index, item, attacked, damage);
|
||||
END_HASHMAP_ITERATION (plugins)
|
||||
if (damage == 0.) return 0;
|
||||
ITER_MAP(plugins) {
|
||||
struct plugin* plugin = value;
|
||||
if (plugin->onEntityAttacked != NULL) damage = (*plugin->onEntityAttacked)(attacker->world, attacker, slot_index, item, attacked, damage);
|
||||
ITER_MAP_END();
|
||||
}
|
||||
if (damage == 0.) {
|
||||
return 0;
|
||||
}
|
||||
damageEntity(attacked, damage, 1);
|
||||
//TODO: enchantment
|
||||
knockback_strength *= .2;
|
||||
applyKnockback(attacked, attacker->yaw, knockback_strength);
|
||||
entity_apply_knockback(attacked, attacker->yaw, knockback_strength);
|
||||
if (attacker->type == ENT_PLAYER) {
|
||||
attacker->data.player.player->foodExhaustion += .1;
|
||||
}
|
||||
|
@ -771,7 +776,7 @@ int damageEntityWithItem(struct entity* attacked, struct entity* attacker, uint8
|
|||
}
|
||||
|
||||
int damageEntity(struct entity* attacked, float damage, int armorable) {
|
||||
if (attacked == NULL || damage <= 0. || attacked->invincibilityTicks > 0 || !entity_has_flag(entity_get_info(attacked->type), "livingbase") || attacked->health <= 0.) return 0;
|
||||
if (attacked == NULL || damage <= 0. || attacked->invincibilityTicks > 0 || !hashset_has(attacked->info->flags, "livingbase") || attacked->health <= 0.) return 0;
|
||||
float armor = 0;
|
||||
if (attacked->type == ENT_PLAYER) {
|
||||
struct player* player = attacked->data.player.player;
|
||||
|
@ -787,10 +792,10 @@ int damageEntity(struct entity* attacked, float damage, int armorable) {
|
|||
}
|
||||
}
|
||||
if (armorable) {
|
||||
float f = armor - damage / 2.;
|
||||
if (f < armor * .2) f = armor * .2;
|
||||
if (f > 20.) f = 20.;
|
||||
damage *= 1. - (f) / 25.;
|
||||
float mod = armor - damage / 2f;
|
||||
if (mod < armor * .2) mod = armor * .2f;
|
||||
if (mod > 20.) mod = 20f;
|
||||
damage *= 1. - mod / 25.;
|
||||
}
|
||||
if (attacked->type == ENT_PLAYER) {
|
||||
struct player* player = attacked->data.player.player;
|
||||
|
@ -798,9 +803,9 @@ int damageEntity(struct entity* attacked, float damage, int armorable) {
|
|||
if (armorable) for (int i = 5; i <= 8; i++) {
|
||||
struct slot* sl = inventory_get(player, player->inventory, i);
|
||||
if (sl != NULL) {
|
||||
struct item_info* ii = getItemInfo(sl->item);
|
||||
if (ii != NULL && ii->onEntityHitWhileWearing != NULL) {
|
||||
damage = (*ii->onEntityHitWhileWearing)(player->world, player, i, sl, damage);
|
||||
struct item_info* info = getItemInfo(sl->item);
|
||||
if (info != NULL && info->onEntityHitWhileWearing != NULL) {
|
||||
damage = (*info->onEntityHitWhileWearing)(player->world, player, i, sl, damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -808,74 +813,68 @@ int damageEntity(struct entity* attacked, float damage, int armorable) {
|
|||
attacked->health -= damage;
|
||||
attacked->invincibilityTicks = 10;
|
||||
if (attacked->type == ENT_PLAYER) {
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_UPDATEHEALTH;
|
||||
pkt->data.play_client.updatehealth.health = attacked->health;
|
||||
pkt->data.play_client.updatehealth.food = attacked->data.player.player->food;
|
||||
pkt->data.play_client.updatehealth.food_saturation = attacked->data.player.player->saturation;
|
||||
add_queue(attacked->data.player.player->outgoing_packets, pkt);
|
||||
struct packet* packet = packet_new(mempool_new(), PKT_PLAY_CLIENT_UPDATEHEALTH);
|
||||
packet->data.play_client.updatehealth.health = attacked->health;
|
||||
packet->data.play_client.updatehealth.food = attacked->data.player.player->food;
|
||||
packet->data.play_client.updatehealth.food_saturation = attacked->data.player.player->saturation;
|
||||
queue_push(attacked->data.player.player->outgoing_packets, packet);
|
||||
}
|
||||
if (attacked->health <= 0.) {
|
||||
if (attacked->type == ENT_PLAYER) {
|
||||
struct player* player = attacked->data.player.player;
|
||||
broadcastf("default", "%s died", player->name);
|
||||
for (size_t i = 0; i < player->inventory->slot_count; i++) {
|
||||
struct slot* slot = inventory_get(player, player->inventory, i);
|
||||
struct slot* slot = inventory_get(player, player->inventory, (int) i);
|
||||
if (slot != NULL) dropEntityItem_explode(player->entity, slot);
|
||||
inventory_set_slot(player, player->inventory, i, 0, 0, 1);
|
||||
inventory_set_slot(player, player->inventory, (int) i, 0, 1);
|
||||
}
|
||||
if (player->inventory_holding != NULL) {
|
||||
dropEntityItem_explode(player->entity, player->inventory_holding);
|
||||
freeSlot(player->inventory_holding);
|
||||
xfree(player->inventory_holding);
|
||||
player->inventory_holding = NULL;
|
||||
}
|
||||
if (player->open_inventory != NULL) player_closeWindow(player, player->open_inventory->windowID);
|
||||
if (player->open_inventory != NULL) {
|
||||
player_closeWindow(player, (uint16_t) player->open_inventory->window);
|
||||
}
|
||||
} else {
|
||||
struct entity_info* ei = entity_get_info(attacked->type);
|
||||
if (ei != NULL) for (size_t i = 0; i < ei->loot_count; i++) {
|
||||
struct entity_loot* el = &ei->loots[i];
|
||||
int amt = el->amountMax == el->amountMin ? el->amountMax : (rand() % (el->amountMax - el->amountMin) + el->amountMin);
|
||||
if (amt <= 0) continue;
|
||||
struct slot it;
|
||||
it.item = el->id;
|
||||
it.count = amt;
|
||||
it.damage = el->metaMax == el->metaMin ? el->metaMax : (rand() % (el->metaMax - el->metaMin) + el->metaMin);
|
||||
it.nbt = NULL;
|
||||
dropEntityItem_explode(attacked, &it);
|
||||
struct entity_info* info = entity_get_info(attacked->type);
|
||||
if (info != NULL) {
|
||||
for (size_t i = 0; i < info->loot_count; i++) {
|
||||
struct entity_loot* el = &info->loots[i];
|
||||
int amt = el->amountMax == el->amountMin ? el->amountMax : (rand() % (el->amountMax - el->amountMin) + el->amountMin);
|
||||
if (amt <= 0) continue;
|
||||
struct slot it;
|
||||
it.item = el->id;
|
||||
it.count = (unsigned char) amt;
|
||||
it.damage = (int16_t) (el->metaMax == el->metaMin ? el->metaMax : (rand() % (el->metaMax - el->metaMin) + el->metaMin));
|
||||
it.nbt = NULL;
|
||||
dropEntityItem_explode(attacked, &it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BEGIN_BROADCAST_DIST(attacked, 128.)
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_ANIMATION;
|
||||
pkt->data.play_client.animation.entity_id = attacked->id;
|
||||
pkt->data.play_client.animation.animation = 1;
|
||||
add_queue(bc_player->outgoing_packets, pkt);
|
||||
entity_animation(attacked, 1);
|
||||
if (attacked->health <= 0.) {
|
||||
pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA;
|
||||
pkt->data.play_client.entitymetadata.entity_id = attacked->id;
|
||||
entitymeta_write(attacked, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size);
|
||||
add_queue(bc_player->outgoing_packets, pkt);
|
||||
entity_broadcast_metadata(attacked);
|
||||
}
|
||||
END_BROADCAST(attacked->world->players)
|
||||
if (attacked->type == ENT_PLAYER) playSound(attacked->world, 316, 8, attacked->x, attacked->y, attacked->z, 1., 1.);
|
||||
if (attacked->type == ENT_PLAYER) playSound(attacked->world, 316, 8, attacked->x, attacked->y, attacked->z, 1f, 1f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void healEntity(struct entity* healed, float amount) {
|
||||
if (healed == NULL || amount <= 0. || healed->health <= 0. || !entity_has_flag(entity_get_info(healed->type), "livingbase")) return;
|
||||
float oh = healed->health;
|
||||
if (healed == NULL || amount <= 0. || healed->health <= 0. || !hashset_has(healed->info->flags, "livingbase")) {
|
||||
return;
|
||||
}
|
||||
float original_health = healed->health;
|
||||
healed->health += amount;
|
||||
if (healed->health > healed->maxHealth) healed->health = 20.;
|
||||
if (healed->type == ENT_PLAYER && oh != healed->health) {
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_UPDATEHEALTH;
|
||||
pkt->data.play_client.updatehealth.health = healed->health;
|
||||
pkt->data.play_client.updatehealth.food = healed->data.player.player->food;
|
||||
pkt->data.play_client.updatehealth.food_saturation = healed->data.player.player->saturation;
|
||||
add_queue(healed->data.player.player->outgoing_packets, pkt);
|
||||
if (healed->health > healed->maxHealth) {
|
||||
healed->health = 20f;
|
||||
}
|
||||
if (healed->type == ENT_PLAYER && original_health != healed->health) {
|
||||
struct packet* packet = packet_new(mempool_new(), PKT_PLAY_CLIENT_UPDATEHEALTH);
|
||||
packet->data.play_client.updatehealth.health = healed->health;
|
||||
packet->data.play_client.updatehealth.food = healed->data.player.player->food;
|
||||
packet->data.play_client.updatehealth.food_saturation = healed->data.player.player->saturation;
|
||||
queue_push(healed->data.player.player->outgoing_packets, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -914,7 +913,6 @@ int entity_inFluid(struct entity* entity, uint16_t blk, float ydown, int meta_ch
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int entity_inBlock(struct entity* ent, block blk) { // blk = 0 for any block
|
||||
struct boundingbox obb;
|
||||
entity_collision_bounding_box(ent, &obb);
|
||||
|
@ -951,8 +949,10 @@ int entity_inBlock(struct entity* ent, block blk) { // blk = 0 for any block
|
|||
return 0;
|
||||
}
|
||||
|
||||
void pushOutOfBlocks(struct entity* ent) {
|
||||
if (!entity_inBlock(ent, 0)) return;
|
||||
void entity_push_out_of_blocks(struct entity* ent) {
|
||||
if (!entity_inBlock(ent, 0)) {
|
||||
return;
|
||||
}
|
||||
struct boundingbox ebb;
|
||||
entity_collision_bounding_box(ent, &ebb);
|
||||
double x = ent->x;
|
||||
|
@ -965,40 +965,40 @@ void pushOutOfBlocks(struct entity* ent) {
|
|||
double dy = y - (double) by;
|
||||
double dz = z - (double) bz;
|
||||
double ld = 100.;
|
||||
float fbx = 0.;
|
||||
float fby = 0.;
|
||||
float fbz = 0.;
|
||||
float fbx = 0f;
|
||||
float fby = 0f;
|
||||
float fbz = 0f;
|
||||
if (dx < ld && !isNormalCube(getBlockInfo(world_get_block(ent->world, bx - 1, by, bz)))) {
|
||||
ld = dx;
|
||||
fbx = -1.;
|
||||
fby = 0.;
|
||||
fbz = 0.;
|
||||
fbx = -1f;
|
||||
fby = 0f;
|
||||
fbz = 0f;
|
||||
}
|
||||
if ((1. - dx) < ld && !isNormalCube(getBlockInfo(world_get_block(ent->world, bx + 1, by, bz)))) {
|
||||
ld = 1. - dx;
|
||||
fbx = 1.;
|
||||
fby = 0.;
|
||||
fbz = 0.;
|
||||
fbx = 1f;
|
||||
fby = 0f;
|
||||
fbz = 0f;
|
||||
}
|
||||
if (dz < ld && !isNormalCube(getBlockInfo(world_get_block(ent->world, bx, by, bz - 1)))) {
|
||||
ld = dx;
|
||||
fbx = 0.;
|
||||
fby = 0.;
|
||||
fbz = -1.;
|
||||
fbx = 0f;
|
||||
fby = 0f;
|
||||
fbz = -1f;
|
||||
}
|
||||
if ((1. - dz) < ld && !isNormalCube(getBlockInfo(world_get_block(ent->world, bx, by, bz + 1)))) {
|
||||
ld = 1. - dz;
|
||||
fbx = 0.;
|
||||
fby = 0.;
|
||||
fbz = 1.;
|
||||
fbx = 0f;
|
||||
fby = 0f;
|
||||
fbz = 1f;
|
||||
}
|
||||
if ((1. - dy) < ld && !isNormalCube(getBlockInfo(world_get_block(ent->world, bx, by + 1, bz)))) {
|
||||
ld = 1. - dy;
|
||||
fbx = 0.;
|
||||
fby = 1.;
|
||||
fbz = 0.;
|
||||
fbx = 0f;
|
||||
fby = 1f;
|
||||
fbz = 0f;
|
||||
}
|
||||
float mag = game_rand_float() * .2 + .1;
|
||||
float mag = game_rand_float() * .2f + .1f;
|
||||
if (fbx == 0. && fbz == 0.) {
|
||||
ent->motX *= .75;
|
||||
ent->motY = mag * fby;
|
||||
|
@ -1038,13 +1038,11 @@ void tick_entity(struct world* world, struct entity* entity) {
|
|||
}
|
||||
}
|
||||
if (entity->type > ENT_PLAYER) {
|
||||
if (entity->motX != 0. || entity->motY != 0. || entity->motZ != 0.) moveEntity(entity, &entity->motX, &entity->motY, &entity->motZ, 0.);
|
||||
if (entity->motX != 0. || entity->motY != 0. || entity->motZ != 0.) entity_move(entity, &entity->motX, &entity->motY, &entity->motZ, 0.);
|
||||
double gravity = 0.;
|
||||
int ar = entity->type == ENT_ARROW || entity->type == ENT_SPECTRALARROW;
|
||||
int is_arrow = entity->type == ENT_ARROW || entity->type == ENT_SPECTRALARROW;
|
||||
float friction = .98;
|
||||
if (ar) {
|
||||
//printf("ymot %f pit %f\n", entity->motY, entity->pitch);
|
||||
//printf("af %.17f, %.17f --- %.17f, %.17f, %.17f\n", entity->yaw, entity->pitch, entity->motX, entity->motY, entity->motZ);
|
||||
if (is_arrow) {
|
||||
friction = .99;
|
||||
if (entity->inWater) friction = .6;
|
||||
entity->motX *= friction;
|
||||
|
@ -1052,8 +1050,8 @@ void tick_entity(struct world* world, struct entity* entity) {
|
|||
entity->motZ *= friction;
|
||||
}
|
||||
if (entity->type == ENT_ITEM) gravity = .04;
|
||||
else if (ar) gravity = .05;
|
||||
else if (entity_has_flag(entity_get_info(entity->type), "livingbase")) {
|
||||
else if (is_arrow) gravity = .05;
|
||||
else if (hashset_has(entity->info->flags, "livingbase")) {
|
||||
if (entity->inLava) {
|
||||
entity->motX *= .5;
|
||||
entity->motY *= .5;
|
||||
|
@ -1072,7 +1070,7 @@ void tick_entity(struct world* world, struct entity* entity) {
|
|||
gravity = .04;
|
||||
}
|
||||
if (gravity != 0. && !entity->immovable) entity->motY -= gravity;
|
||||
if (!ar) {
|
||||
if (!is_arrow) {
|
||||
if (entity->on_ground) {
|
||||
struct block_info* bi = getBlockInfo(world_get_block(entity->world, (int32_t) floor(entity->x), (int32_t) floor(entity->y) - 1, (int32_t) floor(entity->z)));
|
||||
if (bi != NULL) friction = bi->slipperiness * .98;
|
||||
|
@ -1086,28 +1084,27 @@ void tick_entity(struct world* world, struct entity* entity) {
|
|||
if (fabs(entity->motZ) < .0001) entity->motZ = 0.;
|
||||
if (entity->type == ENT_ITEM && entity->on_ground && entity->motX == 0. && entity->motY == 0. && entity->motZ == 0.) entity->motY *= -.5;
|
||||
}
|
||||
if (entity->type == ENT_ITEM || entity->type == ENT_XPORB) pushOutOfBlocks(entity);
|
||||
if (entity_has_flag(entity_get_info(entity->type), "livingbase")) {
|
||||
entity->inWater = entity_inFluid(entity, BLK_WATER, .2, 0) || entity_inFluid(entity, BLK_WATER_1, .2, 0);
|
||||
entity->inLava = entity_inFluid(entity, BLK_LAVA, .2, 0) || entity_inFluid(entity, BLK_LAVA_1, .2, 0);
|
||||
if ((entity->inWater || entity->inLava) && entity->type == ENT_PLAYER) entity->data.player.player->llTick = tick_counter;
|
||||
if (entity->type == ENT_ITEM || entity->type == ENT_XPORB) entity_push_out_of_blocks(entity);
|
||||
if (hashset_has(entity->info->flags, "livingbase")) {
|
||||
entity->inWater = (uint8_t) (entity_inFluid(entity, BLK_WATER, .2, 0) || entity_inFluid(entity, BLK_WATER_1, .2, 0));
|
||||
entity->inLava = (uint8_t) (entity_inFluid(entity, BLK_LAVA, .2, 0) || entity_inFluid(entity, BLK_LAVA_1, .2, 0));
|
||||
//TODO: ladders
|
||||
if (entity->type == ENT_PLAYER && entity->data.player.player->gamemode == 1) goto bfd;
|
||||
if (entity->inLava) {
|
||||
damageEntity(entity, 4., 1);
|
||||
//TODO: fire
|
||||
damageEntity(entity, 4f, 1);
|
||||
//TODO: fire
|
||||
}
|
||||
if (!entity->on_ground) {
|
||||
float dy = entity->last_y - entity->y;
|
||||
double dy = entity->last_y - entity->y;
|
||||
if (dy > 0.) {
|
||||
entity->fallDistance += dy;
|
||||
}
|
||||
} else if (entity->fallDistance > 0.) {
|
||||
if (entity->fallDistance > 3. && !entity->inWater && !entity->inLava) {
|
||||
damageEntity(entity, entity->fallDistance - 3., 0);
|
||||
playSound(entity->world, 312, 8, entity->x, entity->y, entity->z, 1., 1.);
|
||||
damageEntity(entity, entity->fallDistance - 3f, 0);
|
||||
playSound(entity->world, 312, 8, entity->x, entity->y, entity->z, 1f, 1f);
|
||||
}
|
||||
entity->fallDistance = 0.;
|
||||
entity->fallDistance = 0f;
|
||||
}
|
||||
bfd: ;
|
||||
}
|
||||
|
@ -1115,33 +1112,13 @@ void tick_entity(struct world* world, struct entity* entity) {
|
|||
double md = entity_distsq_block(entity, entity->last_x, entity->last_y, entity->last_z);
|
||||
double mp = (entity->yaw - entity->last_yaw) * (entity->yaw - entity->last_yaw) + (entity->pitch - entity->last_pitch) * (entity->pitch - entity->last_pitch);
|
||||
if (md > .001 || mp > .01) {
|
||||
BEGIN_HASHMAP_ITERATION(entity->loadingPlayers);
|
||||
player_send_entity_move(value, entity);
|
||||
END_HASHMAP_ITERATION(entity->loadingPlayers);
|
||||
pthread_rwlock_rdlock(&entity->loadingPlayers->rwlock);
|
||||
ITER_MAP(entity->loadingPlayers) {
|
||||
player_send_entity_move(value, entity);
|
||||
ITER_MAP_END();
|
||||
}
|
||||
pthread_rwlock_unlock(&entity->loadingPlayers->rwlock);
|
||||
}
|
||||
}
|
||||
/*int32_t chunk_x = ((int32_t) entity->x) >> 4;
|
||||
int32_t chunk_z = ((int32_t) entity->z) >> 4;
|
||||
int32_t lcx = ((int32_t) entity->lx) >> 4;
|
||||
int32_t lcz = ((int32_t) entity->lz) >> 4;
|
||||
if (chunk_x != lcx || chunk_z != lcz) {
|
||||
struct chunk* lch = getChunk(entity->world, lcx, lcz);
|
||||
struct chunk* cch = world_get_chunk(entity->world, chunk_x, chunk_z);
|
||||
put_hashmap(lch->entities, entity->id, NULL);
|
||||
put_hashmap(cch->entities, entity->id, entity);
|
||||
}*/
|
||||
}
|
||||
|
||||
void freeEntity(struct entity* entity) {
|
||||
del_hashmap(entity->loadingPlayers);
|
||||
if (entity->type == ENT_ITEM) {
|
||||
if (entity->data.itemstack.slot != NULL) {
|
||||
freeSlot(entity->data.itemstack.slot);
|
||||
xfree(entity->data.itemstack.slot);
|
||||
}
|
||||
}
|
||||
if (entity->type == ENT_PAINTING) {
|
||||
if (entity->data.painting.title != NULL) xfree(entity->data.painting.title);
|
||||
}
|
||||
xfree(entity);
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ void dropPlayerItem(struct player* player, struct slot* drop) {
|
|||
END_BROADCAST(player->world->players)
|
||||
}
|
||||
|
||||
void playSound(struct world* world, int32_t soundID, int32_t soundCategory, float x, float y, float z, float volume, float pitch) {
|
||||
void playSound(struct world* world, int32_t soundID, int32_t soundCategory, double x, double y, double z, float volume, float pitch) {
|
||||
BEGIN_BROADCAST_DISTXYZ(x, y, z, world->players, 64.)
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_SOUNDEFFECT;
|
||||
|
|
|
@ -303,13 +303,13 @@ void player_tick(struct player* player) {
|
|||
player->itemUseDuration = 0;
|
||||
player->entity->usingItemMain = 0;
|
||||
player->entity->usingItemOff = 0;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
} else if (ihi->maxUseDuration <= player->itemUseDuration) {
|
||||
if (ihi->onItemUse != NULL) (*ihi->onItemUse)(player->world, player, (uint8_t) (player->itemUseHand ? 45 : (36 + player->currentItem)), ihs, player->itemUseDuration);
|
||||
player->itemUseDuration = 0;
|
||||
player->entity->usingItemMain = 0;
|
||||
player->entity->usingItemOff = 0;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
} else {
|
||||
if (ihi->onItemUseTick != NULL) (*ihi->onItemUseTick)(player->world, player, (uint8_t) (player->itemUseHand ? 45 : (36 + player->currentItem)), ihs, player->itemUseDuration);
|
||||
player->itemUseDuration++;
|
||||
|
|
|
@ -624,7 +624,7 @@ void player_packet_handle_playerposition(struct player* player, struct mempool*
|
|||
double moveX = packet->x - lastX;
|
||||
double moveY = packet->feet_y - lastY;
|
||||
double moveZ = packet->z - lastZ;
|
||||
if (moveEntity(player->entity, &moveX, &moveY, &moveZ, .05)) {
|
||||
if (entity_move(player->entity, &moveX, &moveY, &moveZ, .05)) {
|
||||
player_teleport(player, lastX, lastY, lastZ);
|
||||
} else {
|
||||
player->entity->last_x = lastX;
|
||||
|
@ -660,7 +660,7 @@ void player_packet_handle_playerpositionandlook(struct player* player, struct me
|
|||
double moveX = packet->x - lastX;
|
||||
double moveY = packet->feet_y - lastY;
|
||||
double moveZ = packet->z - lastZ;
|
||||
if (moveEntity(player->entity, &moveX, &moveY, &moveZ, .05)) {
|
||||
if (entity_move(player->entity, &moveX, &moveY, &moveZ, .05)) {
|
||||
player_teleport(player, lastX, lastY, lastZ);
|
||||
} else {
|
||||
player->entity->last_x = lastX;
|
||||
|
@ -861,13 +861,13 @@ void player_packet_handle_playerdigging(struct player* player, struct mempool* p
|
|||
player->itemUseDuration = 0;
|
||||
player->entity->usingItemMain = 0;
|
||||
player->entity->usingItemOff = 0;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
}
|
||||
if (item_info != NULL && item_info->onItemUse != NULL) (*item_info->onItemUse)(player->world, player, player->itemUseHand ? 45 : (36 + player->currentItem), item_in_hand, player->itemUseDuration);
|
||||
player->entity->usingItemMain = 0;
|
||||
player->entity->usingItemOff = 0;
|
||||
player->itemUseDuration = 0;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
}
|
||||
pthread_mutex_unlock(&player->inventory->mutex);
|
||||
} else if (packet->status == 6) {
|
||||
|
@ -881,7 +881,7 @@ void player_packet_handle_entityaction(struct player* player, struct mempool* po
|
|||
else if (packet->action_id == 1) player->entity->sneaking = 0;
|
||||
else if (packet->action_id == 3) player->entity->sprinting = 1;
|
||||
else if (packet->action_id == 4) player->entity->sprinting = 0;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
}
|
||||
|
||||
void player_packet_handle_steervehicle(struct player* player, struct mempool* pool, struct pkt_play_server_steervehicle* packet) {
|
||||
|
@ -1061,7 +1061,7 @@ void player_packet_handle_useitem(struct player* player, struct mempool* pool, s
|
|||
player->itemUseHand = (uint8_t) (packet->hand ? 1 : 0);
|
||||
player->entity->usingItemMain = !player->itemUseHand;
|
||||
player->entity->usingItemOff = player->itemUseHand;
|
||||
updateMetadata(player->entity);
|
||||
entity_broadcast_metadata(player->entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue