1 // Copyright 2015-2017 the openage authors. See copying.md for legal info.
2 
3 #pragma once
4 
5 #include "../job/job.h"
6 #include "../gamedata/gamedata.gen.h"
7 #include "../gamedata/graphic.gen.h"
8 #include "../terrain/terrain.h"
9 #include "../unit/unit_texture.h"
10 #include "../util/csv.h"
11 
12 #include <unordered_map>
13 #include <memory>
14 #include <QObject>
15 
16 
17 namespace openage {
18 
19 class AssetManager;
20 class GameSpec;
21 class UnitType;
22 class UnitTypeMeta;
23 class Player;
24 
25 
26 /**
27  * the key type mapped to data objects
28  */
29 using index_t = int;
30 
31 
32 /**
33  * could use unique ptr
34  */
35 using unit_type_list = std::vector<std::shared_ptr<UnitType>>;
36 using unit_meta_list = std::vector<std::shared_ptr<UnitTypeMeta>>;
37 
38 
39 /**
40  * simple sound object
41  * TODO: move to assetmanager
42  */
43 class Sound {
44 public:
Sound(GameSpec * spec,std::vector<int> && sound_items)45 	Sound(GameSpec *spec, std::vector<int> &&sound_items)
46 		:
47 		sound_items{sound_items},
48 		game_spec{spec} {}
49 
50 	void play() const;
51 
52 	std::vector<int> sound_items;
53 
54 	GameSpec *game_spec;
55 };
56 
57 
58 /**
59  * GameSpec gives a collection of all game elements
60  * this currently includes unit types and terrain types
61  * This provides a system which can easily allow game modding
62  *
63  * uses the AssetManager to gather
64  * graphic data, composite textures and sounds.
65  *
66  * all types are sorted and stored by id values,
67  * each data object is referenced by a type and id pair
68  *
69  * dealing directly with files done by asset manager
70  * TODO: should the audio loading should be moved there?
71  */
72 class GameSpec {
73 public:
74 	GameSpec(AssetManager *am);
75 	virtual ~GameSpec();
76 
77 	/**
78 	 * perform the main loading job.
79 	 * this loads all the data into the storage.
80 	 */
81 	bool initialize();
82 
83 	/**
84 	 * Check if loading has been completed,
85 	 * a load percent would be nice
86 	 */
87 	bool load_complete() const;
88 
89 	/**
90 	 * return data used for constructing terrain objects
91 	 */
92 	terrain_meta *get_terrain_meta();
93 
94 	/**
95 	 * reverse lookup of slp
96 	 */
97 	index_t get_slp_graphic(index_t slp);
98 
99 	/**
100 	 * lookup using a texture id, this specifically avoids returning the missing placeholder texture
101 	 */
102 	Texture *get_texture(index_t graphic_id) const;
103 
104 	/**
105 	 * lookup using a texture file name
106 	 */
107 	Texture *get_texture(const std::string &file_name, bool use_metafile=true) const;
108 
109 	/**
110 	 * get unit texture by graphic id -- this is an directional texture
111 	 * which also includes graphic deltas
112 	 */
113 	std::shared_ptr<UnitTexture> get_unit_texture(index_t graphic_id) const;
114 
115 	/**
116 	 * get sound by sound id
117 	 */
118 	const Sound *get_sound(index_t sound_id) const;
119 
120 	/**
121 	 * gamedata for a graphic
122 	 * nyan will have to replace this somehow
123 	 */
124 	const gamedata::graphic *get_graphic_data(index_t grp_id) const;
125 
126 	/**
127 	 * get available commands for a unit id
128 	 * nyan will have to replace this somehow
129 	 */
130 	std::vector<const gamedata::unit_command *> get_command_data(index_t unit_id) const;
131 
132 	/**
133 	 * returns the name of a civ by index
134 	 */
135 	std::string get_civ_name(int civ_id) const;
136 
137 	/**
138 	 * makes initial unit types for a particular civ id
139 	 */
140 	void create_unit_types(unit_meta_list &objects, int civ_id) const;
141 
142 	/**
143 	 * Return the asset manager used for loading resources
144 	 * of this game specification.
145 	 */
146 	AssetManager *get_asset_manager() const;
147 
148 private:
149 	/**
150 	 * check graphic id is valid
151 	 */
152 	bool valid_graphic_id(index_t) const;
153 
154 	/**
155 	 * create unit abilities from game data
156 	 */
157 	void create_abilities(const gamedata::empiresdat &gamedata);
158 
159 	/**
160 	 * loads required assets to construct a buildings.
161 	 * adds to the type list if the object can be created safely.
162 	 */
163 	void load_building(const gamedata::building_unit &, unit_meta_list &) const;
164 
165 	/**
166 	 * loads assets for living things.
167 	 */
168 	void load_living(const gamedata::living_unit &, unit_meta_list &) const;
169 
170 	/**
171 	 * load assets for other game objects (not building and living).
172 	 */
173 	void load_object(const gamedata::unit_object &, unit_meta_list &) const;
174 
175 	/**
176 	 * load missile assets.
177 	 */
178 	void load_missile(const gamedata::missile_unit &, unit_meta_list &) const;
179 
180 	/**
181 	 * fill in the terrain_data attribute of this
182 	 */
183 	void load_terrain(const gamedata::empiresdat &gamedata);
184 
185 	/**
186 	 * Invoked when the gamedata has been loaded.
187 	 */
188 	void on_gamedata_loaded(const gamedata::empiresdat &gamedata);
189 
190 	/**
191 	 * Asset management entity that is responsible for textures, sounds, etc.
192 	 */
193 	AssetManager *assetmanager;
194 
195 	/**
196 	 * The full original gamedata tree.
197 	 */
198 	std::vector<gamedata::empiresdat> gamedata;
199 
200 	/**
201 	 * data used for constructing terrain objects
202 	 */
203 	terrain_meta terrain_data;
204 
205 	/**
206 	 * slp to graphic id reverse lookup
207 	 */
208 	std::unordered_map<index_t, index_t> slp_to_graphic;
209 
210 	/**
211 	 * map graphic id to gamedata graphic.
212 	 */
213 	std::unordered_map<index_t, const gamedata::graphic *> graphics;
214 
215 	/**
216 	 * commands available for each unit id
217 	 */
218 	std::unordered_map<index_t, std::vector<const gamedata::unit_command *>> commands;
219 
220 	/**
221 	 * graphic ids -> unit texture for that id
222 	 */
223 	std::unordered_map<index_t, std::shared_ptr<UnitTexture>> unit_textures;
224 
225 	/**
226 	 * sound ids mapped to playable sounds for all available sounds.
227 	 */
228 	std::unordered_map<index_t, Sound> available_sounds;
229 
230 	/**
231 	 * has game data been load yet
232 	 */
233 	bool gamedata_loaded;
234 };
235 
236 } // openage
237 
238 namespace qtsdl {
239 class GuiItemLink;
240 } // qtsdl
241 
242 namespace openage {
243 
244 class GameSpecSignals;
245 
246 /**
247  * Game specification instanciated in QML.
248  * Linked to the "GameSpec" QML type.
249  *
250  * Wraps the "GameSpec" C++ class from above.
251  */
252 class GameSpecHandle {
253 public:
254 	explicit GameSpecHandle(qtsdl::GuiItemLink *gui_link);
255 
256 	/**
257 	 * Control whether this specification can be loaded (=true)
258 	 * or will not be loaded (=false).
259 	 */
260 	void set_active(bool active);
261 
262 	/**
263 	 * invoked from qml when the asset_manager member is set.
264 	 */
265 	void set_asset_manager(AssetManager *asset_manager);
266 
267 	/**
268 	 * Return if the specification was fully loaded.
269 	 */
270 	bool is_ready() const;
271 
272 	/**
273 	 * forget everything about the specification and
274 	 * reload it with `start_loading_if_needed`.
275 	 */
276 	void invalidate();
277 
278 	/**
279 	 * signal about a loaded spec if any
280 	 */
281 	void announce_spec();
282 
283 	/**
284 	 * Return the contained game specification.
285 	 */
286 	std::shared_ptr<GameSpec> get_spec();
287 
288 private:
289 	/**
290 	 * load the game specification if not already present.
291 	 */
292 	void start_loading_if_needed();
293 
294 	/**
295 	 * Actually dispatch the loading job to the job manager.
296 	 */
297 	void start_load_job();
298 
299 	/**
300 	 * called from the job manager when the loading job finished.
301 	 */
302 	void on_loaded(job::result_function_t<bool> result);
303 
304 	/**
305 	 * The real game specification.
306 	 */
307 	std::shared_ptr<GameSpec> spec;
308 
309 	/**
310 	 * enables the loading of the game specification.
311 	 */
312 	bool active;
313 
314 	AssetManager *asset_manager;
315 
316 public:
317 	std::shared_ptr<GameSpecSignals> gui_signals;
318 	qtsdl::GuiItemLink *gui_link;
319 };
320 
321 class GameSpecSignals : public QObject {
322 	Q_OBJECT
323 
324 public:
325 signals:
326 	/*
327 	 * Some load job has finished.
328 	 *
329 	 * To be sure that the latest result is used, do the verification at the point of use.
330 	 */
331 	void load_job_finished();
332 
333 	void game_spec_loaded(std::shared_ptr<GameSpec> loaded_game_spec);
334 };
335 
336 }
337