1 #define NOMINMAX
2 #include <windows.h>
3 #include <cstring>
4 #include "xr_file_system.h"
5 #include "xr_ini_file.h"
6 #include "xr_string_utils.h"
7 #include "xr_cl_parser.h"
8 #include "xr_log.h"
9 #include "aiwrapper.h"
10 #include "syncer.h"
11 
12 using namespace xray_re;
13 
usage()14 const void usage()
15 {
16 	printf("X-Ray AI compiler wrapper (%s)\n", BUILD_DATE);
17 	printf("Vendor: ZENOBIAN mod team\n");
18 	printf("Usage: aiwrapper <options>\n\n");
19 	printf("xrAI derived options:\n");
20 	printf(" -h or -?	this help\n");
21 	printf(" -verify <NAME>	verify AI map in gamedata\\levels\\<NAME>\\\n");
22 	printf(" -f <NAME>	build AI map in gamedata\\levels\\<NAME>\\\n");
23 	printf(" -g <NAME>	build off-line AI graph and cross-table to AI map in gamedata\\levels\\<NAME>\\\n");
24 	printf(" -m		merge level graphs\n");
25 	printf(" -s		build game spawn data\n");
26 	printf(" -draft		build draft AI map\n\n");
27 	printf("Custom options:\n");
28 	printf(" -fs <SPEC>	use <SPEC> as file system specification file (default is %s)\n", DEFAULT_FS_SPEC);
29 	printf(" -fast_sync	update just older files in shadow xrAI tree\n");
30 	printf(" -split_spawns	restore level.spawn files from all.spawn/game.graph\n");
31 	printf(" -split_paths	restore level.game files from all.spawn\n");
32 	printf(" -split_graphs	restore level.graph files from all.spawn/game.graph\n");
33 	printf(" -check_paths	check walk paths in all.spawn\n");
34 	printf(" -upgrade <BLD>	convert levels into CS (3502) or CoP (3870) format\n\n");
35 	printf("Deprecated options:\n");
36 	printf(" -m2 <FILE>	adjust level graphs according to <FILE> and merge them\n");
37 	printf(" -dump_gp	dump list of graph points in all level.spawn files\n");
38 //	printf(" -use_orig_gp	read graph points from original level.spawn\n");
39 }
40 
run_xrai(const char * opt,const char * arg=0)41 static void run_xrai(const char* opt, const char* arg = 0)
42 {
43 	xr_file_system& fs = xr_file_system::instance();
44 	const char* root = fs.resolve_path(PA2215_FS_ROOT);
45 	char cmd[2*MAX_PATH];
46 	xr_snprintf(cmd, sizeof(cmd), "%sxrAI.exe %s%s%s", root, opt, arg ? " " : "", arg ? arg : "");
47 	STARTUPINFOA si = {0};
48 	si.cb = sizeof(si);
49 	PROCESS_INFORMATION pi = {0};
50 	msg("launching '%s'", cmd + std::strlen(root));
51 	BOOL success = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, root, &si, &pi);
52 	if (!success)
53 		throw syncer::sync_error();
54 	WaitForSingleObject(pi.hProcess, INFINITE);
55 	CloseHandle(pi.hProcess);
56 	CloseHandle(pi.hThread);
57 }
58 
main(int argc,char * argv[])59 int main(int argc, char* argv[])
60 {
61 	static const cl_parser::option_desc options[] = {
62 		{"-h",			cl_parser::OT_BOOL},
63 		{"-?",			cl_parser::OT_BOOL},
64 		{"-verify",		cl_parser::OT_STRING},
65 		{"-f",			cl_parser::OT_STRING},
66 		{"-g",			cl_parser::OT_STRING},
67 		{"-m",			cl_parser::OT_BOOL},
68 		{"-s",			cl_parser::OT_BOOL},
69 		{"-draft",		cl_parser::OT_BOOL},
70 		{"-fs",			cl_parser::OT_STRING},
71 		{"-fast_sync",		cl_parser::OT_BOOL},
72 		{"-split_spawns",	cl_parser::OT_BOOL},
73 		{"-split_paths",	cl_parser::OT_BOOL},
74 		{"-split_graphs",	cl_parser::OT_BOOL},
75 		{"-check_paths",	cl_parser::OT_BOOL},
76 		{"-upgrade",		cl_parser::OT_INTEGER},
77 		{"-m2",			cl_parser::OT_STRING},
78 		{"-dump_gp",		cl_parser::OT_BOOL},
79 		{"-use_orig_dp",	cl_parser::OT_BOOL},
80 	};
81 	cl_parser cl;
82 	if (!cl.parse(argc, argv, xr_dim(options), options) || cl.num_params() != 0) {
83 		usage();
84 		return 1;
85 	}
86 	if (cl.get_bool("-h") || cl.get_bool("-?") || cl.num_options() == 0) {
87 		usage();
88 		return 0;
89 	}
90 
91 	const char* fs_spec;
92 	if (!cl.get_string("-fs", fs_spec))
93 		fs_spec = DEFAULT_FS_SPEC;
94 	if (!xr_file_system::file_exist(fs_spec)) {
95 		msg("can't find %s", fs_spec);
96 		return 1;
97 	}
98 	xr_file_system& fs = xr_file_system::instance();
99 	if (!fs.initialize(fs_spec, 0)) {
100 		msg("can't initialize the file system");
101 		return 1;
102 	}
103 	xr_log::instance().init("aiwrapper");
104 
105 	try {
106 		syncer sync;
107 		sync.check_fs_paths();
108 		sync.load_ini("aiwrapper.ini");
109 		unsigned force = cl.get_bool("-fast_sync") ? 0 : SYNC_FORCE;
110 		const char* name;
111 		int bld_ver;
112 		if (cl.get_string("-f", name)) {
113 			sync.to_xrai(name, SYNC_BUILD_AIMAP|SYNC_BUILD_CFORM|SYNC_BUILD_PRJ|force);
114 			run_xrai((cl.get_bool("-draft") ? "-draft -f" : "-f"), name);
115 			sync.from_xrai(name, SYNC_LEVEL_AI|SYNC_FORCE);
116 		} else if (cl.get_string("-verify", name)) {
117 			sync.to_xrai(name, SYNC_LEVEL_AI|force);
118 			run_xrai("-verify", name);
119 		} else if (cl.get_string("-g", name)) {
120 			sync.to_xrai(name, SYNC_LEVEL_AI|SYNC_LEVEL_SECTORS_AI|SYNC_LEVEL_SPAWN|force);
121 			run_xrai("-g", name);
122 			sync.from_xrai(name, SYNC_LEVEL_GRAPH|SYNC_LEVEL_GCT_RAW|SYNC_LEVEL_SECTORS_AI|SYNC_FORCE);
123 		} else if (cl.get_bool("-m")) {
124 			sync.to_xrai(SYNC_GAME_LTX|SYNC_LEVEL_AI|SYNC_LEVEL_GCT_RAW|SYNC_LEVEL_GRAPH|SYNC_LEVEL_SPAWN|force);
125 			run_xrai("-m");
126 			sync.from_xrai(SYNC_GAME_GRAPH|SYNC_LEVEL_GCT|SYNC_LEVEL_GCT_RAW|SYNC_FORCE);
127 		} else if (cl.get_bool("-s")) {
128 			sync.to_xrai(SYNC_GAME_LTX|SYNC_GAME_GRAPH|SYNC_LEVEL_AI|SYNC_LEVEL_SECTORS_AI|
129 					SYNC_LEVEL_GRAPH|SYNC_LEVEL_GCT|SYNC_LEVEL_GCT_RAW|SYNC_LEVEL_SPAWN|force);
130 			run_xrai("-s");
131 			sync.from_xrai(SYNC_GAME_SPAWN|SYNC_LEVEL_SECTORS_AI|SYNC_FORCE);
132 		} else if (cl.get_bool("-split_spawns")) {
133 			sync.split_spawns(cl.get_bool("-use_orig_gp"));
134 		} else if (cl.get_bool("-split_paths")) {
135 			sync.split_paths();
136 		} else if (cl.get_bool("-split_graphs")) {
137 			sync.split_graphs();
138 		} else if (cl.get_bool("-check_paths")) {
139 			sync.check_paths();
140 		} else if (cl.get_integer("-upgrade", bld_ver)) {
141 			sync.upgrade(bld_ver);
142 		} else if (cl.get_string("-m2", name)) {
143 			sync.load_links_ini(name);
144 			sync.to_xrai(SYNC_GAME_LTX|SYNC_LEVEL_AI|SYNC_LEVEL_GCT_RAW|SYNC_LEVEL_GRAPH|SYNC_LEVEL_SPAWN|force);
145 			run_xrai("-m");
146 			sync.from_xrai(SYNC_GAME_GRAPH|SYNC_LEVEL_GCT|SYNC_LEVEL_GCT_RAW|SYNC_FORCE);
147 		} else if (cl.get_bool("-dump_gp")) {
148 			sync.dump_links("links.output");
149 		} else {
150 			usage();
151 		}
152 	} catch (syncer::sync_error) {
153 		msg("ERROR occured! Aborting.");
154 	}
155 	return 0;
156 }
157