1 #include "xr_ai_version.h"
2 #include "xr_level_game.h"
3 #include "xr_level_graph.h"
4 #include "xr_level_spawn.h"
5 #include "xr_level_gct.h"
6 #include "xr_level_ai.h"
7 #include "xr_level_env_mod.h"
8 #include "xr_level_ps_static.h"
9 #include "xr_game_spawn.h"
10 #include "xr_game_graph.h"
11 #include "xr_utils.h"
12 #include "xr_entity_factory.h"
13 #include "xr_file_system.h"
14 #include "xr_string_utils.h"
15 #include "syncer.h"
16
17 using namespace xray_re;
18
scan_levels()19 void syncer::scan_levels()
20 {
21 if (m_scan_done)
22 return;
23
24 msg("loading %s", "game_levels.ltx");
25 if (!m_levels_ini.load(PA_GAME_CONFIG, "game_levels.ltx")) {
26 msg("can't load game_levels.ltx");
27 throw sync_error();
28 }
29 m_num_levels = m_levels_ini.line_count("levels");
30 for (size_t i = 0; i != m_num_levels; ++i) {
31 const char* section;
32 m_levels_ini.r_line("levels", i, §ion, 0);
33 if (!m_levels_ini.line_exist(section, "name")) {
34 msg("can't read level name in section %s", section);
35 throw sync_error();
36 }
37 }
38 m_scan_done = true;
39 }
40
level_name(size_t level_idx) const41 const char* syncer::level_name(size_t level_idx) const
42 {
43 const char* section;
44 m_levels_ini.r_line("levels", level_idx, §ion, 0);
45 return m_levels_ini.r_string(section, "name");
46 }
47
check_or_create_fs_path(const char * path,bool & status,bool may_create=false)48 static void check_or_create_fs_path(const char* path, bool& status, bool may_create = false)
49 {
50 xr_file_system& fs = xr_file_system::instance();
51 if (!fs.folder_exist(path, "")) {
52 if (may_create && status) {
53 if (fs.create_folder(path, ""))
54 return;
55 msg("can't create path %s", path);
56 } else {
57 msg("path %s does not exist", path);
58 }
59 status = false;
60 }
61 }
62
check_fs_paths() const63 void syncer::check_fs_paths() const
64 {
65 bool status = true;
66 check_or_create_fs_path(PA_GAME_DATA, status);
67 check_or_create_fs_path(PA_GAME_CONFIG, status);
68 check_or_create_fs_path(PA_GAME_SPAWN, status);
69 check_or_create_fs_path(PA_GAME_LEVELS, status);
70 check_or_create_fs_path(PA2215_FS_ROOT, status);
71 check_or_create_fs_path(PA2215_GAME_DATA, status, true);
72 check_or_create_fs_path(PA2215_GAME_CONFIG, status, true);
73 check_or_create_fs_path(PA2215_GAME_SPAWN, status, true);
74 check_or_create_fs_path(PA2215_GAME_LEVELS, status, true);
75 if (!status)
76 throw sync_error();
77 }
78
load_ini(const char * name)79 void syncer::load_ini(const char* name)
80 {
81 msg("loading %s", name);
82 if (!m_ini.load(name) && !m_ini.load(PA_SDK_ROOT, name))
83 throw sync_error();
84 }
85
load_links_ini(const char * name)86 void syncer::load_links_ini(const char* name)
87 {
88 msg("loading %s", name);
89 if (!m_links_ini.load(name))
90 throw sync_error();
91 }
92
split_spawns(bool use_orig_gp) const93 void syncer::split_spawns(bool use_orig_gp) const
94 {
95 xr_game_spawn gspawn;
96 msg("loading %s\\%s", PA_GAME_SPAWN, "all.spawn");
97 if (!gspawn.load(PA_GAME_SPAWN, "all.spawn"))
98 throw sync_error();
99
100 msg("loading %s\\%s", PA_GAME_DATA, "game.graph");
101 if (!gspawn.graph().load(PA_GAME_DATA, "game.graph"))
102 throw sync_error();
103
104 xr_level_spawn* by_level_id[256];
105 std::uninitialized_fill_n(by_level_id, xr_dim(by_level_id), static_cast<xr_level_spawn*>(0));
106
107 xr_file_system& fs = xr_file_system::instance();
108
109 msg("collecting %s", "graph points");
110 for (const gg_level *it = gspawn.graph().levels(),
111 *end = it + gspawn.graph().num_levels(); it != end; ++it) {
112 const char* name = it->name.c_str();
113 if (!fs.folder_exist(PA_GAME_LEVELS, name))
114 continue;
115
116 xr_level_spawn* spawn = by_level_id[it->level_id];
117 if (spawn == 0)
118 by_level_id[it->level_id] = spawn = new xr_level_spawn;
119
120 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
121 #if 0
122 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.spawn");
123 if (!load_graph_points(*spawn, PA_LEVEL, "level.spawn"))
124 throw sync_error();
125 #else
126 bool make_aiw_bak = true;
127 const char* level_spawn_name = "level.spawn";
128 if (fs.file_exist(PA_LEVEL, "level.spawn.aiw_bak")) {
129 level_spawn_name = "level.spawn.aiw_bak";
130 make_aiw_bak = false;
131 }
132 if (make_aiw_bak) {
133 msg("making %s\\%s\\%s", PA_GAME_LEVELS, name, "level.spawn.aiw_bak");
134 if (!fs.copy_file(PA_LEVEL, "level.spawn", PA_LEVEL, "level.spawn.aiw_bak"))
135 throw sync_error();
136 }
137 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, level_spawn_name);
138 if (!load_graph_points(*spawn, PA_LEVEL, level_spawn_name))
139 throw sync_error();
140 #endif
141 }
142
143 msg("sorting %s", "spawns");
144 if (!split_spawns(gspawn, by_level_id))
145 throw sync_error();
146
147 for (const gg_level *it = gspawn.graph().levels(),
148 *end = it + gspawn.graph().num_levels(); it != end; ++it) {
149 const char* name = it->name.c_str();
150 if (!fs.folder_exist(PA_GAME_LEVELS, name))
151 continue;
152 for (const gg_level *it1 = gspawn.graph().levels(),
153 *end1 = it1 + gspawn.graph().num_levels();
154 it1 != end1; ++it1) {
155 if (_stricmp(it1->name.c_str(), name) == 0) {
156 xr_assert(it1->level_id < xr_dim(by_level_id));
157 xr_level_spawn* spawn = by_level_id[it1->level_id];
158 xr_assert(spawn);
159 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
160 msg("saving %s\\%s\\%s", PA_GAME_LEVELS, name, "level.spawn");
161 if (!spawn->save(PA_LEVEL, "level.spawn"))
162 throw sync_error();
163 break;
164 }
165 }
166 }
167 delete_elements(by_level_id, xr_dim(by_level_id));
168 }
169
split_paths() const170 void syncer::split_paths() const
171 {
172 xr_game_spawn gspawn;
173 msg("loading %s\\%s", PA_GAME_SPAWN, "all.spawn");
174 if (!gspawn.load(PA_GAME_SPAWN, "all.spawn"))
175 throw sync_error();
176
177 msg("loading %s\\%s", PA_GAME_DATA, "game.graph");
178 if (!gspawn.load_graph(PA_GAME_DATA, "game.graph"))
179 throw sync_error();
180
181 xr_level_game* by_level_id[256];
182 std::uninitialized_fill_n(by_level_id, xr_dim(by_level_id), static_cast<xr_level_game*>(0));
183
184 xr_file_system& fs = xr_file_system::instance();
185
186 msg("collecting %s", "$rpoints");
187 for (const gg_level *it = gspawn.graph().levels(),
188 *end = it + gspawn.graph().num_levels(); it != end; ++it) {
189 const char* name = it->name.c_str();
190 if (!fs.folder_exist(PA_GAME_LEVELS, name))
191 continue;
192
193 xr_level_game* game = by_level_id[it->level_id];
194 if (game == 0)
195 by_level_id[it->level_id] = game = new xr_level_game;
196
197 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
198 #if 0
199 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.game");
200 if (!load_mp_rpoints(*game, PA_LEVEL, "level.game"))
201 throw sync_error();
202 #else
203 bool make_aiw_bak = true;
204 const char* level_game_name = "level.game";
205 if (fs.file_exist(PA_LEVEL, "level.game.aiw_bak")) {
206 level_game_name = "level.game.aiw_bak";
207 make_aiw_bak = false;
208 }
209 if (make_aiw_bak) {
210 msg("making %s\\%s\\%s", PA_GAME_LEVELS, name, "level.game.aiw_bak");
211 if (!fs.copy_file(PA_LEVEL, "level.game", PA_LEVEL, "level.game.aiw_bak"))
212 throw sync_error();
213 }
214 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, level_game_name);
215 if (!load_mp_rpoints(*game, PA_LEVEL, level_game_name))
216 throw sync_error();
217 #endif
218 }
219
220 msg("sorting %s", "paths");
221 if (!split_paths(gspawn, by_level_id, m_ini))
222 throw sync_error();
223
224 for (const gg_level *it = gspawn.graph().levels(),
225 *end = it + gspawn.graph().num_levels(); it != end; ++it) {
226 const char* name = it->name.c_str();
227 if (!fs.folder_exist(PA_GAME_LEVELS, name))
228 continue;
229 for (const gg_level *it1 = gspawn.graph().levels(),
230 *end1 = it1 + gspawn.graph().num_levels();
231 it1 != end1; ++it1) {
232 if (_stricmp(it1->name.c_str(), name) == 0) {
233 xr_assert(it1->level_id < xr_dim(by_level_id));
234 xr_level_game* game = by_level_id[it1->level_id];
235 xr_assert(game);
236 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
237 msg("saving %s\\%s\\%s", PA_GAME_LEVELS, name, "level.game");
238 if (!game->save(PA_LEVEL, "level.game"))
239 throw sync_error();
240 break;
241 }
242 }
243 }
244 delete_elements(by_level_id, xr_dim(by_level_id));
245 }
246
check_paths() const247 void syncer::check_paths() const
248 {
249 xr_game_spawn gspawn;
250 msg("loading %s\\%s", PA_GAME_SPAWN, "all.spawn");
251 if (!gspawn.load(PA_GAME_SPAWN, "all.spawn"))
252 throw sync_error();
253
254 check_paths(gspawn);
255 }
256
split_graphs()257 void syncer::split_graphs()
258 {
259 msg("not yet implemented");
260 }
261
dump_links(const char * path)262 void syncer::dump_links(const char* path)
263 {
264 scan_levels();
265
266 xr_file_system& fs = xr_file_system::instance();
267 xr_writer* w = fs.w_open(path);
268 if (w == 0)
269 throw sync_error();
270 for (size_t i = 0; i != m_num_levels; ++i) {
271 const char* name = level_name(i);
272 if (!fs.folder_exist(PA_GAME_LEVELS, name))
273 continue;
274 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
275 if (!fs.file_exist(PA_LEVEL, "level.spawn"))
276 continue;
277 xr_level_spawn spawn;
278 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.spawn");
279 if (!spawn.load(PA_LEVEL, "level.spawn"))
280 throw sync_error();
281 dump_links(spawn, *w, name);
282 }
283 fs.w_close(w);
284 }
285
upgrade(int bld_ver)286 void syncer::upgrade(int bld_ver)
287 {
288 #if 0
289 if (0) {
290 xr_game_spawn gspawn;
291 msg("loading %s\\%s", PA_GAME_SPAWN, "all.spawn.orig");
292 if (!gspawn.load(PA_GAME_SPAWN, "all.spawn.orig"))
293 throw sync_error();
294 msg("saving %s\\%s", PA_GAME_SPAWN, "all.spawn.out");
295 if (!gspawn.save(PA_GAME_SPAWN, "all.spawn.out"))
296 throw sync_error();
297 } else {
298 bool status = true;
299 check_or_create_fs_path(PA9_FS_ROOT, status);
300 check_or_create_fs_path(PA9_GAME_DATA, status);
301 check_or_create_fs_path(PA9_GAME_CONFIG, status);
302 check_or_create_fs_path(PA9_GAME_SPAWN, status);
303 if (!status)
304 throw sync_error();
305 load_system_ini(PA9_GAME_CONFIG);
306 xr_game_spawn gspawn;
307 msg("loading %s\\%s", PA9_GAME_SPAWN, "marsh.spawn");
308 if (!gspawn.load(PA9_GAME_SPAWN, "marsh.spawn"))
309 throw sync_error();
310 msg("saving %s\\%s", PA9_GAME_SPAWN, "marsh.spawn.out");
311 if (!gspawn.save(PA9_GAME_SPAWN, "marsh.spawn.out"))
312 throw sync_error();
313 }
314 return;
315 #endif
316
317 uint32_t new_ai_version;
318 if (bld_ver == 3120) {
319 new_ai_version = AI_VERSION_9;
320 } else if (bld_ver >= 3502) {
321 new_ai_version = AI_VERSION_10;
322 } else {
323 msg("unsupported version");
324 throw sync_error();
325 }
326
327 bool status = true;
328 check_or_create_fs_path(PA9_FS_ROOT, status);
329 check_or_create_fs_path(PA9_GAME_DATA, status, true);
330 check_or_create_fs_path(PA9_GAME_SPAWN, status, true);
331 check_or_create_fs_path(PA9_GAME_LEVELS, status, true);
332
333 check_or_create_fs_path(PA10_FS_ROOT, status);
334 check_or_create_fs_path(PA10_GAME_DATA, status, true);
335 check_or_create_fs_path(PA10_GAME_SPAWN, status, true);
336 check_or_create_fs_path(PA10_GAME_LEVELS, status, true);
337
338 if (!status)
339 throw sync_error();
340
341 xr_game_spawn gspawn;
342 msg("loading %s\\%s", PA_GAME_SPAWN, "all.spawn");
343 if (!gspawn.load(PA_GAME_SPAWN, "all.spawn"))
344 throw sync_error();
345 msg("loading %s\\%s", PA_GAME_DATA, "game.graph");
346 if (!gspawn.load_graph(PA_GAME_DATA, "game.graph"))
347 throw sync_error();
348 gspawn.graph().version() = gspawn.version() = new_ai_version;
349
350 if (bld_ver >= 3502) {
351 msg("upgrading spawn version");
352 char *PA_UPG_GAME_SPAWN = NULL;
353 char *PA_UPG_GAME_LEVELS = NULL;
354 char *PA_UPG_LEVEL = NULL;
355
356 if (bld_ver >= 3870) {
357 load_system_ini(PA10_GAME_CONFIG);
358 PA_UPG_GAME_LEVELS = (char *)PA10_GAME_LEVELS;
359 PA_UPG_LEVEL = (char *)PA10_LEVEL;
360 PA_UPG_GAME_SPAWN = (char *)PA10_GAME_SPAWN;
361 msg("upgrading spawn version to CoP format");
362 xr_entity_vec* gs = new xr_entity_vec;
363 int i = 0;
364 for (xr_entity_vec_it it = gspawn.spawns().begin(),
365 end = gspawn.spawns().end(); it != end; ++it) {
366 cse_abstract* entity = *it;
367
368 if (get_entity_clsid(entity->name()) != &entity->clsid())
369 {
370 cse_abstract* new_entity = create_entity(entity->name());
371 xr_packet packet;
372
373 entity->spawn_write(packet, true);
374 new_entity->spawn_read(packet);
375
376 packet.clear();
377 entity->update_write(packet);
378 new_entity->update_read(packet);
379
380 new_entity->version() = CSE_VERSION_COP;
381 new_entity->script_version() = 12;
382 new_entity->spawn_id() = i++;
383
384 gs->push_back(new_entity);
385 }
386 else
387 {
388 entity->version() = CSE_VERSION_COP;
389 entity->script_version() = 12;
390 entity->spawn_id() = i++;
391
392 gs->push_back(entity);
393 }
394 }
395 gspawn.spawns() = *gs;
396 }
397 else if (bld_ver >= 3502) {
398 load_system_ini(PA9_GAME_CONFIG);
399 PA_UPG_GAME_LEVELS = (char *)PA9_GAME_LEVELS;
400 PA_UPG_LEVEL = (char *)PA9_LEVEL;
401 PA_UPG_GAME_SPAWN = (char *)PA9_GAME_SPAWN;
402 msg("upgrading spawn version to CS format");
403 xr_entity_vec* gs = new xr_entity_vec;
404 int i = 0;
405 for (xr_entity_vec_it it = gspawn.spawns().begin(),
406 end = gspawn.spawns().end(); it != end; ++it) {
407 cse_abstract* entity = *it;
408 entity->version() = CSE_VERSION_CS;
409 entity->script_version() = 8;
410 }
411 }
412
413 xr_file_system& fs = xr_file_system::instance();
414 for (const gg_level *it = gspawn.graph().levels(),
415 *end = it + gspawn.graph().num_levels(); it != end; ++it) {
416 const char* name = it->name.c_str();
417
418 if (!fs.folder_exist(PA_GAME_LEVELS, name))
419 continue;
420
421 if (!fs.folder_exist(PA_UPG_GAME_LEVELS, name)) {
422 msg("creating %s\\%s\\", PA_UPG_GAME_LEVELS, name);
423 if (!fs.create_folder(PA_UPG_GAME_LEVELS, name))
424 throw sync_error();
425 }
426
427 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
428 fs.update_path(PA_UPG_LEVEL, PA_UPG_GAME_LEVELS, name);
429
430 xr_level_ai ai;
431 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.ai");
432 if (!ai.load(PA_LEVEL, "level.ai"))
433 throw sync_error();
434 ai.version() = new_ai_version;
435 msg("saving %s\\%s\\%s", PA_UPG_GAME_LEVELS, name, "level.ai");
436 if (!ai.save(PA_UPG_LEVEL, "level.ai"))
437 throw sync_error();
438
439 xr_level_gct gct;
440 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.gct");
441 if (!gct.load(PA_LEVEL, "level.gct"))
442 throw sync_error();
443 msg("embedding cross table");
444 if (!import_cross_table(gspawn, gct))
445 throw sync_error();
446
447 if (bld_ver >= 3456) {
448 xr_level_env_mod env_mod;
449 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.env_mod");
450 if (env_mod.load(PA_LEVEL, "level.env_mod")) {
451 env_mod.version() = ENV_MOD_VERSION_23;
452 msg("saving %s\\%s\\%s", PA_UPG_GAME_LEVELS, name, "level.env_mod");
453 if (!env_mod.save(PA_UPG_LEVEL, "level.env_mod"))
454 throw sync_error();
455 }
456
457 xr_level_ps_static ps_static;
458 msg("loading %s\\%s\\%s", PA_GAME_LEVELS, name, "level.ps_static");
459 if (ps_static.load(PA_LEVEL, "level.ps_static")) {
460 ps_static.version() = PS_VERSION_1;
461 msg("saving %s\\%s\\%s", PA_UPG_GAME_LEVELS, name, "level.ps_static");
462 if (!ps_static.save(PA_UPG_LEVEL, "level.ps_static"))
463 throw sync_error();
464 }
465 }
466 }
467 // msg("moving actor to military");
468 // move_actor(gspawn.spawns(), -334.578491210938f, -25.5103607177734f, 45.0102348327637f, 16231, 1546);
469 msg("saving %s\\%s", PA_UPG_GAME_SPAWN, "all.spawn");
470 if (!gspawn.save(PA_UPG_GAME_SPAWN, "all.spawn"))
471 throw sync_error();
472 }
473 }
474
sync_build_aimap()475 void syncer::sync_build_aimap()
476 {
477 if (up_to_date(m_src_level, "build.aimap", m_tgt_level)) {
478 msg("%s\\%s is up to date", m_tgt_level_path, "build.aimap");
479 } else {
480 msg("updating %s\\%s", m_tgt_level_path, "build.aimap");
481 xr_file_system& fs = xr_file_system::instance();
482 if (!fs.copy_file(m_src_level, "build.aimap", m_tgt_level))
483 throw sync_error();
484 }
485 }
486
sync_build_cform()487 void syncer::sync_build_cform()
488 {
489 if (up_to_date(m_src_level, "build.cform", m_tgt_level)) {
490 msg("%s\\%s is up to date", m_tgt_level_path, "build.cform");
491 } else {
492 msg("updating %s\\%s", m_tgt_level_path, "build.cform");
493 xr_file_system& fs = xr_file_system::instance();
494 if (!fs.copy_file(m_src_level, "build.cform", m_tgt_level))
495 throw sync_error();
496 }
497 }
498
sync_build_prj()499 void syncer::sync_build_prj()
500 {
501 if (up_to_date(m_src_level, "build.prj", m_tgt_level)) {
502 msg("%s\\%s is up to date", m_tgt_level_path, "build.prj");
503 } else {
504 msg("updating %s\\%s", m_tgt_level_path, "build.prj");
505 xr_file_system& fs = xr_file_system::instance();
506 if (!fs.copy_file(m_src_level, "build.prj", m_tgt_level))
507 throw sync_error();
508 }
509 }
510
sync_level_ai()511 void syncer::sync_level_ai()
512 {
513 if (up_to_date(m_src_level, "level.ai", m_tgt_level)) {
514 msg("%s\\%s is up to date", m_tgt_level_path, "level.ai");
515 } else {
516 msg("updating %s\\%s", m_tgt_level_path, "level.ai");
517 xr_file_system& fs = xr_file_system::instance();
518 if (!fs.copy_file(m_src_level, "level.ai", m_tgt_level))
519 throw sync_error();
520 }
521 }
522
sync_level_gct()523 void syncer::sync_level_gct()
524 {
525 if (up_to_date(m_src_level, "level.gct", m_tgt_level)) {
526 msg("%s\\%s is up to date", m_tgt_level_path, "level.gct");
527 } else {
528 msg("updating %s\\%s", m_tgt_level_path, "level.gct");
529 xr_file_system& fs = xr_file_system::instance();
530 fs.copy_file(m_src_level, "level.gct", m_tgt_level);
531 }
532 }
533
sync_level_gct_raw()534 void syncer::sync_level_gct_raw()
535 {
536 xr_file_system& fs = xr_file_system::instance();
537 bool rebuild = !m_xrai_compat && !fs.file_exist(m_src_level, "level.gct.raw");
538 if (up_to_date(m_src_level, rebuild ? "level.gct" : "level.gct.raw", m_tgt_level, "level.gct.raw")) {
539 msg("%s\\%s is up to date", m_tgt_level_path, "level.gct.raw");
540 return;
541 }
542 if (rebuild) {
543 msg("rebuilding %s\\%s", m_tgt_level_path, "level.gct.raw");
544 xr_level_gct gct;
545 if (!gct.load(m_src_level, "level.gct"))
546 throw sync_error();
547 to_raw(gct);
548 if (!gct.save(m_tgt_level, "level.gct.raw"))
549 throw sync_error();
550 } else {
551 msg("updating %s\\%s", m_tgt_level_path, "level.gct.raw");
552 fs.copy_file(m_src_level, "level.gct.raw", m_tgt_level);
553 }
554 }
555
sync_level_graph()556 void syncer::sync_level_graph()
557 {
558 if (up_to_date(m_src_level, "level.graph", m_tgt_level)) {
559 msg("%s\\%s is up to date", m_tgt_level_path, "level.graph");
560 } else {
561 msg("updating %s\\%s", m_tgt_level_path, "level.graph");
562 xr_level_graph graph;
563 if (!graph.load(m_src_level, "level.graph"))
564 throw sync_error();
565 graph.version() = m_xrai_compat ? AI_VERSION_8 : AI_VERSION_2215;
566 if (!graph.save(m_tgt_level, "level.graph"))
567 throw sync_error();
568 }
569 }
570
sync_level_spawn(const char * name)571 void syncer::sync_level_spawn(const char* name)
572 {
573 xr_assert(!m_xrai_compat);
574 if (m_links_ini.empty() && up_to_date(PA_LEVEL, "level.spawn", PA2215_LEVEL)) {
575 msg("%s\\%s is up to date", m_tgt_level_path, "level.spawn");
576 } else {
577 msg("updating %s\\%s", m_tgt_level_path, "level.spawn");
578 xr_level_spawn spawn;
579 if (!spawn.load(PA_LEVEL, "level.spawn"))
580 throw sync_error();
581 edit_links(spawn, m_links_ini, name);
582 to_xrai_compat(spawn, m_ini, "entity_compat");
583 if (!spawn.save(PA2215_LEVEL, "level.spawn"))
584 throw sync_error();
585 }
586 }
587
sync_level_sectors_ai()588 void syncer::sync_level_sectors_ai()
589 {
590 if (up_to_date(m_src_level, "level_sectors.ai", m_tgt_level)) {
591 msg("%s\\%s is up to date", m_tgt_level_path, "level_sectors.ai");
592 } else {
593 msg("updating %s\\%s", m_tgt_level_path, "level_sectors.ai");
594 xr_file_system& fs = xr_file_system::instance();
595 fs.copy_file(m_src_level, "level_sectors.ai", m_tgt_level);
596 }
597 }
598
sync_game_ltx(const char * name)599 void syncer::sync_game_ltx(const char* name)
600 {
601 xr_assert(!m_xrai_compat);
602 if (up_to_date(PA_GAME_CONFIG, name, PA2215_GAME_CONFIG)) {
603 msg("%s\\%s is up to date", PA2215_GAME_CONFIG, name);
604 } else {
605 msg("updating %s\\%s", PA2215_GAME_CONFIG, name);
606 xr_file_system& fs = xr_file_system::instance();
607 fs.copy_file(PA_GAME_CONFIG, name, PA2215_GAME_CONFIG);
608 }
609 }
610
sync_game_graph()611 void syncer::sync_game_graph()
612 {
613 if (up_to_date(m_src_game_data, "game.graph", m_tgt_game_data)) {
614 msg("%s\\%s is up to date", m_tgt_game_data, "game.graph");
615 } else {
616 msg("updating %s\\%s", m_tgt_game_data, "game.graph");
617 xr_game_graph graph;
618 if (!graph.load(m_src_game_data, "game.graph"))
619 throw sync_error();
620 graph.version() = m_xrai_compat ? AI_VERSION_8 : AI_VERSION_2215;
621 if (!graph.save(m_tgt_game_data, "game.graph"))
622 throw sync_error();
623 }
624 }
625
sync_game_spawn()626 void syncer::sync_game_spawn()
627 {
628 xr_assert(m_xrai_compat);
629 m_actor_level = 0;
630 xr_game_spawn gspawn;
631 xr_file_system& fs = xr_file_system::instance();
632 for (size_t i = 0; i != m_num_levels; ++i) {
633 const char* name = level_name(i);
634 if (!fs.folder_exist(PA_GAME_LEVELS, name))
635 continue;
636
637 fs.update_path(PA_LEVEL, PA_GAME_LEVELS, name);
638 if (!fs.file_exist(PA_LEVEL, "level.spawn") ||
639 !fs.file_exist(PA_LEVEL, "level.game")) {
640 continue;
641 }
642
643 update_tgt_level_path(name);
644
645 xr_level_spawn spawn;
646 msg("loading %s\\%s", m_tgt_level_path, "level.spawn");
647 if (!spawn.load(PA_LEVEL, "level.spawn"))
648 throw sync_error();
649
650 xr_level_game game;
651 msg("loading %s\\%s", m_tgt_level_path, "level.game");
652 if (!game.load(PA_LEVEL, "level.game"))
653 throw sync_error();
654
655 xr_level_ai ai;
656 msg("loading %s\\%s", m_tgt_level_path, "level.ai");
657 if (!ai.load(PA_LEVEL, "level.ai"))
658 throw sync_error();
659
660 xr_level_gct gct;
661 msg("loading %s\\%s", m_tgt_level_path, "level.gct");
662 if (!gct.load(PA_LEVEL, "level.gct"))
663 throw sync_error();
664
665 msg("adding %s to game spawn", name);
666 if (!add_level(gspawn, name, spawn, game, ai, gct))
667 throw sync_error();
668 }
669 if (m_actor_level == 0) {
670 msg("can't find %s", "actor");
671 throw sync_error();
672 }
673 char gs2215[256];
674 xr_snprintf(gs2215, sizeof(gs2215), "%s.spawn", m_actor_level);
675 if (up_to_date(PA2215_GAME_SPAWN, gs2215, PA_GAME_SPAWN, "all.spawn")) {
676 msg("%s\\%s is up to date", PA_GAME_SPAWN, "all.spawn");
677 return;
678 }
679 msg("merging xrAI-generated %s\\%s", PA2215_GAME_SPAWN, gs2215);
680 if (!merge_xrai_compat(gspawn, PA2215_GAME_SPAWN, gs2215))
681 throw sync_error();
682
683 msg("saving %s\\%s", PA_GAME_DATA, "all.spawn");
684 gspawn.graph().version() = gspawn.version() = AI_VERSION_8;
685 if (!gspawn.save(PA_GAME_SPAWN, "all.spawn"))
686 throw sync_error();
687 }
688
up_to_date(const char * src_path,const char * src_name,const char * tgt_path,const char * tgt_name)689 bool syncer::up_to_date(const char* src_path, const char* src_name,
690 const char* tgt_path, const char* tgt_name)
691 {
692 if (m_flags & SYNC_FORCE)
693 return false;
694 if (tgt_name == 0)
695 tgt_name = src_name;
696 xr_file_system& fs = xr_file_system::instance();
697 uint32_t src_age = fs.file_age(src_path, src_name);
698 uint32_t tgt_age = fs.file_age(tgt_path, tgt_name);
699 return src_age <= tgt_age;
700 }
701
set_target(sync_target target,unsigned flags)702 void syncer::set_target(sync_target target, unsigned flags)
703 {
704 m_flags = flags;
705 if (target == SYNC_TARGET_FINAL) {
706 m_xrai_compat = true;
707 m_src_game_data = PA2215_GAME_DATA;
708 m_src_game_spawn = PA2215_GAME_SPAWN;
709 m_src_game_levels = PA2215_GAME_LEVELS;
710 m_src_level = PA2215_LEVEL;
711 m_tgt_game_data = PA_GAME_DATA;
712 m_tgt_game_spawn = PA_GAME_SPAWN;
713 m_tgt_game_levels = PA_GAME_LEVELS;
714 m_tgt_level = PA_LEVEL;
715 } else {
716 m_xrai_compat = false;
717 m_src_game_data = PA_GAME_DATA;
718 m_src_game_spawn = PA_GAME_SPAWN;
719 m_src_game_levels = PA_GAME_LEVELS;
720 m_src_level = PA_LEVEL;
721 m_tgt_game_data = PA2215_GAME_DATA;
722 m_tgt_game_spawn = PA2215_GAME_SPAWN;
723 m_tgt_game_levels = PA2215_GAME_LEVELS;
724 m_tgt_level = PA2215_LEVEL;
725 }
726 }
727
update_tgt_level_path(const char * name)728 void syncer::update_tgt_level_path(const char* name)
729 {
730 xr_snprintf(m_tgt_level_path, sizeof(m_tgt_level_path),
731 "%s\\%s", m_tgt_game_levels, name);
732 }
733
do_sync(const char * name)734 void syncer::do_sync(const char* name)
735 {
736 xr_file_system& fs = xr_file_system::instance();
737 if (!fs.folder_exist(m_src_game_levels, name))
738 return;
739 if (!fs.folder_exist(m_tgt_game_levels, name)) {
740 msg("creating %s\\%s\\", m_tgt_game_levels, name);
741 if (!fs.create_folder(m_tgt_game_levels, name))
742 throw sync_error();
743 }
744 update_tgt_level_path(name);
745 fs.update_path(m_src_level, m_src_game_levels, name);
746 fs.update_path(m_tgt_level, m_tgt_game_levels, name);
747 if (m_flags & SYNC_BUILD_AIMAP)
748 sync_build_aimap();
749 if (m_flags & SYNC_BUILD_CFORM)
750 sync_build_cform();
751 if (m_flags & SYNC_BUILD_PRJ)
752 sync_build_prj();
753 if (m_flags & SYNC_LEVEL_AI)
754 sync_level_ai();
755 if (m_flags & SYNC_LEVEL_GCT)
756 sync_level_gct();
757 if (m_flags & SYNC_LEVEL_GCT_RAW)
758 sync_level_gct_raw();
759 if (m_flags & SYNC_LEVEL_GRAPH)
760 sync_level_graph();
761 if (m_flags & SYNC_LEVEL_SPAWN)
762 sync_level_spawn(name);
763 if (m_flags & SYNC_LEVEL_SECTORS_AI)
764 sync_level_sectors_ai();
765 }
766
do_sync()767 void syncer::do_sync()
768 {
769 if (m_flags & SYNC_GAME_GRAPH)
770 sync_game_graph();
771 if (m_flags & SYNC_GAME_SPAWN)
772 sync_game_spawn();
773 if (m_flags & SYNC_LEVEL) {
774 scan_levels();
775 for (size_t i = 0; i != m_num_levels; ++i)
776 do_sync(level_name(i));
777 if (m_flags & SYNC_GAME_LTX) {
778 sync_game_ltx("game_graphs.ltx");
779 sync_game_ltx("game_levels.ltx");
780 sync_game_ltx("game_story_ids.ltx");
781 }
782 }
783 }
784
to_xrai(unsigned flags)785 void syncer::to_xrai(unsigned flags)
786 {
787 set_target(SYNC_TARGET_XRAI, flags|SYNC_GAME_LTX);
788 do_sync();
789 }
790
from_xrai(unsigned flags)791 void syncer::from_xrai(unsigned flags)
792 {
793 set_target(SYNC_TARGET_FINAL, flags);
794 do_sync();
795 }
796
to_xrai(const char * name,unsigned flags)797 void syncer::to_xrai(const char* name, unsigned flags)
798 {
799 set_target(SYNC_TARGET_XRAI, flags|SYNC_GAME_LTX);
800 do_sync(name);
801 }
802
from_xrai(const char * name,unsigned flags)803 void syncer::from_xrai(const char* name, unsigned flags)
804 {
805 set_target(SYNC_TARGET_FINAL, flags);
806 do_sync(name);
807 }
808