protocol: Fix off-by-one when appending space in Protocol_Names
[xonotic/darkplaces.git] / protocol.c
1 #include "quakedef.h"
2
3 // this is 88 bytes (must match entity_state_t in protocol.h)
4 entity_state_t defaultstate =
5 {
6         // ! means this is not sent to client
7         0,//double time; // ! time this state was built (used on client for interpolation)
8         {0,0,0},//float netcenter[3]; // ! for network prioritization, this is the center of the bounding box (which may differ from the origin)
9         {0,0,0},//float origin[3];
10         {0,0,0},//float angles[3];
11         0,//int effects;
12         0,//unsigned int customizeentityforclient; // !
13         0,//unsigned short number; // entity number this state is for
14         0,//unsigned short modelindex;
15         0,//unsigned short frame;
16         0,//unsigned short tagentity;
17         0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light
18         0,//unsigned short viewmodelforclient; // !
19         0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
20         0,//unsigned short nodrawtoclient; // !
21         0,//unsigned short drawonlytoclient; // !
22         0,//unsigned short traileffectnum;
23         {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
24         ACTIVE_NOT,//unsigned char active; // true if a valid state
25         0,//unsigned char lightstyle;
26         0,//unsigned char lightpflags;
27         0,//unsigned char colormap;
28         0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
29         255,//unsigned char alpha;
30         16,//unsigned char scale;
31         0,//unsigned char glowsize;
32         254,//unsigned char glowcolor;
33         0,//unsigned char flags;
34         0,//unsigned char internaleffects; // INTEF_FLAG1QW and so on
35         0,//unsigned char tagindex;
36         {32, 32, 32},//unsigned char colormod[3];
37         {32, 32, 32},//unsigned char glowmod[3];
38 };
39
40 // LadyHavoc: I own protocol ranges 96, 97, 3500-3599
41
42 struct protocolversioninfo_s
43 {
44         int number;
45         protocolversion_t version;
46         const char *name;
47 }
48 protocolversioninfo[] =
49 {
50         { 3505, PROTOCOL_DARKPLACES8 , "DP8"},
51         { 3504, PROTOCOL_DARKPLACES7 , "DP7"},
52         { 3503, PROTOCOL_DARKPLACES6 , "DP6"},
53         { 3502, PROTOCOL_DARKPLACES5 , "DP5"},
54         { 3501, PROTOCOL_DARKPLACES4 , "DP4"},
55         { 3500, PROTOCOL_DARKPLACES3 , "DP3"},
56         {   97, PROTOCOL_DARKPLACES2 , "DP2"},
57         {   96, PROTOCOL_DARKPLACES1 , "DP1"},
58         {   15, PROTOCOL_QUAKEDP     , "QUAKEDP"},
59         {   15, PROTOCOL_QUAKE       , "QUAKE"},
60         {   28, PROTOCOL_QUAKEWORLD  , "QW"},
61         {  250, PROTOCOL_NEHAHRAMOVIE, "NEHAHRAMOVIE"},
62         {10000, PROTOCOL_NEHAHRABJP  , "NEHAHRABJP"},
63         {10001, PROTOCOL_NEHAHRABJP2 , "NEHAHRABJP2"},
64         {10002, PROTOCOL_NEHAHRABJP3 , "NEHAHRABJP3"},
65         {    0, PROTOCOL_UNKNOWN     , NULL}
66 };
67
68 protocolversion_t Protocol_EnumForName(const char *s)
69 {
70         int i;
71         for (i = 0;protocolversioninfo[i].name;i++)
72                 if (!strcasecmp(s, protocolversioninfo[i].name))
73                         return protocolversioninfo[i].version;
74         return PROTOCOL_UNKNOWN;
75 }
76
77 const char *Protocol_NameForEnum(protocolversion_t p)
78 {
79         int i;
80         for (i = 0;protocolversioninfo[i].name;i++)
81                 if (protocolversioninfo[i].version == p)
82                         return protocolversioninfo[i].name;
83         return "UNKNOWN";
84 }
85
86 protocolversion_t Protocol_EnumForNumber(int n)
87 {
88         int i;
89         for (i = 0;protocolversioninfo[i].name;i++)
90                 if (protocolversioninfo[i].number == n)
91                         return protocolversioninfo[i].version;
92         return PROTOCOL_UNKNOWN;
93 }
94
95 int Protocol_NumberForEnum(protocolversion_t p)
96 {
97         int i;
98         for (i = 0;protocolversioninfo[i].name;i++)
99                 if (protocolversioninfo[i].version == p)
100                         return protocolversioninfo[i].number;
101         return 0;
102 }
103
104 void Protocol_Names(char *buffer, size_t buffersize)
105 {
106         int i;
107         if (buffersize < 1)
108                 return;
109         buffer[0] = 0;
110         for (i = 0;protocolversioninfo[i].name;i++)
111         {
112                 if (i > 0)
113                         strlcat(buffer, " ", buffersize);
114                 strlcat(buffer, protocolversioninfo[i].name, buffersize);
115         }
116 }
117
118 void Protocol_UpdateClientStats(const int *stats)
119 {
120         int i;
121         // update the stats array and set deltabits for any changed stats
122         for (i = 0;i < MAX_CL_STATS;i++)
123         {
124                 if (host_client->stats[i] != stats[i])
125                 {
126                         host_client->statsdeltabits[i >> 3] |= 1 << (i & 7);
127                         host_client->stats[i] = stats[i];
128                 }
129         }
130 }
131
132 // only a few stats are within the 32 stat limit of Quake, and most of them
133 // are sent every frame in svc_clientdata messages, so we only send the
134 // remaining ones here
135 static const int sendquakestats[] =
136 {
137 // quake did not send these secrets/monsters stats in this way, but doing so
138 // allows a mod to increase STAT_TOTALMONSTERS during the game, and ensures
139 // that STAT_SECRETS and STAT_MONSTERS are always correct (even if a client
140 // didn't receive an svc_foundsecret or svc_killedmonster), which may be most
141 // valuable if randomly seeking around in a demo
142 STAT_TOTALSECRETS, // never changes during game
143 STAT_TOTALMONSTERS, // changes in some mods
144 STAT_SECRETS, // this makes svc_foundsecret unnecessary
145 STAT_MONSTERS, // this makes svc_killedmonster unnecessary
146 STAT_VIEWHEIGHT, // sent just for FTEQW clients
147 STAT_VIEWZOOM, // this rarely changes
148 -1,
149 };
150
151 void Protocol_WriteStatsReliable(void)
152 {
153         int i, j;
154         if (!host_client->netconnection)
155                 return;
156         // detect changes in stats and write reliable messages
157         // this only deals with 32 stats because the older protocols which use
158         // this function can only cope with 32 stats,
159         // they also do not support svc_updatestatubyte which was introduced in
160         // DP6 protocol (except for QW)
161         for (j = 0;sendquakestats[j] >= 0;j++)
162         {
163                 i = sendquakestats[j];
164                 // check if this bit is set
165                 if (host_client->statsdeltabits[i >> 3] & (1 << (i & 7)))
166                 {
167                         host_client->statsdeltabits[i >> 3] -= (1 << (i & 7));
168                         // send the stat as a byte if possible
169                         if (sv.protocol == PROTOCOL_QUAKEWORLD)
170                         {
171                                 if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
172                                 {
173                                         MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestat);
174                                         MSG_WriteByte(&host_client->netconnection->message, i);
175                                         MSG_WriteByte(&host_client->netconnection->message, host_client->stats[i]);
176                                 }
177                                 else
178                                 {
179                                         MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestatlong);
180                                         MSG_WriteByte(&host_client->netconnection->message, i);
181                                         MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
182                                 }
183                         }
184                         else
185                         {
186                                 // this could make use of svc_updatestatubyte in DP6 and later
187                                 // protocols but those protocols do not use this function
188                                 MSG_WriteByte(&host_client->netconnection->message, svc_updatestat);
189                                 MSG_WriteByte(&host_client->netconnection->message, i);
190                                 MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
191                         }
192                 }
193         }
194 }