From f5cf3b82006ffe51f9462ddc8a6f65dce55a03d6 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Thu, 29 Oct 2009 00:59:40 -0700 Subject: Pre- and post-savefile callbacks. The constructor of class SavefileCallback can be used to add a callback which is called before a game is saved and after it's restored. This is useful to move data in and out of you.props, or after a restore if there's data not stored in the savefile which can be easily regenerated. NOTE: I experienced some weirdness with C++ global constructors, and since global constructors probably differ with compiler and system, until this has been tested on all compiler/system combinations, any code which uses the callbacks should fail gracefully if the callbacks aren't called. --- crawl-ref/source/files.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++ crawl-ref/source/files.h | 11 ++++++++ crawl-ref/source/newgame.cc | 5 ++++ 3 files changed, 85 insertions(+) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 759b5c13e7..c27174835e 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -92,6 +92,8 @@ #endif #endif +static std::vector* _callback_list = NULL; + static void _save_level( int level_saved, level_area_type lt, branch_type where_were_you); @@ -1535,6 +1537,8 @@ void save_game(bool leave_game, const char *farewellmsg) { unwind_bool saving_game(crawl_state.saving_game, true); + SavefileCallback::pre_save(); + /* Stashes */ std::string stashFile = get_savedir_filename(you.your_name, "", "st"); FILE *stashf = fopen(stashFile.c_str(), "wb"); @@ -1669,6 +1673,13 @@ void save_game(bool leave_game, const char *farewellmsg) #ifdef DGL_WHEREIS whereis_record("saved"); #endif + + if (_callback_list != NULL) + { + delete _callback_list; + _callback_list = NULL; + } + end(0, false, farewellmsg? "%s" : "See you soon, %s!", farewellmsg? farewellmsg : you.your_name.c_str()); } // end save_game() @@ -1863,6 +1874,8 @@ void restore_game(void) load_messages(inf); fclose(msgf); } + + SavefileCallback::post_restore(); } static void _restore_level(const level_id &original) @@ -2270,3 +2283,59 @@ file_lock::~file_lock() lk_close(handle, mode, filename); #endif } + +///////////////////////////////////////////////////////////////////////////// +// SavefileCallback +// +// Callbacks which are called before a save and after a restore. Can be used +// to move stuff in and out of you.props, or on a restore to recalculate data +// which isn't stored in the savefile. Declare a SavefileCallback variable +// using a C++ global constructor to register the callback. +// +// XXX: Due to some weirdness with C++ global constructors (see below) I'm +// not sure if this will work for all compiler/system combos, so make any +// code which uses this fail gracefully if the callbacks aren't called. + +SavefileCallback::SavefileCallback(callback func) +{ + ASSERT(func != NULL); + + // XXX: For some reason (at least with GCC 4.3.2 on Linux) if the + // callback list is made with a global contructor then it gets emptied + // out by the time that pre_save() or post_restore() is called, + // probably having something to do with the fact that global + // contructors are also used to add the callbacks. Thus we have to do + // it this way. + if (_callback_list == NULL) + _callback_list = new std::vector(); + + _callback_list->push_back(func); +} + +void SavefileCallback::pre_save() +{ + ASSERT(crawl_state.saving_game); + + if (_callback_list == NULL) + return; + + for (unsigned int i = 0; i < _callback_list->size(); i++) + { + callback func = (*_callback_list)[i]; + (*func)(true); + } +} + +void SavefileCallback::post_restore() +{ + ASSERT(!crawl_state.saving_game); + + if (_callback_list == NULL) + return; + + for (unsigned int i = 0; i < _callback_list->size(); i++) + { + callback func = (*_callback_list)[i]; + (*func)(false); + } +} diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h index 3c05196f4a..80dcf2c3ec 100644 --- a/crawl-ref/source/files.h +++ b/crawl-ref/source/files.h @@ -145,4 +145,15 @@ private: std::string filename; }; +class SavefileCallback +{ +public: + typedef void (*callback)(bool saving); + + SavefileCallback(callback func); + + static void pre_save(); + static void post_restore(); +}; + #endif diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index ffb56cf046..e36fa10a01 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -898,6 +898,11 @@ game_start: fix_up_jiyva_name(); _save_newgame_options(); + + // Pretend that a savefile was just loaded, in order to + // get things setup properly. + SavefileCallback::post_restore(); + return (true); } -- cgit v1.2.3-54-g00ecf