1 | #include "server.h" |
2 | #include "../shared/parse.h" |
3 | |
4 | |
5 | |
6 | |
7 | typedef struct mapcycle_s { |
8 | char *map; |
9 | char *type; |
10 | bool day; |
11 | struct mapcycle_s* next; |
12 | } mapcycle_t; |
13 | |
14 | static mapcycle_t *mapcycleList; |
15 | static int mapcycleCount; |
16 | |
17 | |
18 | |
19 | |
20 | void SV_NextMapcycle (void) |
21 | { |
22 | const char *map = NULL__null, *gameType = NULL__null; |
23 | bool day = true; |
24 | char *base; |
25 | char assembly[MAX_QPATH64]; |
26 | char expanded[MAX_QPATH64]; |
27 | char cmd[MAX_QPATH64]; |
28 | mapcycle_t *mapcycle; |
29 | |
30 | mapcycle = mapcycleList; |
31 | if (sv->name[0]) { |
| |
32 | int i; |
33 | Com_Printf("current map: %s\n", sv->name); |
34 | for (i = 0; i < mapcycleCount; i++) { |
| 4 | Loop condition is true. Entering loop body |
|
| 9 | Loop condition is true. Entering loop body |
|
35 | |
36 | |
37 | if (mapcycle->map[0] == '+') { |
| |
| 10 | Access to field 'map' results in a dereference of a null pointer (loaded from variable 'mapcycle') |
|
38 | Q_strncpyz(expanded, mapcycle->map, sizeof(expanded))Q_strncpyzDebug( expanded, mapcycle->map, sizeof(expanded) , "src/server/sv_mapcycle.cpp", 38 ); |
39 | base = strstr(expanded, " "); |
40 | if (base) { |
41 | base[0] = '\0'; |
42 | Q_strncpyz(assembly, base + 1, sizeof(assembly))Q_strncpyzDebug( assembly, base + 1, sizeof(assembly), "src/server/sv_mapcycle.cpp" , 42 ); |
43 | |
44 | if (Q_streq(sv->name, expanded)(strcmp(sv->name, expanded) == 0) && Q_streq(sv->assembly, assembly)(strcmp(sv->assembly, assembly) == 0)) { |
45 | |
46 | if (mapcycle->next) { |
47 | map = mapcycle->next->map; |
48 | day = mapcycle->next->day; |
49 | gameType = mapcycle->next->type; |
50 | Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType); |
51 | |
52 | } else { |
53 | map = mapcycleList->map; |
54 | day = mapcycleList->day; |
55 | gameType = mapcycleList->type; |
56 | Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType); |
57 | } |
58 | break; |
59 | } |
60 | } else { |
61 | Com_Printf("ignore mapcycle entry for random map (%s) with" |
62 | " no assembly given\n", mapcycle->map); |
63 | } |
64 | } else { |
65 | |
66 | if (Q_streq(sv->name, mapcycle->map)(strcmp(sv->name, mapcycle->map) == 0)) { |
| |
67 | |
68 | if (mapcycle->next) { |
| |
69 | map = mapcycle->next->map; |
70 | day = mapcycle->next->day; |
71 | gameType = mapcycle->next->type; |
72 | Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType); |
73 | |
74 | } else { |
75 | map = mapcycleList->map; |
76 | day = mapcycleList->day; |
77 | gameType = mapcycleList->type; |
78 | Com_DPrintf(DEBUG_SERVER0x40, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType); |
79 | } |
80 | Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map); |
81 | |
82 | |
83 | if (map[0] != '+' && FS_CheckFile("%s", expanded) < 0) { |
| |
84 | Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n" |
85 | "Use the 'maplist' command to get a list of valid maps\n", expanded); |
86 | map = NULL__null; |
87 | gameType = NULL__null; |
88 | } else |
89 | break; |
90 | } |
91 | } |
92 | mapcycle = mapcycle->next; |
93 | } |
94 | } |
95 | |
96 | if (!map) { |
97 | if (mapcycleCount > 0) { |
98 | map = mapcycleList->map; |
99 | day = mapcycleList->day; |
100 | gameType = mapcycleList->type; |
101 | if (map[0] != '+') { |
102 | Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map); |
103 | |
104 | |
105 | if (FS_CheckFile("%s", expanded) < 0) { |
106 | Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n" |
107 | "Use the 'maplist' command to get a list of valid maps\n", expanded); |
108 | return; |
109 | } |
110 | } |
111 | } else if (sv->name[0]) { |
112 | Com_Printf("No mapcycle - restart the current map (%s)\n", sv->name); |
113 | map = sv->name; |
114 | gameType = NULL__null; |
115 | } else { |
116 | Com_Printf("No mapcycle and no running map\n"); |
117 | return; |
118 | } |
119 | |
120 | if (!map) |
121 | return; |
122 | } |
123 | |
124 | |
125 | if (gameType && gameType[0] != '\0') { |
126 | Cvar_Set("sv_gametype", gameType); |
127 | Com_SetGameType(); |
128 | sv_gametype->modified = false; |
129 | } |
130 | |
131 | if (day) |
132 | Com_sprintf(cmd, sizeof(cmd), "map day %s", map); |
133 | else |
134 | Com_sprintf(cmd, sizeof(cmd), "map night %s", map); |
135 | Cbuf_AddText(cmd); |
136 | } |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | void SV_MapcycleClear (void) |
143 | { |
144 | int i; |
145 | mapcycle_t *mapcycle; |
146 | |
147 | mapcycle = mapcycleList; |
148 | for (i = 0; i < mapcycleCount; i++) { |
149 | mapcycle_t *oldMapcycle = mapcycle; |
150 | mapcycle = mapcycle->next; |
151 | Mem_Free(oldMapcycle->type)_Mem_Free((oldMapcycle->type),"src/server/sv_mapcycle.cpp" ,151); |
152 | Mem_Free(oldMapcycle->map)_Mem_Free((oldMapcycle->map),"src/server/sv_mapcycle.cpp", 152); |
153 | Mem_Free(oldMapcycle)_Mem_Free((oldMapcycle),"src/server/sv_mapcycle.cpp",153); |
154 | } |
155 | |
156 | |
157 | mapcycleList = NULL__null; |
158 | mapcycleCount = 0; |
159 | } |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | static void SV_MapcycleAdd (const char* mapName, bool day, const char* gameType) |
167 | { |
168 | mapcycle_t* const mapcycle = Mem_PoolAllocType(mapcycle_t, sv_genericPool)static_cast<mapcycle_t*>(static_cast<mapcycle_t*> (_Mem_Alloc((sizeof(mapcycle_t) * (1)),true,(((sv_genericPool ))),(0),"src/server/sv_mapcycle.cpp",168))); |
169 | mapcycle->map = Mem_PoolStrDup(mapName, sv_genericPool, 0)_Mem_PoolStrDup((mapName),(sv_genericPool),(0),"src/server/sv_mapcycle.cpp" ,169); |
170 | mapcycle->day = day; |
171 | mapcycle->type = Mem_PoolStrDup(gameType, sv_genericPool, 0)_Mem_PoolStrDup((gameType),(sv_genericPool),(0),"src/server/sv_mapcycle.cpp" ,171); |
172 | mapcycle->next = 0; |
173 | Com_DPrintf(DEBUG_SERVER0x40, "mapcycle add: '%s' type '%s'\n", mapcycle->map, mapcycle->type); |
174 | |
175 | |
176 | mapcycle_t** anchor = &mapcycleList; |
177 | while (*anchor) anchor = &(*anchor)->next; |
178 | *anchor = mapcycle; |
179 | |
180 | ++mapcycleCount; |
181 | } |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | static void SV_ParseMapcycle (void) |
189 | { |
190 | int length = 0; |
191 | byte *buffer = NULL__null; |
192 | const char *token; |
193 | const char *buf; |
194 | char map[MAX_VAR64], gameType[MAX_VAR64]; |
195 | |
196 | mapcycleCount = 0; |
197 | mapcycleList = NULL__null; |
198 | |
199 | length = FS_LoadFile("mapcycle.txt", &buffer); |
200 | if (length == -1 || !buffer) |
201 | return; |
202 | |
203 | if (length != -1) { |
204 | buf = (const char*)buffer; |
205 | do { |
206 | bool day = false; |
207 | |
208 | token = Com_Parse(&buf); |
209 | if (!buf) |
210 | break; |
211 | Q_strncpyz(map, token, sizeof(map))Q_strncpyzDebug( map, token, sizeof(map), "src/server/sv_mapcycle.cpp" , 211 ); |
212 | |
213 | token = Com_Parse(&buf); |
214 | if (!buf) |
215 | break; |
216 | if (Q_streq(token, "day")(strcmp(token, "day") == 0)) |
217 | day = true; |
218 | else if (!Q_streq(token, "night")(strcmp(token, "night") == 0)) { |
219 | Com_Printf("Skip mapcycle parsing, expected day or night."); |
220 | break; |
221 | } |
222 | |
223 | token = Com_Parse(&buf); |
224 | if (!buf) |
225 | break; |
226 | Q_strncpyz(gameType, token, sizeof(gameType))Q_strncpyzDebug( gameType, token, sizeof(gameType), "src/server/sv_mapcycle.cpp" , 226 ); |
227 | SV_MapcycleAdd(map, day, gameType); |
228 | } while (buf); |
229 | |
230 | Com_Printf("added %i maps to the mapcycle\n", mapcycleCount); |
231 | } |
232 | FS_FreeFile(buffer); |
233 | } |
234 | |
235 | static void SV_MapcycleList_f (void) |
236 | { |
237 | int i; |
238 | const mapcycle_t* mapcycle; |
239 | |
240 | mapcycle = mapcycleList; |
241 | Com_Printf("current mapcycle has %i entries\n", mapcycleCount); |
242 | for (i = 0; i < mapcycleCount; i++) { |
243 | Com_Printf(" %s (%s)\n", mapcycle->map, mapcycle->type); |
244 | mapcycle = mapcycle->next; |
245 | } |
246 | } |
247 | |
248 | static void SV_MapcycleAdd_f (void) |
249 | { |
250 | if (Cmd_Argc() == 4) { |
251 | const char *map = Cmd_Argv(1); |
252 | const char *day = Cmd_Argv(2); |
253 | const char *gametype = Cmd_Argv(3); |
254 | if (!SV_CheckMap(map, NULL__null)) { |
255 | Com_Printf("map '%s' isn't a valid map\n", map); |
256 | return; |
257 | } |
258 | Com_Printf("adding map '%s' with gametype '%s' to mapcycle (to add this permanently edit your mapcycle.txt)\n", map, gametype); |
259 | if (Q_streq(day, "day")(strcmp(day, "day") == 0)) |
260 | SV_MapcycleAdd(map, true, gametype); |
261 | else |
262 | SV_MapcycleAdd(map, false, gametype); |
263 | } else { |
264 | Com_Printf("Usage: %s <mapname> <day|night> <gametype>\n", Cmd_Argv(0)); |
265 | Com_Printf(" ...to get a list of valid maps type 'maplist'\n" |
266 | " ...to get a list of valid gametypes 'gametypelist'\n"); |
267 | } |
268 | } |
269 | |
270 | static void SV_MapcycleNext_f (void) |
271 | { |
272 | if (mapcycleCount > 0) |
| |
273 | SV_NextMapcycle(); |
| 2 | Calling 'SV_NextMapcycle' |
|
274 | else |
275 | Com_Printf("no mapcycle.txt\n"); |
276 | } |
277 | |
278 | void SV_MapcycleInit (void) |
279 | { |
280 | SV_ParseMapcycle(); |
281 | |
282 | Cmd_AddCommand("mapcyclelist", SV_MapcycleList_f, "Print the current mapcycle"); |
283 | Cmd_AddCommand("mapcyclenext", SV_MapcycleNext_f, "Start the next map from the cycle"); |
284 | Cmd_AddCommand("mapcycleclear", SV_MapcycleClear, "Delete the current mapcycle"); |
285 | Cmd_AddCommand("mapcycleadd", SV_MapcycleAdd_f, "Add new maps to the mapcycle"); |
286 | } |