1 #include <dragonstd/map.h>
4 #include "client/client_entity.h"
5 #include "client/client_player.h"
7 ClientEntityType client_entity_types[COUNT_ENTITY];
12 // called when adding, getting or removing an entity from the map
13 static int cmp_entity(const Refcount *entity, const u64 *id)
15 return u64_cmp(&((ClientEntity *) entity->obj)->data.id, id);
19 // called when server sent removal of entity
20 static void entity_drop(ClientEntity *entity)
22 if (entity->type->remove)
23 entity->type->remove(entity);
25 refcount_drp(&entity->rc);
29 // called when all refs have been dropped
30 static void entity_delete(ClientEntity *entity)
32 if (entity->type->free)
33 entity->type->free(entity);
35 refcount_dst(&entity->rc);
37 if (entity->data.nametag)
38 free(entity->data.nametag);
40 pthread_rwlock_init(&entity->lock_pos_rot, NULL);
41 pthread_rwlock_init(&entity->lock_box_eye, NULL);
42 pthread_rwlock_init(&entity->lock_nametag, NULL);
49 void client_entity_init()
56 void client_entity_deinit()
58 // forget all entities
59 map_cnl(&entities, &refcount_drp, NULL, NULL, 0);
62 ClientEntity *client_entity_grab(u64 id)
64 return id ? map_get(&entities, &id, &cmp_entity, &refcount_grb) : NULL;
67 void client_entity_transform(ClientEntity *entity)
72 entity->model->root->pos = (v3f32) {entity->data.pos.x, entity->data.pos.y, entity->data.pos.z};
73 entity->model->root->rot = (v3f32) {entity->data.rot.x, entity->data.rot.y, entity->data.rot.z};
75 if (entity->type->transform)
76 entity->type->transform(entity);
78 model_node_transform(entity->model->root);
81 void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityAdd *pkt)
83 if (pkt->type >= COUNT_ENTITY)
86 ClientEntity *entity = malloc(sizeof *entity);
88 entity->data = pkt->data;
89 entity->type = &client_entity_types[pkt->type];
90 refcount_ini(&entity->rc, entity, &entity_delete);
92 pkt->data.nametag = NULL;
96 pthread_rwlock_init(&entity->lock_pos_rot, NULL);
97 pthread_rwlock_init(&entity->lock_box_eye, NULL);
98 pthread_rwlock_init(&entity->lock_nametag, NULL);
100 if (entity->type->add)
101 entity->type->add(entity);
103 if (!map_add(&entities, &entity->data.id, &entity->rc, &cmp_entity, &refcount_inc))
104 fprintf(stderr, "[warning] failed to add entity %lu\n", entity->data.id);
106 refcount_drp(&entity->rc);
109 void client_entity_remove(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityRemove *pkt)
111 map_del(&entities, &pkt->id, &cmp_entity, &entity_drop, NULL, &refcount_obj);
114 void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt)
116 ClientEntity *entity = client_entity_grab(pkt->id);
121 pthread_rwlock_wrlock(&entity->lock_pos_rot);
123 entity->data.pos = pkt->pos;
124 entity->data.rot = pkt->rot;
126 if (entity->type->update_pos_rot)
127 entity->type->update_pos_rot(entity);
129 pthread_rwlock_unlock(&entity->lock_pos_rot);
131 refcount_drp(&entity->rc);
134 void client_entity_update_box_eye(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt)
136 ClientEntity *entity = client_entity_grab(pkt->id);
141 pthread_rwlock_wrlock(&entity->lock_box_eye);
143 entity->data.box = pkt->box;
144 entity->data.eye = pkt->eye;
146 if (entity->type->update_box_eye)
147 entity->type->update_box_eye(entity);
149 pthread_rwlock_unlock(&entity->lock_box_eye);
151 refcount_drp(&entity->rc);
154 void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt)
156 ClientEntity *entity = client_entity_grab(pkt->id);
161 pthread_rwlock_wrlock(&entity->lock_nametag);
163 if (entity->data.nametag)
164 free(entity->data.nametag);
166 entity->data.nametag = pkt->nametag;
169 if (entity->type->update_nametag)
170 entity->type->update_nametag(entity);
172 pthread_rwlock_unlock(&entity->lock_nametag);
174 refcount_drp(&entity->rc);