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