8 #include <inttypes.h> |
8 #include <inttypes.h> |
9 #include <stdlib.h> |
9 #include <stdlib.h> |
10 |
10 |
11 int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) { |
11 int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) { |
12 int result = -1; |
12 int result = -1; |
13 if(!vec || !fmt) { |
13 if(!log_badparams_if(!vec || !fmt)) { |
14 flib_log_e("null parameter in flib_ipc_appendmessage"); |
|
15 } else { |
|
16 // 1 byte size prefix, 255 bytes max message length, 1 0-byte for vsnprintf |
14 // 1 byte size prefix, 255 bytes max message length, 1 0-byte for vsnprintf |
17 char msgbuffer[257]; |
15 char msgbuffer[257]; |
18 |
16 |
19 // Format the message, leaving one byte at the start for the length |
17 // Format the message, leaving one byte at the start for the length |
20 va_list argp; |
18 va_list argp; |
21 va_start(argp, fmt); |
19 va_start(argp, fmt); |
22 int msgSize = vsnprintf(msgbuffer+1, 256, fmt, argp); |
20 int msgSize = vsnprintf(msgbuffer+1, 256, fmt, argp); |
23 va_end(argp); |
21 va_end(argp); |
24 |
22 |
25 if(msgSize > 255) { |
23 if(!log_e_if(msgSize > 255, "Message too long (%u bytes)", (unsigned)msgSize) |
26 flib_log_e("Message too long (%u bytes) in flib_ipc_appendmessage", (unsigned)msgSize); |
24 && !log_e_if(msgSize < 0, "printf error")) { |
27 } else if(msgSize<0) { |
|
28 flib_log_e("printf error in flib_ipc_appendmessage"); |
|
29 } else { |
|
30 // Add the length prefix |
25 // Add the length prefix |
31 ((uint8_t*)msgbuffer)[0] = msgSize; |
26 ((uint8_t*)msgbuffer)[0] = msgSize; |
32 |
27 |
33 // Append it to the vector |
28 // Append it to the vector |
34 if(flib_vector_append(vec, msgbuffer, msgSize+1) == msgSize+1) { |
29 result = flib_vector_append(vec, msgbuffer, msgSize+1); |
35 result = 0; |
|
36 } |
|
37 } |
30 } |
38 } |
31 } |
39 return result; |
32 return result; |
40 } |
33 } |
41 |
34 |
42 int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) { |
35 int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) { |
43 int result = -1; |
36 int result = -1; |
44 flib_vector *tempvector = flib_vector_create(); |
37 flib_vector *tempvector = flib_vector_create(); |
45 if(!vec || !map) { |
38 if(!log_badparams_if(!vec || !map)) { |
46 flib_log_e("null parameter in flib_ipc_append_mapconf"); |
|
47 } else if(tempvector) { |
|
48 bool error = false; |
39 bool error = false; |
49 |
40 |
50 if(map->mapgen == MAPGEN_NAMED) { |
41 if(map->mapgen == MAPGEN_NAMED) { |
51 if(map->name) { |
42 error |= log_e_if(!map->name, "Missing map name") |
52 error |= flib_ipc_append_message(tempvector, "emap %s", map->name); |
43 || flib_ipc_append_message(tempvector, "emap %s", map->name); |
53 } else { |
44 } |
54 flib_log_e("Missing map name"); |
45 if(!mappreview) { |
55 error = true; |
46 error |= log_e_if(!map->theme, "Missing map theme") |
56 } |
47 || flib_ipc_append_message(tempvector, "etheme %s", map->theme); |
57 } |
|
58 if(map->theme && !mappreview) { |
|
59 if(map->theme) { |
|
60 error |= flib_ipc_append_message(tempvector, "etheme %s", map->theme); |
|
61 } else { |
|
62 flib_log_e("Missing map theme"); |
|
63 error = true; |
|
64 } |
|
65 } |
48 } |
66 error |= flib_ipc_append_seed(tempvector, map->seed); |
49 error |= flib_ipc_append_seed(tempvector, map->seed); |
67 error |= flib_ipc_append_message(tempvector, "e$template_filter %i", map->templateFilter); |
50 error |= flib_ipc_append_message(tempvector, "e$template_filter %i", map->templateFilter); |
68 error |= flib_ipc_append_message(tempvector, "e$mapgen %i", map->mapgen); |
51 error |= flib_ipc_append_message(tempvector, "e$mapgen %i", map->mapgen); |
69 |
52 |
79 int edrawlen = strlen(edraw); |
62 int edrawlen = strlen(edraw); |
80 for(int offset=0; offset<map->drawDataSize; offset+=200) { |
63 for(int offset=0; offset<map->drawDataSize; offset+=200) { |
81 int bytesRemaining = map->drawDataSize-offset; |
64 int bytesRemaining = map->drawDataSize-offset; |
82 int fragmentsize = bytesRemaining < 200 ? bytesRemaining : 200; |
65 int fragmentsize = bytesRemaining < 200 ? bytesRemaining : 200; |
83 uint8_t messagesize = edrawlen + fragmentsize; |
66 uint8_t messagesize = edrawlen + fragmentsize; |
84 error |= (flib_vector_append(tempvector, &messagesize, 1) != 1); |
67 error |= flib_vector_append(tempvector, &messagesize, 1); |
85 error |= (flib_vector_append(tempvector, edraw, edrawlen) != edrawlen); |
68 error |= flib_vector_append(tempvector, edraw, edrawlen); |
86 error |= (flib_vector_append(tempvector, map->drawData+offset, fragmentsize) != fragmentsize); |
69 error |= flib_vector_append(tempvector, map->drawData+offset, fragmentsize); |
|
70 } |
|
71 } |
|
72 |
|
73 if(!log_e_if(error, "Error generating map config")) { |
|
74 // Message created, now we can copy everything. |
|
75 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
|
76 if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { |
|
77 result = 0; |
|
78 } |
|
79 } |
|
80 } |
|
81 flib_vector_destroy(tempvector); |
|
82 return result; |
|
83 } |
|
84 |
|
85 int flib_ipc_append_seed(flib_vector *vec, const char *seed) { |
|
86 if(!log_badparams_if(!vec || !seed)) { |
|
87 return flib_ipc_append_message(vec, "eseed %s", seed); |
|
88 } |
|
89 return -1; |
|
90 } |
|
91 |
|
92 int flib_ipc_append_script(flib_vector *vec, const char *script) { |
|
93 int result = -1; |
|
94 char *copy = flib_strdupnull(script); |
|
95 if(!log_badparams_if(!vec) && copy) { |
|
96 if(!strcmp("Normal", copy)) { |
|
97 // "Normal" means no gametype script |
|
98 result = 0; |
|
99 } else { |
|
100 size_t len = strlen(copy); |
|
101 for(size_t i=0; i<len; i++) { |
|
102 if(copy[i] == ' ') { |
|
103 copy[i] = '_'; |
|
104 } |
|
105 } |
|
106 |
|
107 result = flib_ipc_append_message(vec, "escript %s%s.lua", MULTIPLAYER_SCRIPT_PATH, copy); |
|
108 } |
|
109 } |
|
110 free(copy); |
|
111 return result; |
|
112 } |
|
113 |
|
114 uint32_t buildModFlags(const flib_cfg *scheme) { |
|
115 uint32_t result = 0; |
|
116 for(int i=0; i<scheme->meta->modCount; i++) { |
|
117 if(scheme->mods[i]) { |
|
118 int bitmaskIndex = scheme->meta->mods[i].bitmaskIndex; |
|
119 result |= (UINT32_C(1) << bitmaskIndex); |
|
120 } |
|
121 } |
|
122 return result; |
|
123 } |
|
124 |
|
125 int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *scheme) { |
|
126 int result = -1; |
|
127 flib_vector *tempvector = flib_vector_create(); |
|
128 if(!log_badparams_if(!vec || !scheme) && tempvector) { |
|
129 const flib_cfg_meta *meta = scheme->meta; |
|
130 bool error = false; |
|
131 error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, buildModFlags(scheme)); |
|
132 for(int i=0; i<meta->settingCount; i++) { |
|
133 if(meta->settings[i].engineCommand) { |
|
134 int value = scheme->settings[i]; |
|
135 if(meta->settings[i].maxMeansInfinity) { |
|
136 value = value>=meta->settings[i].max ? 9999 : value; |
|
137 } |
|
138 if(meta->settings[i].times1000) { |
|
139 value *= 1000; |
|
140 } |
|
141 error |= flib_ipc_append_message(tempvector, "%s %i", meta->settings[i].engineCommand, value); |
87 } |
142 } |
88 } |
143 } |
89 |
144 |
90 if(!error) { |
145 if(!error) { |
91 // Message created, now we can copy everything. |
146 // Message created, now we can copy everything. |
92 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
147 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
93 if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { |
148 if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { |
94 result = 0; |
|
95 } |
|
96 } |
|
97 } |
|
98 flib_vector_destroy(tempvector); |
|
99 return result; |
|
100 } |
|
101 |
|
102 int flib_ipc_append_seed(flib_vector *vec, const char *seed) { |
|
103 if(!vec || !seed) { |
|
104 flib_log_e("null parameter in flib_ipc_append_seed"); |
|
105 return -1; |
|
106 } else { |
|
107 return flib_ipc_append_message(vec, "eseed %s", seed); |
|
108 } |
|
109 } |
|
110 |
|
111 int flib_ipc_append_script(flib_vector *vec, const char *script) { |
|
112 if(!vec || !script) { |
|
113 flib_log_e("null parameter in flib_ipc_append_script"); |
|
114 return -1; |
|
115 } else { |
|
116 return flib_ipc_append_message(vec, "escript %s", script); |
|
117 } |
|
118 } |
|
119 |
|
120 int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *scheme) { |
|
121 int result = -1; |
|
122 flib_vector *tempvector = flib_vector_create(); |
|
123 if(!vec || !scheme) { |
|
124 flib_log_e("null parameter in flib_ipc_append_gamescheme"); |
|
125 } else if(tempvector) { |
|
126 const flib_cfg_meta *meta = scheme->meta; |
|
127 bool error = false; |
|
128 uint32_t gamemods = 0; |
|
129 for(int i=0; i<meta->modCount; i++) { |
|
130 if(scheme->mods[i]) { |
|
131 gamemods |= (1<<meta->mods[i].bitmaskIndex); |
|
132 } |
|
133 } |
|
134 error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, gamemods); |
|
135 for(int i=0; i<meta->settingCount; i++) { |
|
136 int value = scheme->settings[i]; |
|
137 if(meta->settings[i].maxMeansInfinity) { |
|
138 value = value>=meta->settings[i].max ? 9999 : value; |
|
139 } |
|
140 if(meta->settings[i].times1000) { |
|
141 value *= 1000; |
|
142 } |
|
143 error |= flib_ipc_append_message(tempvector, "%s %i", meta->settings[i].engineCommand, value); |
|
144 } |
|
145 |
|
146 if(!error) { |
|
147 // Message created, now we can copy everything. |
|
148 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
|
149 if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { |
|
150 result = 0; |
149 result = 0; |
151 } |
150 } |
152 } |
151 } |
153 } |
152 } |
154 flib_vector_destroy(tempvector); |
153 flib_vector_destroy(tempvector); |
163 } |
162 } |
164 |
163 |
165 int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) { |
164 int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) { |
166 int result = -1; |
165 int result = -1; |
167 flib_vector *tempvector = flib_vector_create(); |
166 flib_vector *tempvector = flib_vector_create(); |
168 if(!vec || !team) { |
167 if(!log_badparams_if(!vec || !team) && tempvector) { |
169 flib_log_e("invalid parameter in flib_ipc_append_addteam"); |
|
170 } else if(tempvector) { |
|
171 bool error = false; |
168 bool error = false; |
172 |
169 |
173 if(!perHogAmmo && !noAmmoStore) { |
170 if(!perHogAmmo && !noAmmoStore) { |
174 error |= appendWeaponSet(tempvector, team->hogs[0].weaponset); |
171 error = error |
175 error |= flib_ipc_append_message(tempvector, "eammstore"); |
172 || appendWeaponSet(tempvector, team->hogs[0].weaponset) |
|
173 || flib_ipc_append_message(tempvector, "eammstore"); |
176 } |
174 } |
177 |
175 |
178 // TODO |
176 // TODO |
179 char *hash = team->ownerName ? team->ownerName : "00000000000000000000000000000000"; |
177 char *hash = team->ownerName ? team->ownerName : "00000000000000000000000000000000"; |
180 error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", hash, team->color, team->name); |
178 if(team->colorIndex<0 || team->colorIndex>=flib_teamcolor_defaults_len) { |
|
179 flib_log_e("Color index out of bounds for team %s: %i", team->name, team->colorIndex); |
|
180 error = true; |
|
181 } else { |
|
182 error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", hash, flib_teamcolor_defaults[team->colorIndex], team->name); |
|
183 } |
181 |
184 |
182 if(team->remoteDriven) { |
185 if(team->remoteDriven) { |
183 error |= flib_ipc_append_message(tempvector, "erdriven"); |
186 error |= flib_ipc_append_message(tempvector, "erdriven"); |
184 } |
187 } |
185 |
188 |
201 } |
204 } |
202 |
205 |
203 if(!error) { |
206 if(!error) { |
204 // Message created, now we can copy everything. |
207 // Message created, now we can copy everything. |
205 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
208 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
206 if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { |
209 if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { |
207 result = 0; |
210 result = 0; |
208 } |
211 } |
209 } |
212 } |
210 } |
213 } |
211 flib_vector_destroy(tempvector); |
214 flib_vector_destroy(tempvector); |
212 return result; |
215 return result; |
213 } |
216 } |
214 |
217 |
215 static bool getGameMod(const flib_cfg *conf, int maskbit) { |
218 static bool getGameMod(const flib_cfg *conf, const char *name) { |
216 for(int i=0; i<conf->meta->modCount; i++) { |
219 for(int i=0; i<conf->meta->modCount; i++) { |
217 if(conf->meta->mods[i].bitmaskIndex == maskbit) { |
220 if(!strcmp(conf->meta->mods[i].name, name)) { |
218 return conf->mods[i]; |
221 return conf->mods[i]; |
219 } |
222 } |
220 } |
223 } |
221 flib_log_e("Unable to find game mod with mask bit %i", maskbit); |
224 flib_log_e("Unable to find game mod %s", name); |
222 return false; |
225 return false; |
223 } |
226 } |
224 |
227 |
225 int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) { |
228 int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) { |
226 int result = -1; |
229 int result = -1; |
227 flib_vector *tempvector = flib_vector_create(); |
230 flib_vector *tempvector = flib_vector_create(); |
228 if(!vec || !setup) { |
231 if(!log_badparams_if(!vec || !setup) && tempvector) { |
229 flib_log_e("null parameter in flib_ipc_append_fullconfig"); |
|
230 } else if(tempvector) { |
|
231 bool error = false; |
232 bool error = false; |
232 bool perHogAmmo = false; |
233 bool perHogAmmo = false; |
233 bool sharedAmmo = false; |
234 bool sharedAmmo = false; |
234 |
235 |
235 error |= flib_ipc_append_message(vec, netgame ? "TN" : "TL"); |
236 error |= flib_ipc_append_message(vec, netgame ? "TN" : "TL"); |
236 if(setup->map) { |
237 if(setup->map) { |
237 error |= flib_ipc_append_mapconf(tempvector, setup->map, false); |
238 error |= flib_ipc_append_mapconf(tempvector, setup->map, false); |
238 } |
239 } |
239 if(setup->script) { |
240 if(setup->script) { |
240 error |= flib_ipc_append_message(tempvector, "escript %s", setup->script); |
241 error |= flib_ipc_append_script(tempvector, setup->script); |
241 } |
242 } |
242 if(setup->gamescheme) { |
243 if(setup->gamescheme) { |
243 error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme); |
244 error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme); |
244 sharedAmmo = getGameMod(setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT); |
245 sharedAmmo = getGameMod(setup->gamescheme, "sharedammo"); |
245 // Shared ammo has priority over per-hog ammo |
246 // Shared ammo has priority over per-hog ammo |
246 perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT); |
247 perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, "perhogammo"); |
247 } |
248 } |
248 if(setup->teams && setup->teamCount>0) { |
249 if(setup->teamlist->teams && setup->teamlist->teamCount>0) { |
249 uint32_t *clanColors = flib_calloc(setup->teamCount, sizeof(uint32_t)); |
250 int *clanColors = flib_calloc(setup->teamlist->teamCount, sizeof(int)); |
250 if(!clanColors) { |
251 if(!clanColors) { |
251 error = true; |
252 error = true; |
252 } else { |
253 } else { |
253 int clanCount = 0; |
254 int clanCount = 0; |
254 for(int i=0; i<setup->teamCount; i++) { |
255 for(int i=0; !error && i<setup->teamlist->teamCount; i++) { |
255 flib_team *team = setup->teams[i]; |
256 flib_team *team = setup->teamlist->teams[i]; |
|
257 // Find the clan index of this team (clans are identified by color). |
256 bool newClan = false; |
258 bool newClan = false; |
257 |
|
258 // Find the clan index of this team (clans are identified by color). |
|
259 // The upper 8 bits (alpha) are ignored in the engine as well. |
|
260 uint32_t color = team->color&UINT32_C(0x00ffffff); |
|
261 int clan = 0; |
259 int clan = 0; |
262 while(clan<clanCount && clanColors[clan] != color) { |
260 while(clan<clanCount && clanColors[clan] != team->colorIndex) { |
263 clan++; |
261 clan++; |
264 } |
262 } |
265 if(clan==clanCount) { |
263 if(clan==clanCount) { |
266 newClan = true; |
264 newClan = true; |
267 clanCount++; |
265 clanCount++; |
268 clanColors[clan] = color; |
266 clanColors[clan] = team->colorIndex; |
269 } |
267 } |
270 |
268 |
271 // If shared ammo is active, only add an ammo store for the first team in each clan. |
269 // If shared ammo is active, only add an ammo store for the first team in each clan. |
272 bool noAmmoStore = sharedAmmo&&!newClan; |
270 bool noAmmoStore = sharedAmmo&&!newClan; |
273 error |= flib_ipc_append_addteam(tempvector, setup->teams[i], perHogAmmo, noAmmoStore); |
271 error |= flib_ipc_append_addteam(tempvector, setup->teamlist->teams[i], perHogAmmo, noAmmoStore); |
274 } |
272 } |
275 } |
273 } |
276 free(clanColors); |
274 free(clanColors); |
277 } |
275 } |
278 error |= flib_ipc_append_message(tempvector, "!"); |
276 error |= flib_ipc_append_message(tempvector, "!"); |
279 |
277 |
280 if(!error) { |
278 if(!error) { |
281 // Message created, now we can copy everything. |
279 // Message created, now we can copy everything. |
282 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
280 flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); |
283 if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { |
281 if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { |
284 result = 0; |
282 result = 0; |
285 } |
283 } |
286 } |
284 } |
287 } |
285 } |
288 return result; |
286 return result; |
289 } |
287 } |