]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/client_entity.c
refactoring
[dragonblocks_alpha.git] / src / client / client_entity.c
1 #include <dragonstd/map.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include "client/client_entity.h"
5 #include "client/client_player.h"
6
7 ClientEntityType client_entity_types[COUNT_ENTITY];
8
9 static Map entities;
10
11 // any thread
12 // called when adding, getting or removing an entity from the map
13 static int cmp_entity(const Refcount *entity, const u64 *id)
14 {
15         return u64_cmp(&((ClientEntity *) entity->obj)->data.id, id);
16 }
17
18 // recv thread
19 // called when server sent removal of entity
20 static void entity_drop(ClientEntity *entity)
21 {
22         if (entity->type->remove)
23                 entity->type->remove(entity);
24
25         refcount_drp(&entity->rc);
26 }
27
28 // any thread
29 // called when all refs have been dropped
30 static void entity_delete(ClientEntity *entity)
31 {
32         if (entity->type->free)
33                 entity->type->free(entity);
34
35         refcount_dst(&entity->rc);
36
37         if (entity->data.nametag)
38                 free(entity->data.nametag);
39
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);
43
44         free(entity);
45 }
46
47 // main thread
48 // called on startup
49 void client_entity_init()
50 {
51         map_ini(&entities);
52 }
53
54 // main thead
55 // called on shutdown
56 void client_entity_deinit()
57 {
58         // forget all entities
59         map_cnl(&entities, &refcount_drp, NULL, NULL, 0);
60 }
61
62 ClientEntity *client_entity_grab(u64 id)
63 {
64         return id ? map_get(&entities, &id, &cmp_entity, &refcount_grb) : NULL;
65 }
66
67 void client_entity_transform(ClientEntity *entity)
68 {
69         if (!entity->model)
70                 return;
71
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};
74
75         if (entity->type->transform)
76                 entity->type->transform(entity);
77
78         model_node_transform(entity->model->root);
79 }
80
81 void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityAdd *pkt)
82 {
83         if (pkt->type >= COUNT_ENTITY)
84                 return;
85
86         ClientEntity *entity = malloc(sizeof *entity);
87
88         entity->data = pkt->data;
89         entity->type = &client_entity_types[pkt->type];
90         refcount_ini(&entity->rc, entity, &entity_delete);
91
92         pkt->data.nametag = NULL;
93
94         entity->model = NULL;
95
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);
99
100         if (entity->type->add)
101                 entity->type->add(entity);
102
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);
105
106         refcount_drp(&entity->rc);
107 }
108
109 void client_entity_remove(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityRemove *pkt)
110 {
111         map_del(&entities, &pkt->id, &cmp_entity, &entity_drop, NULL, &refcount_obj);
112 }
113
114 void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt)
115 {
116         ClientEntity *entity = client_entity_grab(pkt->id);
117
118         if (!entity)
119                 return;
120
121         pthread_rwlock_wrlock(&entity->lock_pos_rot);
122
123         entity->data.pos = pkt->pos;
124         entity->data.rot = pkt->rot;
125
126         if (entity->type->update_pos_rot)
127                 entity->type->update_pos_rot(entity);
128
129         pthread_rwlock_unlock(&entity->lock_pos_rot);
130
131         refcount_drp(&entity->rc);
132 }
133
134 void client_entity_update_box_eye(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt)
135 {
136         ClientEntity *entity = client_entity_grab(pkt->id);
137
138         if (!entity)
139                 return;
140
141         pthread_rwlock_wrlock(&entity->lock_box_eye);
142
143         entity->data.box = pkt->box;
144         entity->data.eye = pkt->eye;
145
146         if (entity->type->update_box_eye)
147                 entity->type->update_box_eye(entity);
148
149         pthread_rwlock_unlock(&entity->lock_box_eye);
150
151         refcount_drp(&entity->rc);
152 }
153
154 void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt)
155 {
156         ClientEntity *entity = client_entity_grab(pkt->id);
157
158         if (!entity)
159                 return;
160
161         pthread_rwlock_wrlock(&entity->lock_nametag);
162
163         if (entity->data.nametag)
164                 free(entity->data.nametag);
165
166         entity->data.nametag = pkt->nametag;
167         pkt->nametag = NULL;
168
169         if (entity->type->update_nametag)
170                 entity->type->update_nametag(entity);
171
172         pthread_rwlock_unlock(&entity->lock_nametag);
173
174         refcount_drp(&entity->rc);
175 }