mirror of https://github.com/basinserver/basin/
entity impl vs definition split
This commit is contained in:
parent
7c57eef9e2
commit
5b505f29ec
|
@ -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;
|
||||
|
|
|
@ -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
|
323
src/entity.c
323
src/entity.c
|
@ -5,16 +5,18 @@
|
|||
* Author: root
|
||||
*/
|
||||
|
||||
#include "basin/packet.h"
|
||||
#include <basin/packet.h>
|
||||
#include <basin/basin.h>
|
||||
#include <basin/network.h>
|
||||
#include <basin/queue.h>
|
||||
#include <basin/entity.h>
|
||||
#include <basin/ai.h>
|
||||
#include <basin/game.h>
|
||||
#include <basin/plugin.h>
|
||||
#include <basin/entity_impl.h>
|
||||
#include <avuna/string.h>
|
||||
#include <avuna/json.h>
|
||||
#include <avuna/queue.h>
|
||||
#include <avuna/util.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -24,17 +26,6 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <avuna/util.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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue