diff --git bauer/tree_builder.cc bauer/tree_builder.cc index 71adc8b4b..6ad6262e2 100644 --- bauer/tree_builder.cc +++ bauer/tree_builder.cc @@ -26,6 +26,7 @@ static const uint8 tree_age_index[(baum_t::AGE_LIMIT >> 6) + 1] = vector_tpl tree_builder_t::tree_list(0); weighted_vector_tpl tree_builder_t::tree_list_per_climate[MAX_CLIMATES]; stringhashtable_tpl tree_builder_t::desc_table; +vector_tpl tree_builder_t::loaded_tree_names; /// Quick lookup of an image, assuring always five seasons and five ages. @@ -343,3 +344,33 @@ bool tree_builder_t::spawn_tree_near(const baum_t *tree, int radius) return plant_tree_on_coordinate(k, tree->get_desc(), true, false); } + +void tree_builder_t::rdwr_tree_ids(loadsave_t *file) +{ + xml_tag_t tag(file, "tree_ids"); + + uint8 num_trees = tree_list.get_count()-1; + file->rdwr_byte(num_trees); + + if (file->is_loading()) { + loaded_tree_names.clear(); + plainstring str; + + for (uint8 i = 0; i < num_trees; ++i) { + file->rdwr_str(str); + loaded_tree_names.append(str); + } + } + else { + for (uint8 i = 0; i < num_trees; ++i) { + plainstring str = tree_list[i]->get_name(); + file->rdwr_str(str); + } + } +} + + +const char *tree_builder_t::get_loaded_desc_name(uint8 loaded_id) +{ + return (loaded_id < loaded_tree_names.get_count()) ? loaded_tree_names[loaded_id].c_str() : NULL; +} diff --git bauer/tree_builder.h bauer/tree_builder.h index 2ef39943f..1565c20fd 100644 --- bauer/tree_builder.h +++ bauer/tree_builder.h @@ -11,6 +11,8 @@ #include "../tpl/weighted_vector_tpl.h" #include "../tpl/vector_tpl.h" +#include "../utils/plainstring.h" + #include "../dataobj/koord.h" #include "../display/simimg.h" @@ -27,7 +29,21 @@ private: static vector_tpl tree_list; ///< Mapping tree_id -> desc static weighted_vector_tpl tree_list_per_climate[MAX_CLIMATES]; ///< index vector into tree_list, accessible per climate + static vector_tpl loaded_tree_names; ///< Maps loaded_id -> loaded_desc_name + public: + static void rdwr_tree_ids(loadsave_t *file); + + /// Tree IDs never change after loading paks, so when loading a save + /// which was saved with a different set of tree paks the tree ID from the save + /// has to be translated to the one used in the current game. + /// This is done by mapping + /// loaded_id -> loaded_desc_name -> real_desc_name -> real_id + /// This function does the first mapping based on the data stored in the save file. + /// Returns NULL if no desc name could be found. + /// @sa boden_t::boden_t + static const char *get_loaded_desc_name(uint8 loaded_id); + static const tree_desc_t *get_desc_by_name(const char * tree_name) { return desc_table.get(tree_name); } static const tree_desc_t *get_desc_by_id(uint8 tree_id) { return tree_id < get_num_trees() ? tree_list[tree_id] : NULL; } static uint8 get_id_by_desc(const tree_desc_t *desc) { return tree_list.index_of(desc); } @@ -68,7 +84,7 @@ public: static const tree_desc_t *random_tree_for_climate(climate cl); /// also checks for distribution values - /// @returns the tree_i, or 0xFFFF if no trees exist for the requested climate. + /// @returns the tree_id, or 0xFFFF if no trees exist for the requested climate. static uint16 random_tree_id_for_climate(climate cl); }; diff --git boden/boden.cc boden/boden.cc index 265aafbb1..6980586d3 100644 --- boden/boden.cc +++ boden/boden.cc @@ -10,6 +10,7 @@ #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" +#include "../dataobj/translator.h" #include "boden.h" @@ -17,25 +18,51 @@ #include "../descriptor/skin_desc.h" - boden_t::boden_t(loadsave_t *file, koord pos ) : grund_t( koord3d(pos,0) ) { grund_t::rdwr( file ); - // restoring trees (disadvantage: loosing offsets but much smaller savegame footprint) + // restoring trees (disadvantage: losing offsets but much smaller savegame footprint) if( file->is_version_atleast(110, 1) ) { sint16 id = file->rd_obj_id(); while( id!=-1 ) { - sint32 age; - file->rdwr_long( age ); - // check, if we still have this tree ... (if there are not trees, the first index is NULL!) - if (tree_builder_t::get_desc_by_id(id) != NULL) { + if (id != (uint8)id) { + dbg->warning("boden_t::boden_t", "Invalid tree id %hd, using %hhu", id, (uint8)id); + } + + uint16 age; + if (file->is_version_atleast(122, 2)) { + file->rdwr_short(age); + age &= 0xFFF; + } + else { + sint32 val; + file->rdwr_long(val); + age = (uint32)val & 0xFFF; + } + + // check if we still have this tree + const tree_desc_t *desc = NULL; + const char *desc_name = tree_builder_t::get_loaded_desc_name((uint8)id); + + if (desc_name) { + desc = tree_builder_t::get_desc_by_name(desc_name); + if (!desc) { + desc = tree_builder_t::get_desc_by_name(translator::compatibility_name(desc_name)); + } + } + else { + desc = tree_builder_t::get_desc_by_id((uint8)id); + } + + if (desc) { baum_t *tree = new baum_t( get_pos(), (uint8)id, age, slope ); objlist.add( tree ); } else { - dbg->warning( "boden_t::boden_t()", "Could not restore tree type %i at (%s)", id, pos.get_str() ); + dbg->warning( "boden_t::boden_t()", "Could not restore tree type %hhu at (%s)", (uint8)id, pos.get_str() ); } + // check for next tree id = file->rd_obj_id(); } @@ -55,15 +82,22 @@ void boden_t::rdwr(loadsave_t *file) grund_t::rdwr(file); if( file->is_version_atleast(110, 1) ) { - // a server send the smallest possible savegames to clients, i.e. saves only types and age of trees - if( env_t::server && !hat_wege() ) { + // a server sends the smallest possible savegames to clients, i.e. saves only types and age of trees + if( (env_t::server || file->is_version_atleast(122, 2)) && !hat_wege() ) { for( uint8 i=0; iget_typ()==obj_t::baum ) { baum_t *tree = (baum_t *)obj; file->wr_obj_id( tree->get_desc_id() ); - uint32 age = tree->get_age(); - file->rdwr_long( age ); + + if (file->is_version_atleast(122, 2)) { + uint16 age = tree->get_age(); + file->rdwr_short( age ); + } + else { + uint32 age = tree->get_age(); + file->rdwr_long( age ); + } } } } diff --git dataobj/objlist.cc dataobj/objlist.cc index c746a500e..ad53bcbf7 100644 --- dataobj/objlist.cc +++ dataobj/objlist.cc @@ -1077,7 +1077,7 @@ void objlist_t::rdwr(loadsave_t *file, koord3d current_pos) || (new_obj->get_typ()==obj_t::gebaeude && ((gebaeude_t *)new_obj)->get_fabrik()) // things with convoi will not be saved || (new_obj->get_typ()>=66 && new_obj->get_typ()<82) - || (env_t::server && new_obj->get_typ()==obj_t::baum && file->is_version_atleast(110, 1)) + || (new_obj->get_typ()==obj_t::baum && file->is_version_atleast(110, 1) && (env_t::server || file->is_version_atleast(122, 2))) // trees are saved from boden_t ) { // these objects are simply not saved } diff --git obj/baum.h obj/baum.h index f37d2689c..f788f88a0 100644 --- obj/baum.h +++ obj/baum.h @@ -67,6 +67,7 @@ public: typ get_typ() const OVERRIDE { return baum; } /// @copydoc obj_t::rdwr + /// @deprecated Only used for loading old saves that did save tree offsets void rdwr(loadsave_t *file) OVERRIDE; /// @copydoc obj_t::finish_rd diff --git simversion.h simversion.h index 668652939..b432cc9ed 100644 --- simversion.h +++ simversion.h @@ -23,8 +23,8 @@ // Beware: SAVEGAME minor is often ahead of version minor when there were patches. // ==> These have no direct connection at all! -#define SIM_SAVE_MINOR 1 -#define SIM_SERVER_MINOR 1 +#define SIM_SAVE_MINOR 2 +#define SIM_SERVER_MINOR 2 // NOTE: increment before next release to enable save/load of new features #define MAKEOBJ_VERSION "60.5" diff --git simworld.cc simworld.cc index 2f9a0768f..472b7c89e 100644 --- simworld.cc +++ simworld.cc @@ -5609,6 +5609,12 @@ void karte_t::rdwr_gamestate(loadsave_t *file, loadingscreen_t *ls) active_player_nr = 0; } + // rdwr tree ID mapping to restore tree IDs + if (file->is_version_atleast(122, 2)) { + DBG_MESSAGE("karte_t::rdwr_gamestate()", "rdwr tree IDs"); + tree_builder_t::rdwr_tree_ids(file); + } + // rdwr static states senke_t::static_rdwr(file);