1 /*
2  * Copyright (C) 2002-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #include "map_io/map_object_saver.h"
21 
22 #include "base/wexception.h"
23 #include "economy/ferry_fleet.h"
24 #include "economy/flag.h"
25 #include "economy/portdock.h"
26 #include "economy/road.h"
27 #include "economy/ship_fleet.h"
28 #include "economy/ware_instance.h"
29 #include "economy/waterway.h"
30 #include "logic/map_objects/bob.h"
31 #include "logic/map_objects/tribes/battle.h"
32 #include "logic/map_objects/tribes/building.h"
33 
34 namespace Widelands {
35 
MapObjectSaver()36 MapObjectSaver::MapObjectSaver()
37    : nr_roads_(0),
38      nr_waterways_(0),
39      nr_flags_(0),
40      nr_buildings_(0),
41      nr_bobs_(0),
42      nr_wares_(0),
43      nr_immovables_(0),
44      nr_battles_(0),
45      nr_ship_fleets_(0),
46      nr_ferry_fleets_(0),
47      nr_portdocks_(0),
48      lastserial_(0) {
49 }
50 
51 /**
52  * Return a pointer to the record for the given object.
53  * Create a record if that hasn't been done yet.
54  */
get_object_record(const MapObject & obj)55 MapObjectSaver::MapObjectRec& MapObjectSaver::get_object_record(const MapObject& obj) {
56 	MapObjectRecordMap::iterator it = objects_.find(&obj);
57 
58 	if (it != objects_.end()) {
59 		return it->second;
60 	}
61 
62 	MapObjectRec rec;
63 #ifndef NDEBUG
64 	rec.description = to_string(obj.descr().type());
65 	rec.description += " (";
66 	rec.description += obj.serial();
67 	rec.description += ')';
68 #endif
69 	rec.fileserial = ++lastserial_;
70 	rec.registered = false;
71 	rec.saved = false;
72 	return objects_.insert(std::pair<MapObject const*, MapObjectRec>(&obj, rec)).first->second;
73 }
74 
75 /**
76  * Returns true if this object has already been registered.
77  * \deprecated since get_object_file_index supports unregistered objects now
78  */
is_object_known(const MapObject & obj) const79 bool MapObjectSaver::is_object_known(const MapObject& obj) const {
80 	MapObjectRecordMap::const_iterator it = objects_.find(&obj);
81 
82 	if (it == objects_.end()) {
83 		return false;
84 	}
85 
86 	return it->second.registered;
87 }
88 
is_object_saved(const MapObject & obj)89 bool MapObjectSaver::is_object_saved(const MapObject& obj) {
90 	return get_object_record(obj).saved;
91 }
92 
93 /*
94  * Registers this object as a new one
95  */
register_object(const MapObject & obj)96 Serial MapObjectSaver::register_object(const MapObject& obj) {
97 	MapObjectRec& rec = get_object_record(obj);
98 
99 	assert(!rec.registered);
100 
101 	if (dynamic_cast<Flag const*>(&obj)) {
102 		++nr_flags_;
103 	} else if (dynamic_cast<Road const*>(&obj)) {
104 		++nr_roads_;
105 	} else if (dynamic_cast<Waterway const*>(&obj)) {
106 		++nr_waterways_;
107 	} else if (dynamic_cast<Building const*>(&obj)) {
108 		++nr_buildings_;
109 	} else if (dynamic_cast<Immovable const*>(&obj)) {
110 		++nr_immovables_;
111 	} else if (dynamic_cast<WareInstance const*>(&obj)) {
112 		++nr_wares_;
113 	} else if (dynamic_cast<Bob const*>(&obj)) {
114 		++nr_bobs_;
115 	} else if (dynamic_cast<Battle const*>(&obj)) {
116 		++nr_battles_;
117 	} else if (dynamic_cast<ShipFleet const*>(&obj)) {
118 		++nr_ship_fleets_;
119 	} else if (dynamic_cast<FerryFleet const*>(&obj)) {
120 		++nr_ferry_fleets_;
121 	} else if (dynamic_cast<PortDock const*>(&obj)) {
122 		++nr_portdocks_;
123 	} else {
124 		throw wexception("MapObjectSaver: Unknown MapObject type");
125 	}
126 
127 	rec.registered = true;
128 	return rec.fileserial;
129 }
130 
131 /**
132  * Returns the file index for this map object. This is used on load
133  * to regenerate the dependencies between the objects.
134  */
get_object_file_index(const MapObject & obj)135 uint32_t MapObjectSaver::get_object_file_index(const MapObject& obj) {
136 	return get_object_record(obj).fileserial;
137 }
138 
139 /**
140  * Returns the file index of the given object, or zero for null pointers.
141  */
get_object_file_index_or_zero(const MapObject * obj)142 uint32_t MapObjectSaver::get_object_file_index_or_zero(const MapObject* obj) {
143 	if (obj) {
144 		return get_object_file_index(*obj);
145 	}
146 	return 0;
147 }
148 
149 /*
150  * mark this object as saved
151  */
mark_object_as_saved(const MapObject & obj)152 void MapObjectSaver::mark_object_as_saved(const MapObject& obj) {
153 	MapObjectRec& rec = get_object_record(obj);
154 	assert(rec.registered);
155 	rec.saved = true;
156 }
157 
158 #ifndef NDEBUG
159 /*
160  * Return the number of unsaved objects
161  */
detect_unsaved_objects() const162 void MapObjectSaver::detect_unsaved_objects() const {
163 	for (const auto& temp_map : objects_) {
164 		if (!temp_map.second.saved) {
165 			throw wexception("%s has not been saved", temp_map.second.description.c_str());
166 		}
167 	}
168 }
169 #endif
170 }  // namespace Widelands
171