]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - com_ents4.c
cmd: Use reentrant mutex for cbufs. Fixes deadlock when expanding aliases in some...
[xonotic/darkplaces.git] / com_ents4.c
1 #include "quakedef.h"
2 #include "protocol.h"
3
4 entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
5 {
6         entityframe4_database_t *d;
7         d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d));
8         d->mempool = pool;
9         EntityFrame4_ResetDatabase(d);
10         return d;
11 }
12
13 void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
14 {
15         int i;
16         for (i = 0;i < MAX_ENTITY_HISTORY;i++)
17                 if (d->commit[i].entity)
18                         Mem_Free(d->commit[i].entity);
19         if (d->referenceentity)
20                 Mem_Free(d->referenceentity);
21         Mem_Free(d);
22 }
23
24 void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
25 {
26         int i;
27         d->referenceframenum = -1;
28         for (i = 0;i < MAX_ENTITY_HISTORY;i++)
29                 d->commit[i].numentities = 0;
30         for (i = 0;i < d->maxreferenceentities;i++)
31                 d->referenceentity[i] = defaultstate;
32 }
33
34 entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
35 {
36         if (d->maxreferenceentities <= number)
37         {
38                 int oldmax = d->maxreferenceentities;
39                 entity_state_t *oldentity = d->referenceentity;
40                 d->maxreferenceentities = (number + 15) & ~7;
41                 d->referenceentity = (entity_state_t *)Mem_Alloc(d->mempool, d->maxreferenceentities * sizeof(*d->referenceentity));
42                 if (oldentity)
43                 {
44                         memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity));
45                         Mem_Free(oldentity);
46                 }
47                 // clear the newly created entities
48                 for (;oldmax < d->maxreferenceentities;oldmax++)
49                 {
50                         d->referenceentity[oldmax] = defaultstate;
51                         d->referenceentity[oldmax].number = oldmax;
52                 }
53         }
54         return d->referenceentity + number;
55 }
56
57 void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
58 {
59         // resize commit's entity list if full
60         if (d->currentcommit->maxentities <= d->currentcommit->numentities)
61         {
62                 entity_state_t *oldentity = d->currentcommit->entity;
63                 d->currentcommit->maxentities += 8;
64                 d->currentcommit->entity = (entity_state_t *)Mem_Alloc(d->mempool, d->currentcommit->maxentities * sizeof(*d->currentcommit->entity));
65                 if (oldentity)
66                 {
67                         memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity));
68                         Mem_Free(oldentity);
69                 }
70         }
71         d->currentcommit->entity[d->currentcommit->numentities++] = *s;
72 }
73
74 int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode)
75 {
76         int i, j, found;
77         entity_database4_commit_t *commit;
78         if (framenum == -1)
79         {
80                 // reset reference, but leave commits alone
81                 d->referenceframenum = -1;
82                 for (i = 0;i < d->maxreferenceentities;i++)
83                 {
84                         d->referenceentity[i] = defaultstate;
85                 // if this is the server, remove commits
86                         for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
87                                 commit->numentities = 0;
88                 }
89                 found = true;
90         }
91         else if (d->referenceframenum == framenum)
92                 found = true;
93         else
94         {
95                 found = false;
96                 for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
97                 {
98                         if (commit->numentities && commit->framenum <= framenum)
99                         {
100                                 if (commit->framenum == framenum)
101                                 {
102                                         found = true;
103                                         d->referenceframenum = framenum;
104                                         if (developer_networkentities.integer >= 3)
105                                         {
106                                                 for (j = 0;j < commit->numentities;j++)
107                                                 {
108                                                         entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number);
109                                                         if (commit->entity[j].active != s->active)
110                                                         {
111                                                                 if (commit->entity[j].active == ACTIVE_NETWORK)
112                                                                         Con_Printf("commit entity %i has become active (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
113                                                                 else
114                                                                         Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
115                                                         }
116                                                         *s = commit->entity[j];
117                                                 }
118                                         }
119                                         else
120                                                 for (j = 0;j < commit->numentities;j++)
121                                                         *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j];
122                                 }
123                                 commit->numentities = 0;
124                         }
125                 }
126         }
127         if (developer_networkentities.integer >= 1)
128         {
129                 Con_Printf("ack ref:%i database updated to: ref:%i commits:", framenum, d->referenceframenum);
130                 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
131                         if (d->commit[i].numentities)
132                                 Con_Printf(" %i", d->commit[i].framenum);
133                 Con_Print("\n");
134         }
135         return found;
136 }