1 // Copyright 2015-2018 the openage authors. See copying.md for legal info.
2 
3 #include "game_save.h"
4 
5 #include <fstream>
6 #include <vector>
7 
8 #include "../log/log.h"
9 #include "../terrain/terrain_chunk.h"
10 #include "../unit/producer.h"
11 #include "../unit/unit.h"
12 #include "../unit/unit_type.h"
13 #include "game_main.h"
14 #include "game_save.h"
15 #include "game_spec.h"
16 
17 namespace openage {
18 namespace gameio {
19 
save_unit(std::ofstream & file,Unit * unit)20 void save_unit(std::ofstream &file, Unit *unit) {
21 	file << unit->unit_type->id() << std::endl;
22 	file << unit->get_attribute<attr_type::owner>().player.player_number << std::endl;
23 	coord::tile pos = unit->location->pos.start;
24 	file << pos.ne << " " << pos.se << std::endl;
25 
26 	bool has_building_attr = unit->has_attribute(attr_type::building);
27 	file << has_building_attr << std::endl;
28 	if (has_building_attr) {
29 		file << unit->get_attribute<attr_type::building>().completed << std::endl;
30 	}
31 }
32 
load_unit(std::ifstream & file,GameMain * game)33 void load_unit(std::ifstream &file, GameMain *game) {
34 	int pr_id;
35 	int player_no;
36 	coord::tile_t ne, se;
37 	file >> pr_id;
38 	file >> player_no;
39 	file >> ne;
40 	file >> se;
41 
42 	UnitType &saved_type = *game->get_player(player_no)->get_type(pr_id);
43 	auto ref = game->placed_units.new_unit(saved_type, *game->get_player(player_no), coord::tile{ne, se}.to_phys3(*game->terrain));
44 
45 	bool has_building_attr;
46 	file >> has_building_attr;
47 	if (has_building_attr) {
48 		float completed;
49 		file >> completed;
50 		if (completed >= 1.0f && ref.is_valid()) {
51 			complete_building(*ref.get());
52 		}
53 	}
54 }
55 
save_tile_content(std::ofstream & file,openage::TileContent * content)56 void save_tile_content(std::ofstream &file, openage::TileContent *content) {
57 	file << content->terrain_id << std::endl;
58 	file << content->obj.size() << std::endl;
59 }
60 
load_tile_content(std::ifstream & file)61 TileContent load_tile_content(std::ifstream &file) {
62 	openage::TileContent content;
63 	file >> content.terrain_id;
64 
65 	unsigned int o_size;
66 	file >> o_size;
67 	return content;
68 }
69 
save(openage::GameMain * game,std::string fname)70 void save(openage::GameMain *game, std::string fname) {
71 	std::ofstream file(fname, std::ofstream::out);
72 	log::log(MSG(dbg) << "saving " + fname);
73 
74 	// metadata
75 	file << save_label << std::endl;
76 	file << save_version << std::endl;
77 	file << config::version << std::endl;
78 
79 	// how many chunks
80 	std::vector<coord::chunk> used = game->terrain->used_chunks();
81 	file << used.size() << std::endl;
82 
83 	// save each chunk
84 	for (coord::chunk &position : used) {
85 		file << position.ne << " " << position.se << std::endl;
86 		openage::TerrainChunk *chunk = game->terrain->get_chunk(position);
87 
88 		file << chunk->tile_count << std::endl;
89 		for (size_t p = 0; p < chunk->tile_count; ++p) {
90 			save_tile_content( file, chunk->get_data(p) );
91 		}
92 	}
93 
94 	// save units
95 	std::vector<openage::Unit *> units = game->placed_units.all_units();
96 	file << units.size() << std::endl;
97 	for (Unit *u : units) {
98 		save_unit(file, u);
99 	}
100 }
101 
load(openage::GameMain * game,std::string fname)102 void load(openage::GameMain *game, std::string fname) {
103 	std::ifstream file(fname, std::ifstream::in);
104 	if (!file.good()) {
105 		log::log(MSG(dbg) << "could not find " + fname);
106 		return;
107 	}
108 	log::log(MSG(dbg) << "loading " + fname);
109 
110 	// load metadata
111 	std::string file_label;
112 	file >> file_label;
113 	if (file_label != save_label) {
114 		log::log(MSG(warn) << fname << " is not a savefile");
115 		return;
116 	}
117 	std::string version;
118 	file >> version;
119 	if (version != save_version) {
120 		log::log(MSG(warn) << "savefile has different version");
121 	}
122 	std::string build;
123 	file >> build;
124 
125 	// read terrain chunks
126 	unsigned int num_chunks;
127 	file >> num_chunks;
128 	for (unsigned int c = 0; c < num_chunks; ++c) {
129 		coord::chunk_t ne, se;
130 		size_t tile_count;
131 		file >> ne;
132 		file >> se;
133 		file >> tile_count;
134 		openage::TerrainChunk *chunk = game->terrain->get_create_chunk(coord::chunk{ne, se});
135 		for (size_t p = 0; p < tile_count; ++p) {
136 			*chunk->get_data(p) = load_tile_content( file );
137 		}
138 	}
139 
140 	game->placed_units.reset();
141 	unsigned int num_units;
142 	file >> num_units;
143 	for (unsigned int u = 0; u < num_units; ++u) {
144 		load_unit( file, game );
145 	}
146 }
147 
148 }} // openage::gameio
149