From 5b505f29ec4d44d56287d387e4ea006582fb00c9 Mon Sep 17 00:00:00 2001 From: Protryon Date: Sat, 4 May 2019 18:24:47 -0700 Subject: [PATCH] entity impl vs definition split --- include/basin/entity.h | 2 - include/basin/entity_impl.h | 20 +++ src/entity.c | 323 +----------------------------------- src/entity_impl.c | 308 ++++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+), 319 deletions(-) create mode 100644 include/basin/entity_impl.h create mode 100644 src/entity_impl.c diff --git a/include/basin/entity.h b/include/basin/entity.h index 5a52d23..c69a0bb 100644 --- a/include/basin/entity.h +++ b/include/basin/entity.h @@ -164,8 +164,6 @@ uint32_t getIDFromEntityDataName(const char* dataname); struct entity_info* getEntityInfo(uint32_t id); -void add_entity_info(uint32_t eid, struct entity_info* bm); - struct potioneffect { char effectID; char amplifier; diff --git a/include/basin/entity_impl.h b/include/basin/entity_impl.h new file mode 100644 index 0000000..87ea1b3 --- /dev/null +++ b/include/basin/entity_impl.h @@ -0,0 +1,20 @@ +#ifndef BASIN_ENTITY_IMPL_H +#define BASIN_ENTITY_IMPL_H + +#include "entity_impl.h" + +void onSpawned_minecart(struct world* world, struct entity* entity); + +int onTick_tnt(struct world* world, struct entity* ent); + +int onTick_fallingblock(struct world* world, struct entity* ent); + +void onInteract_cow(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index); + +void onInteract_mooshroom(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index); + +int tick_arrow(struct world* world, struct entity* entity); + +int tick_itemstack(struct world* world, struct entity* entity); + +#endif //BASIN_ENTITY_IMPL_H diff --git a/src/entity.c b/src/entity.c index d30198e..60fadb7 100644 --- a/src/entity.c +++ b/src/entity.c @@ -5,16 +5,18 @@ * Author: root */ -#include "basin/packet.h" +#include #include #include -#include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -24,17 +26,6 @@ #include #include #include -#include - -void onSpawned_minecart(struct world* world, struct entity* entity) { - if (entity->type == ENT_MINECARTRIDEABLE) entity->objectData = 0; - else if (entity->type == ENT_MINECARTCHEST) entity->objectData = 1; - else if (entity->type == ENT_MINECARTFURNACE) entity->objectData = 2; - else if (entity->type == ENT_MINECARTTNT) entity->objectData = 3; - else if (entity->type == ENT_MINECARTSPAWNER) entity->objectData = 4; - else if (entity->type == ENT_MINECARTHOPPER) entity->objectData = 5; - else if (entity->type == ENT_MINECARTCOMMANDBLOCK) entity->objectData = 6; -} struct entity_info* getEntityInfo(uint32_t id) { if (id < 0 || id > entity_infos->size) return NULL; @@ -51,308 +42,6 @@ void swingArm(struct entity* entity) { END_BROADCAST(entity->world->players) } -void add_entity_info(uint32_t eid, struct entity_info* bm) { - ensure_collection(entity_infos, eid + 1); - entity_infos->data[eid] = bm; - if (entity_infos->size < eid) entity_infos->size = eid; - entity_infos->count++; -} - -int onTick_tnt(struct world* world, struct entity* ent) { - if (ent->data.tnt.fuse-- <= 0) { - world_despawn_entity(world, ent); - world_explode(world, NULL, ent->x, ent->y + .5, ent->z, 4.); - freeEntity(ent); - return 1; - } - return 0; -} - -int onTick_fallingblock(struct world* world, struct entity* ent) { - // TODO: mc has some methods to prevent dupes here, we should see if basin is afflicted - if (ent->on_ground && ent->age > 1) { - block b = world_get_block(world, (int32_t) floor(ent->x), (int32_t) floor(ent->y), (int32_t) floor(ent->z)); - if (!falling_canFallThrough(b)) { - struct slot sl; - sl.item = ent->data.fallingblock.b >> 4; - sl.damage = ent->data.fallingblock.b & 0x0f; - sl.count = 1; - sl.nbt = NULL; - game_drop_block(world, &sl, (int32_t) floor(ent->x), (int32_t) floor(ent->y - .01), (int32_t) floor(ent->z)); - //ent->onGround = 0; - //return 0; - } else { - world_set_block(world, ent->data.fallingblock.b, (int32_t) floor(ent->x), (int32_t) floor(ent->y), (int32_t) floor(ent->z)); - } - //TODO: tile entities - world_despawn_entity(world, ent); - freeEntity(ent); - return 1; - } - return 0; -} - -void onInteract_cow(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index) { - if (item->item == ITM_BUCKET && interacter->gamemode != 1) { // TODO: not child - if (item->count == 1) { - item->item = ITM_MILK; - inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); - } else { - item->count--; - inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); - struct slot slot; - slot.item = ITM_MILK; - slot.count = 1; - slot.damage = 0; - slot.nbt = NULL; - if (inventory_add_player(interacter, interacter->inventory, &slot, 1)) { - dropPlayerItem(interacter, &slot); - } - } - } -} - -void onInteract_mooshroom(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index) { - if (item->item == ITM_BOWL && interacter->gamemode != 1) { // TODO: not child - if (item->count == 1) { - item->item = ITM_MUSHROOMSTEW; - inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); - } else { - item->count--; - inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); - struct slot slot; - slot.item = ITM_MUSHROOMSTEW; - slot.count = 1; - slot.damage = 0; - slot.nbt = NULL; - if (inventory_add_player(interacter, interacter->inventory, &slot, 1)) { - dropPlayerItem(interacter, &slot); - } - } - } else if (item->item == ITM_SHEARS && interacter->gamemode != 1) { // TODO: not child - //TODO: explosion - struct entity* ent = entity_new(nextEntityID++, entity->x, entity->y, entity->z, ENT_COW, entity->yaw, entity->pitch); - ent->health = entity->health; - memcpy(&ent->data, &entity->data, sizeof(union entity_data)); - world_spawn_entity(world, ent); - world_despawn_entity(world, entity); - freeEntity(entity); - struct item_info* ii = getItemInfo(ITM_SHEARS); - if (ii != NULL && ii->onItemAttacked != NULL) (*ii->onItemAttacked)(world, interacter, slot_index, item, ent); - struct slot slot; - slot.item = BLK_MUSHROOM_1; - slot.count = 5; - slot.damage = 0; - slot.nbt = NULL; - dropEntityItem_explode(ent, &slot); // TODO: fix? - } else onInteract_cow(world, entity, interacter, item, slot_index); -} - -int tick_arrow(struct world* world, struct entity* entity) { - if (entity->data.arrow.ticksInGround == 0) { - double hx = 0.; - double hy = 0.; - double hz = 0.; - int hf = world_rayTrace(entity->world, entity->x, entity->y, entity->z, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ, 0, 1, 0, &hx, &hy, &hz); - //printf("hf = %i -- %f, %f, %f\n", hf, entity->x, entity->y, entity->z); - //printf("hf = %i -- %f, %f\n", hf, entity->yaw, entity->pitch); - struct entity* ehit = NULL; - struct entity* shooter = world_get_entity(world, entity->objectData - 1); - double bd = 999.; - BEGIN_HASHMAP_ITERATION(world->entities) - struct entity* e2 = value; - double rd = entity_distsq_block(e2, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ); - if (rd > 4) continue; - //printf("4d %f\n", rd); - if (e2 != entity && e2 != shooter && hasFlag(getEntityInfo(e2->type), "livingbase")) { //todo: ticksInAir >= 5? - struct boundingbox eb; - getEntityCollision(e2, &eb); - //eb.minX -= .3; - //eb.maxX += .3; - //eb.minY -= .3; - //eb.maxY += .3; - //eb.minZ -= .3; - //eb.maxZ += .3; - double rx = 0.; - double ry = 0.; - double rz = 0.; - int face = world_blockRayTrace(&eb, 0, 0, 0, entity->x, entity->y, entity->z, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ, &rx, &ry, &rz); - if (face >= 0) { - double dist = (entity->x + entity->motX - rx) * (entity->x + entity->motX - rx) + (entity->y + entity->motY - ry) * (entity->y + entity->motY - ry) + (entity->z + entity->motZ - rz) * (entity->z + entity->motZ - rz); //entity_distsq_block(entity, rx, ry, rz); - //printf("%f\n", dist); - if (dist < bd) { - bd = dist; - ehit = e2; - } - } - } - END_HASHMAP_ITERATION(world->entities) - if (ehit != NULL) { - float speed = sqrtf(entity->motX * entity->motX + entity->motY * entity->motY + entity->motZ * entity->motZ); - int damage = ceil(speed * entity->data.arrow.damage); - if (entity->data.arrow.isCritical) damage += rand() % (damage / 2 + 2); - //TODO: if burning and not enderman, set entity on fire for 5 ticks. - if (damageEntity(ehit, damage, 1)) { - //TODO: entity arrow count ++; - if (entity->data.arrow.knockback > 0.) { - float hspeed = sqrtf(entity->motX * entity->motX + entity->motZ * entity->motZ); - if (hspeed > 0.) applyVelocity(ehit, entity->motX * entity->data.arrow.knockback * .6 / hspeed, .1, entity->motZ * entity->data.arrow.knockback * .6 / hspeed); - } - } //TODO: else bounce - //TODO: arrow sound - if (ehit->type != ENT_ENDERMAN) { - world_despawn_entity(world, entity); - freeEntity(entity); - return 1; - } - } else if (hf >= 0) { - entity->x = hx; - entity->y = hy; - entity->z = hz; - if (hf == YN) entity->y -= .001; - if (hf == XN) entity->x -= .001; - if (hf == ZN) entity->z -= .001; - entity->motX = hx - entity->x; - entity->motY = hy - entity->y; - entity->motZ = hz - entity->z; - //float ds = sqrt(entity->motX * entity->motX + entity->motY * entity->motY + entity->motZ * entity->motZ); - //entity->x -= entity->motX / ds * 0.05000000074505806; - //entity->y -= entity->motY / ds * 0.05000000074505806; - //entity->z -= entity->motZ / ds * 0.05000000074505806; - entity->data.arrow.ticksInGround = 1; - entity->data.arrow.isCritical = 0; - entity->immovable = 1; - entity->last_x = 0.; - entity->last_y = 0.; - entity->last_z = 0.; - } - } else { - if (entity->data.arrow.ticksInGround == 1) { - entity->motX = 0.; - entity->motY = 0.; - entity->motZ = 0.; - } - entity->data.arrow.ticksInGround++; - if (entity->data.arrow.ticksInGround == 1200) { - world_despawn_entity(world, entity); - freeEntity(entity); - return 1; - } - } -//printf("hf2c = %f, %f, %f\n", entity->x, entity->y, entity->z); - - if (entity->data.arrow.ticksInGround == 0) { - float dhz = sqrtf(entity->motX * entity->motX + entity->motZ * entity->motZ); - entity->yaw = atan2f(entity->motX, entity->motZ) * 180. / M_PI; - entity->pitch = atan2f(entity->motY, dhz) * 180. / M_PI; - //printf("desired %f, %f, %f\n", entity->pitch, entity->motY, dhz); - //printf("yaw = %f, last_yaw = %f\npitch = %f, last_pitch = %f\n", entity->yaw, entity->last_yaw, entity->pitch, entity->last_pitch); - if ((entity->last_yaw == 0. && entity->last_pitch == 0.)) { - entity->last_yaw = entity->yaw; - entity->last_pitch = entity->pitch; - } else { - while (entity->pitch - entity->last_pitch < -180.) - entity->last_pitch -= 360.; - while (entity->pitch - entity->last_pitch >= 180.) - entity->last_pitch += 360.; - while (entity->yaw - entity->last_yaw < -180.) - entity->last_yaw -= 360.; - while (entity->yaw - entity->last_yaw >= 180.) - entity->last_yaw += 360.; - entity->pitch = entity->last_pitch + (entity->pitch - entity->last_pitch) * .2; - entity->yaw = entity->last_yaw + (entity->yaw - entity->last_yaw) * .2; - } - } - return 0; -} - -int tick_itemstack(struct world* world, struct entity* entity) { - if (entity->data.itemstack.delayBeforeCanPickup > 0) { - entity->data.itemstack.delayBeforeCanPickup--; - return 0; - } - if (entity->age >= 6000) { - world_despawn_entity(world, entity); - freeEntity(entity); - return 1; - } - if (tick_counter % 10 != 0) return 0; - struct boundingbox cebb; - getEntityCollision(entity, &cebb); - cebb.minX -= .625; - cebb.maxX += .625; - cebb.maxY += .75; - cebb.minZ -= .625; - cebb.maxZ += .625; - struct boundingbox oebb; -//int32_t chunk_x = ((int32_t) entity->x) >> 4; -//int32_t chunk_z = ((int32_t) entity->z) >> 4; -//for (int32_t icx = chunk_x - 1; icx <= chunk_x + 1; icx++) -//for (int32_t icz = chunk_z - 1; icz <= chunk_z + 1; icz++) { -//struct chunk* ch = world_get_chunk(entity->world, icx, icz); -//if (ch != NULL) { - BEGIN_HASHMAP_ITERATION(entity->world->entities) - struct entity* oe = (struct entity*) value; - if (oe == entity || entity_distsq(entity, oe) > 16. * 16.) continue; - if (oe->type == ENT_PLAYER && oe->health > 0.) { - getEntityCollision(oe, &oebb); - //printf("%f, %f, %f vs %f, %f, %f\n", entity->x, entity->y, entity->z, oe->x, oe->y, oe->z); - if (boundingbox_intersects(&oebb, &cebb)) { - int os = entity->data.itemstack.slot->count; - pthread_mutex_lock(&oe->data.player.player->inventory->mut); - int r = inventory_add_player(oe->data.player.player, oe->data.player.player->inventory, entity->data.itemstack.slot, 1); - pthread_mutex_unlock(&oe->data.player.player->inventory->mut); - if (r <= 0) { - BEGIN_BROADCAST_DIST(entity, 32.) - struct packet* pkt = xmalloc(sizeof(struct packet)); - pkt->id = PKT_PLAY_CLIENT_COLLECTITEM; - pkt->data.play_client.collectitem.collected_entity_id = entity->id; - pkt->data.play_client.collectitem.collector_entity_id = oe->id; - pkt->data.play_client.collectitem.pickup_item_count = os - r; - add_queue(bc_player->outgoing_packets, pkt); - END_BROADCAST(entity->world->players) - world_despawn_entity(world, entity); - freeEntity(entity); - return 1; - } else { - BEGIN_BROADCAST_DIST(entity, 128.) - struct packet* pkt = xmalloc(sizeof(struct packet)); - pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA; - pkt->data.play_client.entitymetadata.entity_id = entity->id; - writeMetadata(entity, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size); - add_queue(bc_player->outgoing_packets, pkt); - END_BROADCAST(entity->world->players) - BREAK_HASHMAP_ITERATION(entity->world->entities) - } - break; - } - } else if (oe->type == ENT_ITEM) { - if (oe->data.itemstack.slot->item == entity->data.itemstack.slot->item && oe->data.itemstack.slot->damage == entity->data.itemstack.slot->damage && oe->data.itemstack.slot->count + entity->data.itemstack.slot->count <= slot_max_size(entity->data.itemstack.slot)) { - getEntityCollision(oe, &oebb); - oebb.minX -= .625; - oebb.maxX += .625; - cebb.maxY += .75; - oebb.minZ -= .625; - oebb.maxZ += .625; - if (boundingbox_intersects(&oebb, &cebb)) { - world_despawn_entity(world, entity); - oe->data.itemstack.slot->count += entity->data.itemstack.slot->count; - freeEntity(entity); - BEGIN_BROADCAST_DIST(oe, 128.) - struct packet* pkt = xmalloc(sizeof(struct packet)); - pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA; - pkt->data.play_client.entitymetadata.entity_id = oe->id; - writeMetadata(oe, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size); - add_queue(bc_player->outgoing_packets, pkt); - END_BROADCAST(oe->world->players) - return 1; - } - } - } - END_HASHMAP_ITERATION(entity->world->entities) - return 0; -} - struct mempool* entities_pool; void init_entities() { @@ -373,7 +62,7 @@ void init_entities() { if (tmp == NULL || tmp->type != JSON_NUMBER) { goto entity_error; } - uint32_t id = (block) tmp->data.number; + uint32_t id = (uint32_t) tmp->data.number; if (id < 0) goto entity_error; tmp = json_get(child_json, "maxHealth"); if (tmp == NULL || tmp->type != JSON_NUMBER) { @@ -460,7 +149,7 @@ void init_entities() { tmp = json_get(child_json, "dataname"); if (tmp == NULL || tmp->type != JSON_STRING) goto entity_error; info->dataname = str_dup(tmp->data.string, 0, entities_pool); - add_entity_info(id, info); + list_set(entity_infos, id, info); continue; entity_error: ; printf("[WARNING] Error Loading Entity \"%s\"! Skipped.\n", child_json->name); diff --git a/src/entity_impl.c b/src/entity_impl.c new file mode 100644 index 0000000..d4a02c4 --- /dev/null +++ b/src/entity_impl.c @@ -0,0 +1,308 @@ +#include "basin/entity_impl.h" + + +void onSpawned_minecart(struct world* world, struct entity* entity) { + if (entity->type == ENT_MINECARTRIDEABLE) entity->objectData = 0; + else if (entity->type == ENT_MINECARTCHEST) entity->objectData = 1; + else if (entity->type == ENT_MINECARTFURNACE) entity->objectData = 2; + else if (entity->type == ENT_MINECARTTNT) entity->objectData = 3; + else if (entity->type == ENT_MINECARTSPAWNER) entity->objectData = 4; + else if (entity->type == ENT_MINECARTHOPPER) entity->objectData = 5; + else if (entity->type == ENT_MINECARTCOMMANDBLOCK) entity->objectData = 6; +} + + +int onTick_tnt(struct world* world, struct entity* ent) { + if (ent->data.tnt.fuse-- <= 0) { + world_despawn_entity(world, ent); + world_explode(world, NULL, ent->x, ent->y + .5, ent->z, 4.); + freeEntity(ent); + return 1; + } + return 0; +} + +int onTick_fallingblock(struct world* world, struct entity* ent) { + // TODO: mc has some methods to prevent dupes here, we should see if basin is afflicted + if (ent->on_ground && ent->age > 1) { + block b = world_get_block(world, (int32_t) floor(ent->x), (int32_t) floor(ent->y), (int32_t) floor(ent->z)); + if (!falling_canFallThrough(b)) { + struct slot sl; + sl.item = ent->data.fallingblock.b >> 4; + sl.damage = ent->data.fallingblock.b & 0x0f; + sl.count = 1; + sl.nbt = NULL; + game_drop_block(world, &sl, (int32_t) floor(ent->x), (int32_t) floor(ent->y - .01), (int32_t) floor(ent->z)); + //ent->onGround = 0; + //return 0; + } else { + world_set_block(world, ent->data.fallingblock.b, (int32_t) floor(ent->x), (int32_t) floor(ent->y), (int32_t) floor(ent->z)); + } + //TODO: tile entities + world_despawn_entity(world, ent); + freeEntity(ent); + return 1; + } + return 0; +} + +void onInteract_cow(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index) { + if (item->item == ITM_BUCKET && interacter->gamemode != 1) { // TODO: not child + if (item->count == 1) { + item->item = ITM_MILK; + inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); + } else { + item->count--; + inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); + struct slot slot; + slot.item = ITM_MILK; + slot.count = 1; + slot.damage = 0; + slot.nbt = NULL; + if (inventory_add_player(interacter, interacter->inventory, &slot, 1)) { + dropPlayerItem(interacter, &slot); + } + } + } +} + +void onInteract_mooshroom(struct world* world, struct entity* entity, struct player* interacter, struct slot* item, int16_t slot_index) { + if (item->item == ITM_BOWL && interacter->gamemode != 1) { // TODO: not child + if (item->count == 1) { + item->item = ITM_MUSHROOMSTEW; + inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); + } else { + item->count--; + inventory_set_slot(interacter, interacter->inventory, slot_index, item, 1, 0); + struct slot slot; + slot.item = ITM_MUSHROOMSTEW; + slot.count = 1; + slot.damage = 0; + slot.nbt = NULL; + if (inventory_add_player(interacter, interacter->inventory, &slot, 1)) { + dropPlayerItem(interacter, &slot); + } + } + } else if (item->item == ITM_SHEARS && interacter->gamemode != 1) { // TODO: not child + //TODO: explosion + struct entity* ent = entity_new(nextEntityID++, entity->x, entity->y, entity->z, ENT_COW, entity->yaw, entity->pitch); + ent->health = entity->health; + memcpy(&ent->data, &entity->data, sizeof(union entity_data)); + world_spawn_entity(world, ent); + world_despawn_entity(world, entity); + freeEntity(entity); + struct item_info* ii = getItemInfo(ITM_SHEARS); + if (ii != NULL && ii->onItemAttacked != NULL) (*ii->onItemAttacked)(world, interacter, slot_index, item, ent); + struct slot slot; + slot.item = BLK_MUSHROOM_1; + slot.count = 5; + slot.damage = 0; + slot.nbt = NULL; + dropEntityItem_explode(ent, &slot); // TODO: fix? + } else onInteract_cow(world, entity, interacter, item, slot_index); +} + +int tick_arrow(struct world* world, struct entity* entity) { + if (entity->data.arrow.ticksInGround == 0) { + double hx = 0.; + double hy = 0.; + double hz = 0.; + int hf = world_rayTrace(entity->world, entity->x, entity->y, entity->z, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ, 0, 1, 0, &hx, &hy, &hz); + //printf("hf = %i -- %f, %f, %f\n", hf, entity->x, entity->y, entity->z); + //printf("hf = %i -- %f, %f\n", hf, entity->yaw, entity->pitch); + struct entity* ehit = NULL; + struct entity* shooter = world_get_entity(world, entity->objectData - 1); + double bd = 999.; + BEGIN_HASHMAP_ITERATION(world->entities) + struct entity* e2 = value; + double rd = entity_distsq_block(e2, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ); + if (rd > 4) continue; + //printf("4d %f\n", rd); + if (e2 != entity && e2 != shooter && hasFlag(getEntityInfo(e2->type), "livingbase")) { //todo: ticksInAir >= 5? + struct boundingbox eb; + getEntityCollision(e2, &eb); + //eb.minX -= .3; + //eb.maxX += .3; + //eb.minY -= .3; + //eb.maxY += .3; + //eb.minZ -= .3; + //eb.maxZ += .3; + double rx = 0.; + double ry = 0.; + double rz = 0.; + int face = world_blockRayTrace(&eb, 0, 0, 0, entity->x, entity->y, entity->z, entity->x + entity->motX, entity->y + entity->motY, entity->z + entity->motZ, &rx, &ry, &rz); + if (face >= 0) { + double dist = (entity->x + entity->motX - rx) * (entity->x + entity->motX - rx) + (entity->y + entity->motY - ry) * (entity->y + entity->motY - ry) + (entity->z + entity->motZ - rz) * (entity->z + entity->motZ - rz); //entity_distsq_block(entity, rx, ry, rz); + //printf("%f\n", dist); + if (dist < bd) { + bd = dist; + ehit = e2; + } + } + } + END_HASHMAP_ITERATION(world->entities) + if (ehit != NULL) { + float speed = sqrtf(entity->motX * entity->motX + entity->motY * entity->motY + entity->motZ * entity->motZ); + int damage = ceil(speed * entity->data.arrow.damage); + if (entity->data.arrow.isCritical) damage += rand() % (damage / 2 + 2); + //TODO: if burning and not enderman, set entity on fire for 5 ticks. + if (damageEntity(ehit, damage, 1)) { + //TODO: entity arrow count ++; + if (entity->data.arrow.knockback > 0.) { + float hspeed = sqrtf(entity->motX * entity->motX + entity->motZ * entity->motZ); + if (hspeed > 0.) applyVelocity(ehit, entity->motX * entity->data.arrow.knockback * .6 / hspeed, .1, entity->motZ * entity->data.arrow.knockback * .6 / hspeed); + } + } //TODO: else bounce + //TODO: arrow sound + if (ehit->type != ENT_ENDERMAN) { + world_despawn_entity(world, entity); + freeEntity(entity); + return 1; + } + } else if (hf >= 0) { + entity->x = hx; + entity->y = hy; + entity->z = hz; + if (hf == YN) entity->y -= .001; + if (hf == XN) entity->x -= .001; + if (hf == ZN) entity->z -= .001; + entity->motX = hx - entity->x; + entity->motY = hy - entity->y; + entity->motZ = hz - entity->z; + //float ds = sqrt(entity->motX * entity->motX + entity->motY * entity->motY + entity->motZ * entity->motZ); + //entity->x -= entity->motX / ds * 0.05000000074505806; + //entity->y -= entity->motY / ds * 0.05000000074505806; + //entity->z -= entity->motZ / ds * 0.05000000074505806; + entity->data.arrow.ticksInGround = 1; + entity->data.arrow.isCritical = 0; + entity->immovable = 1; + entity->last_x = 0.; + entity->last_y = 0.; + entity->last_z = 0.; + } + } else { + if (entity->data.arrow.ticksInGround == 1) { + entity->motX = 0.; + entity->motY = 0.; + entity->motZ = 0.; + } + entity->data.arrow.ticksInGround++; + if (entity->data.arrow.ticksInGround == 1200) { + world_despawn_entity(world, entity); + freeEntity(entity); + return 1; + } + } +//printf("hf2c = %f, %f, %f\n", entity->x, entity->y, entity->z); + + if (entity->data.arrow.ticksInGround == 0) { + float dhz = sqrtf(entity->motX * entity->motX + entity->motZ * entity->motZ); + entity->yaw = atan2f(entity->motX, entity->motZ) * 180. / M_PI; + entity->pitch = atan2f(entity->motY, dhz) * 180. / M_PI; + //printf("desired %f, %f, %f\n", entity->pitch, entity->motY, dhz); + //printf("yaw = %f, last_yaw = %f\npitch = %f, last_pitch = %f\n", entity->yaw, entity->last_yaw, entity->pitch, entity->last_pitch); + if ((entity->last_yaw == 0. && entity->last_pitch == 0.)) { + entity->last_yaw = entity->yaw; + entity->last_pitch = entity->pitch; + } else { + while (entity->pitch - entity->last_pitch < -180.) + entity->last_pitch -= 360.; + while (entity->pitch - entity->last_pitch >= 180.) + entity->last_pitch += 360.; + while (entity->yaw - entity->last_yaw < -180.) + entity->last_yaw -= 360.; + while (entity->yaw - entity->last_yaw >= 180.) + entity->last_yaw += 360.; + entity->pitch = entity->last_pitch + (entity->pitch - entity->last_pitch) * .2; + entity->yaw = entity->last_yaw + (entity->yaw - entity->last_yaw) * .2; + } + } + return 0; +} + +int tick_itemstack(struct world* world, struct entity* entity) { + if (entity->data.itemstack.delayBeforeCanPickup > 0) { + entity->data.itemstack.delayBeforeCanPickup--; + return 0; + } + if (entity->age >= 6000) { + world_despawn_entity(world, entity); + freeEntity(entity); + return 1; + } + if (tick_counter % 10 != 0) return 0; + struct boundingbox cebb; + getEntityCollision(entity, &cebb); + cebb.minX -= .625; + cebb.maxX += .625; + cebb.maxY += .75; + cebb.minZ -= .625; + cebb.maxZ += .625; + struct boundingbox oebb; +//int32_t chunk_x = ((int32_t) entity->x) >> 4; +//int32_t chunk_z = ((int32_t) entity->z) >> 4; +//for (int32_t icx = chunk_x - 1; icx <= chunk_x + 1; icx++) +//for (int32_t icz = chunk_z - 1; icz <= chunk_z + 1; icz++) { +//struct chunk* ch = world_get_chunk(entity->world, icx, icz); +//if (ch != NULL) { + BEGIN_HASHMAP_ITERATION(entity->world->entities) + struct entity* oe = (struct entity*) value; + if (oe == entity || entity_distsq(entity, oe) > 16. * 16.) continue; + if (oe->type == ENT_PLAYER && oe->health > 0.) { + getEntityCollision(oe, &oebb); + //printf("%f, %f, %f vs %f, %f, %f\n", entity->x, entity->y, entity->z, oe->x, oe->y, oe->z); + if (boundingbox_intersects(&oebb, &cebb)) { + int os = entity->data.itemstack.slot->count; + pthread_mutex_lock(&oe->data.player.player->inventory->mut); + int r = inventory_add_player(oe->data.player.player, oe->data.player.player->inventory, entity->data.itemstack.slot, 1); + pthread_mutex_unlock(&oe->data.player.player->inventory->mut); + if (r <= 0) { + BEGIN_BROADCAST_DIST(entity, 32.) + struct packet* pkt = xmalloc(sizeof(struct packet)); + pkt->id = PKT_PLAY_CLIENT_COLLECTITEM; + pkt->data.play_client.collectitem.collected_entity_id = entity->id; + pkt->data.play_client.collectitem.collector_entity_id = oe->id; + pkt->data.play_client.collectitem.pickup_item_count = os - r; + add_queue(bc_player->outgoing_packets, pkt); + END_BROADCAST(entity->world->players) + world_despawn_entity(world, entity); + freeEntity(entity); + return 1; + } else { + BEGIN_BROADCAST_DIST(entity, 128.) + struct packet* pkt = xmalloc(sizeof(struct packet)); + pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA; + pkt->data.play_client.entitymetadata.entity_id = entity->id; + writeMetadata(entity, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size); + add_queue(bc_player->outgoing_packets, pkt); + END_BROADCAST(entity->world->players) + BREAK_HASHMAP_ITERATION(entity->world->entities) + } + break; + } + } else if (oe->type == ENT_ITEM) { + if (oe->data.itemstack.slot->item == entity->data.itemstack.slot->item && oe->data.itemstack.slot->damage == entity->data.itemstack.slot->damage && oe->data.itemstack.slot->count + entity->data.itemstack.slot->count <= slot_max_size(entity->data.itemstack.slot)) { + getEntityCollision(oe, &oebb); + oebb.minX -= .625; + oebb.maxX += .625; + cebb.maxY += .75; + oebb.minZ -= .625; + oebb.maxZ += .625; + if (boundingbox_intersects(&oebb, &cebb)) { + world_despawn_entity(world, entity); + oe->data.itemstack.slot->count += entity->data.itemstack.slot->count; + freeEntity(entity); + BEGIN_BROADCAST_DIST(oe, 128.) + struct packet* pkt = xmalloc(sizeof(struct packet)); + pkt->id = PKT_PLAY_CLIENT_ENTITYMETADATA; + pkt->data.play_client.entitymetadata.entity_id = oe->id; + writeMetadata(oe, &pkt->data.play_client.entitymetadata.metadata.metadata, &pkt->data.play_client.entitymetadata.metadata.metadata_size); + add_queue(bc_player->outgoing_packets, pkt); + END_BROADCAST(oe->world->players) + return 1; + } + } + } + END_HASHMAP_ITERATION(entity->world->entities) + return 0; +}