1 #include <algorithm>
2 #include <cstring>
3 #include <cctype>
4 #include "xr_entity.h"
5 #include "xr_ini_file.h"
6 #include "xr_level_spawn.h"
7 #include "xr_entity_factory.h"
8 #include "xr_file_system.h"
9 #include "syncer.h"
10 
11 using namespace xray_re;
12 
to_xrai_compat(xr_level_spawn & spawn,const xr_ini_file & ini,const char * section)13 void syncer::to_xrai_compat(xr_level_spawn& spawn, const xr_ini_file& ini, const char* section)
14 {
15 	for (xr_entity_vec_it it = spawn.spawns().begin(), end = spawn.spawns().end(); it != end; ++it) {
16 		cse_abstract* entity = *it;
17 		char clsid[9];
18 		entity->clsid().get(clsid);
19 		if (ini.line_exist(section, clsid))
20 			entity->name() = ini.r_string(section, clsid);
21 		entity->version() = CSE_VERSION_2215;
22 		entity->script_version() = 2;
23 	}
24 }
25 
skip_ws(const char * p)26 static inline const char* skip_ws(const char* p)
27 {
28 	for (int c; (c = *p) && (c == ' ' || c == '\t'); ++p) {}
29 	return p;
30 }
31 
skip_name(const char * p)32 static inline const char* skip_name(const char* p)
33 {
34 	for (int c; (c = *p); ++p) {
35 		if (!std::isalnum(c) && c != '_')
36 			break;
37 	}
38 	return p;
39 }
40 
split_link(const char * link_spec,std::string & level_name,std::string & point_name)41 static inline bool split_link(const char* link_spec, std::string& level_name, std::string& point_name)
42 {
43 	const char* p = skip_name(link_spec);
44 	if (p == link_spec) {
45 		// to delete links
46 		level_name.clear();
47 		point_name.clear();
48 		return true;
49 	}
50 	level_name.assign(link_spec, p);
51 	p = skip_ws(p);
52 	if (*p++ != ',')
53 		return false;
54 	p = skip_name(link_spec = skip_ws(p));
55 	if (p == link_spec)
56 		return false;
57 	point_name.assign(link_spec, p);
58 	return true;
59 }
60 
edit_links(xr_level_spawn & spawn,const xr_ini_file & ini,const char * section)61 void syncer::edit_links(xr_level_spawn& spawn, const xr_ini_file& ini, const char* section)
62 {
63 	if (!ini.section_exist(section))
64 		return;
65 
66 	std::string level_name, point_name;
67 	for (xr_entity_vec_it it = spawn.spawns().begin(), end = spawn.spawns().end();
68 			it != end; ++it) {
69 		cse_alife_graph_point* gp = dynamic_cast<cse_alife_graph_point*>(*it);
70 		if (gp == 0)
71 			continue;
72 		const char* name = gp->name_replace().c_str();
73 		if (!ini.line_exist(section, name))
74 			continue;
75 		const char* link_spec = ini.r_string(section, name);
76 		if (split_link(link_spec, level_name, point_name)) {
77 			gp->connection_level() = level_name;
78 			gp->connection_point() = point_name;
79 		} else {
80 			msg("can't parse link fixup for %s:%s", section, name);
81 		}
82 	}
83 }
84 
operator ()graph_point_pred85 struct graph_point_pred { bool operator()(const cse_abstract* l, const cse_abstract* r) const {
86 	const cse_alife_graph_point* gp1 = dynamic_cast<const cse_alife_graph_point*>(l);
87 	const cse_alife_graph_point* gp2 = dynamic_cast<const cse_alife_graph_point*>(r);
88 	if (gp1 == 0)
89 		return gp2 == 0 ? false : true;
90 	else if (gp2 == 0)
91 		return false;
92 	int cmp = gp2->connection_level().compare(gp1->connection_level());
93 	if (cmp)
94 		return cmp < 0;
95 	const fvector3& p1 = l->position();
96 	const fvector3& p2 = r->position();
97 	return p1.x < p2.x || (p1.x == p2.x && (p1.z < p2.z || (p1.z == p2.z && p1.y < p2.y)));
98 }};
99 
dump_links(xr_level_spawn & spawn,xr_writer & w,const char * section)100 void syncer::dump_links(xr_level_spawn& spawn, xr_writer& w, const char* section)
101 {
102 	std::sort(spawn.spawns().begin(), spawn.spawns().end(), graph_point_pred());
103 	w.w_sf("[%s]\n", section);
104 	for (xr_entity_vec_it it = spawn.spawns().begin(), end = spawn.spawns().end(); it != end; ++it) {
105 		cse_alife_graph_point* gp = dynamic_cast<cse_alife_graph_point*>(*it);
106 		if (gp == 0)
107 			continue;
108 		w.w_sf("%-32s= ", gp->name_replace().c_str());
109 		if (!gp->connection_level().empty()) {
110 			w.w_sf("%s", gp->connection_level().c_str());
111 			if (!gp->connection_point().empty())
112 				w.w_sf(", %s", gp->connection_point().c_str());
113 			w.w_sf("\t");
114 		}
115 		const fvector3& p = gp->position();
116 		w.w_sf("; %7.2f %7.2f %7.2f\n", p.x, p.y, p.z);
117 	}
118 	w.w_sf("\n");
119 }
120 
load_graph_points(xr_level_spawn & spawn,const char * path,const char * name) const121 bool syncer::load_graph_points(xr_level_spawn& spawn, const char* path, const char* name) const
122 {
123 	xr_file_system& fs = xr_file_system::instance();
124 	xr_reader* r = fs.r_open(path, name);
125 	if (r == 0)
126 		return false;
127 	xr_reader* s;
128 	for (uint32_t id = 0; (s = r->open_chunk(id)); ++id) {
129 		xr_packet packet;
130 		s->r_packet(packet, s->size());
131 		uint16_t pkt_id;
132 		packet.r_begin(pkt_id);
133 		xr_assert(pkt_id == M_SPAWN);
134 		const char* name = packet.skip_sz();
135 #if 1
136 		packet.r_seek(0);
137 		cse_abstract* entity = create_entity(name);
138 		if (entity && entity->clsid() == "AI_GRAPH") {
139 			entity->spawn_read(packet);
140 			entity->version() = CSE_VERSION_SOC;
141 			entity->script_version() = 6;
142 			spawn.spawns().push_back(entity);
143 		} else {
144 			delete entity;
145 		}
146 #else
147 		if (std::strcmp(name, "graph_point") == 0) {
148 			packet.r_seek(0);
149 			cse_abstract* entity = create_entity(name);
150 			xr_assert(entity);
151 			entity->spawn_read(packet);
152 			entity->version() = CSE_VERSION_SOC;
153 			entity->script_version() = 6;
154 			spawn.spawns().push_back(entity);
155 		}
156 #endif
157 		r->close_chunk(s);
158 	}
159 	fs.r_close(r);
160 	return true;
161 }
162