From 44cb574e327a5d73724e6e0e57cb32da5451f93b Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 8 Feb 2014 23:24:12 +0000 Subject: [PATCH 01/15] Refactor|libcommon: Use a map URI with G_NewGame() and G_DeferredNewGame() At present the logical episode and map numbers are parsed from the map URI. In the future the episode should be specified in MAPINFO. --- doomsday/plugins/common/include/g_common.h | 17 +- doomsday/plugins/common/include/p_mapsetup.h | 13 +- doomsday/plugins/common/src/d_net.c | 24 +- doomsday/plugins/common/src/d_netcl.c | 22 +- doomsday/plugins/common/src/d_netsv.c | 12 +- doomsday/plugins/common/src/fi_lib.c | 10 +- doomsday/plugins/common/src/g_game.c | 234 +++++++++++-------- doomsday/plugins/common/src/g_update.c | 6 +- doomsday/plugins/common/src/hu_menu.c | 8 +- doomsday/plugins/common/src/hu_stuff.cpp | 12 +- doomsday/plugins/common/src/p_mapsetup.cpp | 27 +-- doomsday/plugins/common/src/p_saveg.cpp | 6 +- doomsday/plugins/common/src/p_sound.cpp | 2 +- doomsday/plugins/doom/include/g_game.h | 1 + doomsday/plugins/doom/src/d_main.c | 59 +++-- doomsday/plugins/doom/src/m_cheat.c | 37 +-- doomsday/plugins/doom/src/p_oldsvg.cpp | 2 +- doomsday/plugins/doom/src/wi_stuff.c | 2 +- doomsday/plugins/doom64/include/g_game.h | 1 + doomsday/plugins/doom64/src/d_main.c | 53 ++--- doomsday/plugins/doom64/src/m_cheat.c | 40 ++-- doomsday/plugins/doom64/src/wi_stuff.c | 2 +- doomsday/plugins/heretic/include/g_game.h | 1 + doomsday/plugins/heretic/src/h_main.c | 53 +++-- doomsday/plugins/heretic/src/m_cheat.c | 40 ++-- doomsday/plugins/heretic/src/p_oldsvg.cpp | 2 +- doomsday/plugins/hexen/include/g_game.h | 1 + doomsday/plugins/hexen/include/p_mapinfo.h | 5 + doomsday/plugins/hexen/src/acscript.cpp | 7 +- doomsday/plugins/hexen/src/h2_main.c | 57 ++--- doomsday/plugins/hexen/src/m_cheat.c | 39 ++-- doomsday/plugins/hexen/src/p_mapinfo.cpp | 5 + doomsday/plugins/hexen/src/p_spec.c | 4 +- 33 files changed, 404 insertions(+), 400 deletions(-) diff --git a/doomsday/plugins/common/include/g_common.h b/doomsday/plugins/common/include/g_common.h index 189d1cf6dc..d5347200fe 100644 --- a/doomsday/plugins/common/include/g_common.h +++ b/doomsday/plugins/common/include/g_common.h @@ -69,13 +69,12 @@ void G_EndGame(void); dd_bool G_QuitInProgress(void); /** - * @param episode Logical episode number. - * @param map Logical map number (i.e., not a warp/translated number). + * @param mapUri Map identifier. * @param mapEntrance Logical map entry point number. * @param rules Game rules to apply. */ -void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules); -void G_DeferredNewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules); +void G_NewGame(Uri const *mapUri, uint mapEntrance, GameRuleset const *rules); +void G_DeferredNewGame(Uri const *mapUri, uint mapEntrance, GameRuleset const *rules); /** * Signal that play on the current map may now begin. @@ -103,16 +102,6 @@ void G_LeaveMap(uint newMap, uint mapEntryPoint, dd_bool secretExit); */ Uri *G_ComposeMapUri(uint episode, uint map); -/** - * Compose the Uri for the @em current map. - * - * @note Some APIs are designed such that a NULL uri pointer means the "current map", - * so, calling this may be unnecessary. - * - * @return Resultant Uri. Must be destroyed with Uri_Delete() when no longer needed. - */ -Uri *G_CurrentMapUri(void); - /** * Determine if the specified @a episode and @a map value pair are valid and if not, * adjust their are values within the ranges defined by the current game type and mode. diff --git a/doomsday/plugins/common/include/p_mapsetup.h b/doomsday/plugins/common/include/p_mapsetup.h index fcfa23df70..056096b21d 100644 --- a/doomsday/plugins/common/include/p_mapsetup.h +++ b/doomsday/plugins/common/include/p_mapsetup.h @@ -46,12 +46,19 @@ void P_FinalizeMapChange(Uri const *uri); */ void P_SetupMap(Uri *uri); +/** + * @param mapUri Identifier of the map to lookup the author of. Can be @c 0 in which + * case the author for the @em current map will be returned (if set). + */ char const *P_MapAuthor(Uri const *mapUri, dd_bool supressGameAuthor); + +/** + * @param mapUri Identifier of the map to lookup the title of. Can be @c 0 in which + * case the title for the @em current map will be returned (if set). + */ char const *P_MapTitle(Uri const *mapUri); -patchid_t P_MapTitlePatch(uint episode, uint map); -char const *P_CurrentMapAuthor(dd_bool supressGameAuthor); -char const *P_CurrentMapTitle(void); +patchid_t P_MapTitlePatch(uint episode, uint map); #if __JDOOM__ || __JDOOM64__ || __JHERETIC__ void P_FindSecrets(void); diff --git a/doomsday/plugins/common/src/d_net.c b/doomsday/plugins/common/src/d_net.c index ab79f14af1..e41d06d29c 100644 --- a/doomsday/plugins/common/src/d_net.c +++ b/doomsday/plugins/common/src/d_net.c @@ -126,7 +126,7 @@ void NetSv_ApplyGameRulesFromConfig(void) */ int D_NetServerStarted(int before) { - uint netMap, netEpisode; + Uri *netMapUri = 0; GameRuleset netRules = gameRules; // Make a copy of the current rules. if(before) return true; @@ -144,26 +144,30 @@ int D_NetServerStarted(int before) // Set the game parameters. NetSv_ApplyGameRulesFromConfig(); - // Hexen has translated map numbers. -#if __JHEXEN__ - netMap = P_TranslateMap(cfg.netMap); + { +#if __JDOOM64__ + uint netEpisode = 0; #else - netMap = cfg.netMap; + uint netEpisode = cfg.netEpisode; #endif - -#if __JDOOM64__ - netEpisode = 0; +#if __JHEXEN__ // Map numbers need to be translated. + uint netMap = P_TranslateMap(cfg.netMap); #else - netEpisode = cfg.netEpisode; + uint netMap = cfg.netMap; #endif + netMapUri = G_ComposeMapUri(netEpisode, netMap); + } + netRules.skill = cfg.netSkill; - G_NewGame(netEpisode, netMap, 0/*default*/, &netRules); + G_NewGame(netMapUri, 0/*default*/, &netRules); /// @todo Necessary? G_SetGameAction(GA_NONE); + Uri_Delete(netMapUri); + return true; } diff --git a/doomsday/plugins/common/src/d_netcl.c b/doomsday/plugins/common/src/d_netcl.c index 818cfa4f5b..bc586a3b5e 100644 --- a/doomsday/plugins/common/src/d_netcl.c +++ b/doomsday/plugins/common/src/d_netcl.c @@ -42,10 +42,10 @@ void NetCl_UpdateGameState(Reader* msg) byte len; byte gsFlags = 0; char gsGameIdentity[256]; - Uri* mapUri; - byte gsEpisode = 0; - byte gsMap = 0; - byte gsMapEntrance = 0; + Uri *mapUri; + uint gsEpisode = 0; + uint gsMap = 0; + uint gsMapEntrance = 0; byte configFlags = 0; //byte gsDeathmatch = 0; //byte gsMonsters = 0; @@ -65,13 +65,12 @@ void NetCl_UpdateGameState(Reader* msg) gsGameIdentity[len] = 0; // Current map. - mapUri = Uri_FromReader(msg); - + mapUri = Uri_FromReader(msg); gsEpisode = Reader_ReadByte(msg); - gsMap = Reader_ReadByte(msg); + gsMap = Reader_ReadByte(msg); /// @todo Not communicated to clients?? - //gsMapEntryPoint = ??; + //gsMapEntrance = ??; configFlags = Reader_ReadByte(msg); gsRules.deathmatch = configFlags & 0x3; @@ -80,11 +79,13 @@ void NetCl_UpdateGameState(Reader* msg) gsRules.respawnMonsters = (configFlags & 0x8? true : false); #endif gsJumping = (configFlags & 0x10? true : false); - gsRules.skill = Reader_ReadByte(msg); + gsRules.skill = Reader_ReadByte(msg); // Interpret skill modes outside the normal range as "spawn no things". if(gsRules.skill < SM_BABY || gsRules.skill >= NUM_SKILL_MODES) + { gsRules.skill = SM_NOTHINGS; + } gsGravity = Reader_ReadFloat(msg); @@ -138,7 +139,7 @@ void NetCl_UpdateGameState(Reader* msg) // Do we need to change the map? if(gsFlags & GSF_CHANGE_MAP) { - G_NewGame(gsEpisode, gsMap, gameMapEntrance /*gsMapEntrance*/, &gsRules); + G_NewGame(mapUri, gameMapEntrance /*gsMapEntrance*/, &gsRules); /// @todo Necessary? G_SetGameAction(GA_NONE); @@ -147,6 +148,7 @@ void NetCl_UpdateGameState(Reader* msg) { gameEpisode = gsEpisode; gameMap = gsMap; + Uri_Copy(gameMapUri, mapUri); //gameMapEntrance = gsMapEntrance; /// @todo Not communicated to clients?? gameRules = gsRules; } diff --git a/doomsday/plugins/common/src/d_netsv.c b/doomsday/plugins/common/src/d_netsv.c index a655e16fc2..fc9ad03542 100644 --- a/doomsday/plugins/common/src/d_netsv.c +++ b/doomsday/plugins/common/src/d_netsv.c @@ -727,19 +727,17 @@ void NetSv_SendTotalCounts(int to) void NetSv_SendGameState(int flags, int to) { int i; - Writer* writer; + Writer *writer; GameInfo gameInfo; - Uri* mapUri; - AutoStr* str; + AutoStr *str; if(!IS_NETWORK_SERVER) return; DD_GameInfo(&gameInfo); - mapUri = G_CurrentMapUri(); // Print a short message that describes the game state. - str = Uri_Resolved(mapUri); + str = Uri_Resolved(gameMapUri); App_Log(DE2_NET_NOTE, "Sending game setup: %s %s %s", Str_Text(gameInfo.identityKey), Str_Text(str), gameConfigString); @@ -758,7 +756,7 @@ void NetSv_SendGameState(int flags, int to) Writer_Write(writer, Str_Text(gameInfo.identityKey), Str_Length(gameInfo.identityKey)); // The current map. - Uri_Write(mapUri, writer); + Uri_Write(gameMapUri, writer); // Also include the episode and map numbers. Writer_WriteByte(writer, gameEpisode); @@ -789,8 +787,6 @@ void NetSv_SendGameState(int flags, int to) // Send the packet. Net_SendPacket(i, GPT_GAME_STATE, Writer_Data(writer), Writer_Size(writer)); } - - Uri_Delete(mapUri); } /** diff --git a/doomsday/plugins/common/src/fi_lib.c b/doomsday/plugins/common/src/fi_lib.c index 8e6d1dbdc3..54d7a5d9f3 100644 --- a/doomsday/plugins/common/src/fi_lib.c +++ b/doomsday/plugins/common/src/fi_lib.c @@ -103,10 +103,9 @@ static void initStateConditions(fi_state_t *s) #if __JHEXEN__ // Leaving the current cluster? { - Uri *curMapUri = G_CurrentMapUri(); Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - mapinfo_t *curMapInfo = P_MapInfo(curMapUri); + mapinfo_t *curMapInfo = P_CurrentMapInfo(); mapinfo_t *nextMapInfo = P_MapInfo(nextMapUri); if(curMapInfo && nextMapInfo) { @@ -114,7 +113,6 @@ static void initStateConditions(fi_state_t *s) } Uri_Delete(nextMapUri); - Uri_Delete(curMapUri); } App_Log(DE2_DEV_SCR_VERBOSE, "Infine state condition: leave_hub=%i", s->conditions.leave_hub); #endif @@ -453,14 +451,10 @@ int Hook_FinaleScriptStop(int hookType, int finaleId, void* parameters) else if(mode == FIMODE_BEFORE) // A briefing has ended. { // Its time to start the map; que music and begin! - Uri *mapUri = G_CurrentMapUri(); - - S_MapMusic(mapUri); + S_MapMusic(0/*current map*/); HU_WakeWidgets(-1 /* all players */); G_BeginMap(); Pause_End(); // skip forced period - - Uri_Delete(mapUri); } return true; } diff --git a/doomsday/plugins/common/src/g_game.c b/doomsday/plugins/common/src/g_game.c index 4724cbf4ea..665b9667fb 100644 --- a/doomsday/plugins/common/src/g_game.c +++ b/doomsday/plugins/common/src/g_game.c @@ -165,6 +165,7 @@ dd_bool gameInProgress; uint gameEpisode; uint gameMap; uint gameMapEntrance; // Position indicator for reborn. +Uri *gameMapUri; GameRuleset gameRules; uint nextMap; @@ -208,9 +209,14 @@ int bodyQueueSlot; #endif // vars used with game status cvars +int gsvEpisode = 0; +int gsvMap = 0; +char *gsvMapAuthor = "Unknown"; +int gsvMapMusic = -1; +char *gsvMapTitle = "Unknown"; + int gsvInMap = 0; int gsvCurrentMusic = 0; -int gsvMapMusic = -1; int gsvArmor = 0; int gsvHealth = 0; @@ -226,9 +232,6 @@ int gsvWeapons[NUM_WEAPON_TYPES]; int gsvKeys[NUM_KEY_TYPES]; int gsvAmmo[NUM_AMMO_TYPES]; -char *gsvMapName = "Unknown"; -char *gsvMapAuthor = "Unknown"; - #if __JHERETIC__ || __JHEXEN__ || __JDOOM64__ int gsvInvItems[NUM_INVENTORYITEM_TYPES]; #endif @@ -252,13 +255,13 @@ cvartemplate_t gamestatusCVars[] = #endif {"map-author", READONLYCVAR, CVT_CHARPTR, &gsvMapAuthor, 0, 0}, - {"map-episode", READONLYCVAR, CVT_INT, &gameEpisode, 0, 0}, + {"map-episode", READONLYCVAR, CVT_INT, &gsvEpisode, 0, 0}, #if __JHEXEN__ {"map-hub", READONLYCVAR, CVT_INT, &mapHub, 0, 0}, #endif - {"map-id", READONLYCVAR, CVT_INT, &gameMap, 0, 0}, + {"map-id", READONLYCVAR, CVT_INT, &gsvMap, 0, 0}, {"map-music", READONLYCVAR, CVT_INT, &gsvMapMusic, 0, 0}, - {"map-name", READONLYCVAR, CVT_CHARPTR, &gsvMapName, 0, 0}, + {"map-name", READONLYCVAR, CVT_CHARPTR, &gsvMapTitle, 0, 0}, {"player-health", READONLYCVAR, CVT_INT, &gsvHealth, 0, 0}, {"player-armor", READONLYCVAR, CVT_INT, &gsvArmor, 0, 0}, @@ -402,9 +405,8 @@ ccmdtemplate_t gameCmds[] = { }; // Deferred new game arguments: -static uint dEpisode; -static uint dMap; static uint dMapEntrance; +static Uri *dMapUri; ///< @todo fixme: Never free'd static GameRuleset dRules; static gameaction_t gameAction; @@ -459,6 +461,8 @@ void G_CommonPreInit(void) { int i, j; + DENG_ASSERT(gameMapUri == 0); + gameMapUri = Uri_New(); quitInProgress = false; verbose = CommandLine_Exists("-verbose"); @@ -948,7 +952,7 @@ void G_CommonPostInit(void) /** * Common game shutdown routine. - * \note Game-specific actions should be placed in G_Shutdown rather than here. + * @note Game-specific actions should be placed in G_Shutdown rather than here. */ void G_CommonShutdown(void) { @@ -966,6 +970,8 @@ void G_CommonShutdown(void) Hu_MenuShutdown(); ST_Shutdown(); GUI_Shutdown(); + + Uri_Delete(gameMapUri); gameMapUri = 0; } /** @@ -1142,37 +1148,31 @@ void G_StartHelp(void) */ static void printMapBanner(void) { - Uri *mapUri = G_CurrentMapUri(); - char const *title = P_CurrentMapTitle(); + char const *title = P_MapTitle(0/*current map*/); App_Log(DE2_LOG_MAP, DE2_ESC(R)); if(title) { char buf[64]; #if __JHEXEN__ - mapinfo_t const *mapInfo = P_MapInfo(mapUri); + mapinfo_t const *mapInfo = P_CurrentMapInfo(); int warpNum = (mapInfo? mapInfo->warpTrans : -1); dd_snprintf(buf, 64, "Map %u (%u): " DE2_ESC(b) "%s", warpNum + 1, gameMap + 1, title); #else - dd_snprintf(buf, 64, "Map %u: " DE2_ESC(b) "%s", gameMap+1, title); + dd_snprintf(buf, 64, "Map %u: " DE2_ESC(b) "%s", gameMap + 1, title); #endif App_Log(DE2_MAP_NOTE, "%s", buf); } #if !__JHEXEN__ { - AutoStr *path = Uri_Compose(mapUri); - char const *author; - - author = P_CurrentMapAuthor(P_MapIsCustom(Str_Text(path))); + char const *author = P_MapAuthor(0/*current map*/, P_MapIsCustom(Str_Text(Uri_Compose(gameMapUri)))); if(!author) author = "Unknown"; App_Log(DE2_MAP_VERBOSE, "Author: %s", author); } #endif App_Log(DE2_LOG_MAP, ""); - - Uri_Delete(mapUri); } void G_BeginMap(void) @@ -1256,8 +1256,7 @@ static void initFogForMap(ddmapinfo_t *mapInfo) #if __JHEXEN__ { - Uri *mapUri = G_CurrentMapUri(); - mapinfo_t const *mapInfo = P_MapInfo(mapUri); + mapinfo_t const *mapInfo = P_CurrentMapInfo(); if(mapInfo) { int fadeTable = mapInfo->fadeTable; @@ -1276,7 +1275,6 @@ static void initFogForMap(ddmapinfo_t *mapInfo) } } } - Uri_Delete(mapUri); } #endif } @@ -1423,8 +1421,8 @@ void G_UpdateGSVarsForPlayer(player_t* pl) void G_UpdateGSVarsForMap(void) { - char const *mapAuthor = P_CurrentMapAuthor(false/*don't supress*/); - char const *mapTitle = P_CurrentMapTitle(); + char const *mapAuthor = P_MapAuthor(0/*current map*/, false/*don't supress*/); + char const *mapTitle = P_MapTitle(0/*current map*/); if(!mapAuthor) mapAuthor = "Unknown"; Con_SetString2("map-author", mapAuthor, SVF_WRITE_OVERRIDE); @@ -1511,7 +1509,7 @@ void G_DoQuitGame(void) void G_QueMapMusic(Uri const *mapUri) { - DENG_ASSERT(mapUri != 0); + if(!mapUri) mapUri = gameMapUri; #if __JHEXEN__ /** @@ -1548,7 +1546,7 @@ static void runGameAction(void) { case GA_NEWGAME: G_InitNewGame(); - G_NewGame(dEpisode, dMap, dMapEntrance, &dRules); + G_NewGame(dMapUri, dMapEntrance, &dRules); G_SetGameAction(GA_NONE); break; @@ -1766,13 +1764,11 @@ void G_PlayerLeaveMap(int player) #if __JHEXEN__ { - Uri *mapUri = G_CurrentMapUri(); Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - newCluster = (P_MapInfo(mapUri)->cluster != P_MapInfo(nextMapUri)->cluster); + newCluster = (P_CurrentMapInfo()->cluster != P_MapInfo(nextMapUri)->cluster); Uri_Delete(nextMapUri); - Uri_Delete(mapUri); } #endif @@ -2414,16 +2410,13 @@ void G_DoMapCompleted(void) // Go to an intermission? #if __JDOOM__ || __JHERETIC__ || __JDOOM64__ { - ddmapinfo_t minfo; - Uri* mapUri = G_CurrentMapUri(); - AutoStr* mapPath = Uri_Compose(mapUri); - if(Def_Get(DD_DEF_MAP_INFO, Str_Text(mapPath), &minfo) && (minfo.flags & MIF_NO_INTERMISSION)) - { - Uri_Delete(mapUri); - G_IntermissionDone(); - return; - } - Uri_Delete(mapUri); + ddmapinfo_t minfo; + if(Def_Get(DD_DEF_MAP_INFO, Str_Text(Uri_Compose(gameMapUri)), &minfo) && + (minfo.flags & MIF_NO_INTERMISSION)) + { + G_IntermissionDone(); + return; + } } #elif __JHEXEN__ @@ -2479,9 +2472,8 @@ void G_DoMapCompleted(void) #if __JDOOM__ || __JDOOM64__ void G_PrepareWIData(void) { - Uri* mapUri = G_CurrentMapUri(); - AutoStr* mapPath = Uri_Compose(mapUri); - wbstartstruct_t* info = &wmInfo; + AutoStr *mapPath = Uri_Compose(gameMapUri); + wbstartstruct_t *info = &wmInfo; ddmapinfo_t minfo; int i; @@ -2489,9 +2481,13 @@ void G_PrepareWIData(void) // See if there is a par time definition. if(Def_Get(DD_DEF_MAP_INFO, Str_Text(mapPath), &minfo) && minfo.parTime > 0) + { info->parTime = TICRATE * (int) minfo.parTime; + } else + { info->parTime = -1; // Unknown. + } info->pNum = CONSOLEPLAYER; for(i = 0; i < MAXPLAYERS; ++i) @@ -2506,8 +2502,6 @@ void G_PrepareWIData(void) pStats->time = mapTime; memcpy(pStats->frags, p->frags, sizeof(pStats->frags)); } - - Uri_Delete(mapUri); } #endif @@ -2517,17 +2511,10 @@ void G_PrepareWIData(void) */ dd_bool G_StartDebriefing() { - Uri *mapUri = G_CurrentMapUri(); ddfinale_t fin; - - if(G_DebriefingEnabled(mapUri, &fin) && - G_StartFinale(fin.script, 0, FIMODE_AFTER, 0)) - { - Uri_Delete(mapUri); - return true; - } - Uri_Delete(mapUri); - return false; + if(!G_DebriefingEnabled(gameMapUri, &fin)) return false; + + return G_StartFinale(fin.script, 0, FIMODE_AFTER, 0); } void G_IntermissionDone(void) @@ -2614,9 +2601,8 @@ void G_DoLeaveMap(void) // Same cluster? { - Uri *mapUri = G_CurrentMapUri(); Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - if(P_MapInfo(mapUri)->cluster == P_MapInfo(nextMapUri)->cluster) + if(P_CurrentMapInfo()->cluster == P_MapInfo(nextMapUri)->cluster) { if(!gameRules.deathmatch) { @@ -2633,7 +2619,6 @@ void G_DoLeaveMap(void) } Uri_Delete(nextMapUri); - Uri_Delete(mapUri); } // Take a copy of the player objects (they will be cleared in the process @@ -2747,7 +2732,7 @@ void G_DoRestartMap(void) // Restart the game session entirely. G_InitNewGame(); - G_NewGame(dEpisode, dMap, dMapEntrance, &dRules); + G_NewGame(dMapUri, dMapEntrance, &dRules); #else loadmap_params_t p; @@ -2759,7 +2744,7 @@ void G_DoRestartMap(void) // Delete raw images to conserve texture memory. DD_Executef(true, "texreset raw"); - p.mapUri = G_CurrentMapUri(); + p.mapUri = gameMapUri; p.revisit = false; // Don't reload save state. // This is a restart, so we won't brief again. @@ -2775,7 +2760,6 @@ void G_DoRestartMap(void) G_BeginMap(); Z_CheckHeap(); - Uri_Delete(p.mapUri); #endif } @@ -2877,15 +2861,13 @@ AutoStr *G_GenerateSaveGameName(void) char const *baseName, *mapTitle; char baseNameBuf[256]; AutoStr *mapPath; - Uri *mapUri; hours = time / 3600; time -= hours * 3600; minutes = time / 60; time -= minutes * 60; seconds = time; - mapUri = G_CurrentMapUri(); - mapPath = Uri_Compose(mapUri); - mapTitle = P_CurrentMapTitle(); + mapPath = Uri_Compose(gameMapUri); + mapTitle = P_MapTitle(0/*current map*/); // Still no map title? Use the identifier. // Some tricksy modders provide us with an empty title... @@ -2905,7 +2887,6 @@ AutoStr *G_GenerateSaveGameName(void) Str_Appendf(str, "%s%s%s %02i:%02i:%02i", (baseName? baseName : ""), (baseName? ":" : ""), mapTitle, hours, minutes, seconds); - Uri_Delete(mapUri); return str; } @@ -2958,23 +2939,72 @@ void G_DoSaveGame(void) G_SetGameAction(GA_NONE); } -void G_DeferredNewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules) +void G_DeferredNewGame(Uri const *mapUri, uint mapEntrance, GameRuleset const *rules) { - DENG_ASSERT(rules != 0); - - dEpisode = episode; - dMap = map; + if(!dMapUri) + { + dMapUri = Uri_New(); + } + Uri_Copy(dMapUri, mapUri? mapUri : gameMapUri); dMapEntrance = mapEntrance; - dRules = *rules; // make a copy. + dRules = rules? *rules : gameRules; // make a copy. G_SetGameAction(GA_NEWGAME); } -void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules) +/// @todo Get this from MAPINFO +static uint episodeNumberFor(Uri const *mapUri) +{ +#if __JDOOM__ || __JHERETIC__ + AutoStr *path = Uri_Resolved(mapUri); + if(!Str_IsEmpty(path)) + { +# if __JDOOM__ + if(gameModeBits & (GM_ANY_DOOM | ~GM_DOOM_CHEX)) +# endif + { + if(Str_At(path, 0) == 'E' && Str_At(path, 2) == 'M') + { + return atoi(Str_Text(path) + 1) - 1; + } + } + } +#else + DENG_UNUSED(mapUri); +#endif + return 0; +} + +/// @todo Get this from MAPINFO +static uint mapNumberFor(Uri const *mapUri) +{ + AutoStr *path = Uri_Resolved(mapUri); + if(!Str_IsEmpty(path)) + { +#if __JDOOM__ || __JHERETIC__ +# if __JDOOM__ + if(gameModeBits & (GM_ANY_DOOM | ~GM_DOOM_CHEX)) +# endif + { + if(Str_At(path, 0) == 'E' && Str_At(path, 2) == 'M') + { + return atoi(Str_Text(path) + 3) - 1; + } + } +#endif + if(Str_StartsWith(path, "MAP")) + { + return atoi(Str_Text(path) + 3) - 1; + } + } + return 0; +} + +void G_NewGame(Uri const *mapUri, uint mapEntrance, GameRuleset const *rules) { uint i; - DENG_ASSERT(rules != 0); + DENG_ASSERT(mapUri != 0 && rules != 0); G_StopDemo(); @@ -3016,14 +3046,24 @@ void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rule // Delete raw images to conserve texture memory. DD_Executef(true, "texreset raw"); - // Make sure that the episode and map numbers are good. - G_ValidateMap(&episode, &map); - - gameEpisode = episode; - gameMap = map; + gameEpisode = episodeNumberFor(mapUri); + gameMap = mapNumberFor(mapUri); + Uri_Copy(gameMapUri, mapUri); gameMapEntrance = mapEntrance; gameRules = *rules; + // Make sure that the episode and map numbers are good. + if(!G_ValidateMap(&gameEpisode, &gameMap)) + { + Uri *validMapUri = G_ComposeMapUri(gameEpisode, gameMap); + Uri_Copy(gameMapUri, validMapUri); + Uri_Delete(validMapUri); + } + + // Update game status cvars: + gsvMap = (unsigned)gameMap; + gsvEpisode = (unsigned)gameEpisode; + G_ApplyNewGameRules(); M_ResetRandom(); @@ -3035,7 +3075,7 @@ void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rule dd_bool showBrief; ddfinale_t fin; - p.mapUri = G_CurrentMapUri(); + p.mapUri = gameMapUri; p.revisit = false; showBrief = G_BriefingEnabled(p.mapUri, &fin); @@ -3059,10 +3099,9 @@ void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rule HU_WakeWidgets(-1 /* all players */); G_BeginMap(); } - - Z_CheckHeap(); - Uri_Delete(p.mapUri); } + + Z_CheckHeap(); } int G_QuitGameResponse(msgresponse_t response, int userValue, void* userPointer) @@ -3151,11 +3190,6 @@ Uri *G_ComposeMapUri(uint episode, uint map) return Uri_NewWithPath2(mapId, RC_NULL); } -Uri *G_CurrentMapUri(void) -{ - return G_ComposeMapUri(gameEpisode, gameMap); -} - dd_bool G_ValidateMap(uint *episode, uint *map) { dd_bool ok = true; @@ -3967,6 +4001,7 @@ D_CMD(WarpMap) // Hexen map numbers require translation. map = P_TranslateMapIfExists(map); #endif + if(!G_ValidateMap(&epsd, &map)) { char const *fmtString = argc == 3? "Unknown map \"%s, %s\"." : "Unknown map \"%s%s\"."; @@ -4001,19 +4036,24 @@ D_CMD(WarpMap) // So be it. briefDisabled = true; - if(!forceNewGameSession && gameInProgress) + { + Uri *newMapUri = G_ComposeMapUri(epsd, map); + if(!forceNewGameSession && gameInProgress) + { #if __JHEXEN__ - nextMap = map; - nextMapEntrance = 0; - G_SetGameAction(GA_LEAVEMAP); + nextMap = map; + nextMapEntrance = 0; + G_SetGameAction(GA_LEAVEMAP); #else - G_DeferredNewGame(epsd, map, 0/*default*/, &gameRules); + G_DeferredNewGame(newMapUri, 0/*default*/, &gameRules); #endif - } - else - { - G_DeferredNewGame(epsd, map, 0/*default*/, &gameRules); + } + else + { + G_DeferredNewGame(newMapUri, 0/*default*/, &gameRules); + } + Uri_Delete(newMapUri); } // If the command source was "us" the game library then it was probably in diff --git a/doomsday/plugins/common/src/g_update.c b/doomsday/plugins/common/src/g_update.c index 83bc4738b8..09555922de 100644 --- a/doomsday/plugins/common/src/g_update.c +++ b/doomsday/plugins/common/src/g_update.c @@ -132,11 +132,7 @@ void G_UpdateState(int step) #endif #if __JDOOM__ || __JHERETIC__ || __JDOOM64__ - { - Uri *mapUri = G_CurrentMapUri(); - S_MapMusic(mapUri); - Uri_Delete(mapUri); - } + S_MapMusic(0/*current map*/); #endif break; diff --git a/doomsday/plugins/common/src/hu_menu.c b/doomsday/plugins/common/src/hu_menu.c index 556687a0fe..cb0a9a45e2 100644 --- a/doomsday/plugins/common/src/hu_menu.c +++ b/doomsday/plugins/common/src/hu_menu.c @@ -6442,6 +6442,7 @@ int Hu_MenuConfirmInitNewGame(msgresponse_t response, int userValue, void* userP void Hu_MenuInitNewGame(dd_bool confirmed) { GameRuleset newRules = gameRules; + Uri *newMapUri = 0; #if __JDOOM__ if(!confirmed && SM_NIGHTMARE == mnSkillmode) @@ -6459,10 +6460,13 @@ void Hu_MenuInitNewGame(dd_bool confirmed) newRules.skill = mnSkillmode; #if __JHEXEN__ - G_DeferredNewGame(mnEpisode, P_TranslateMap(0), 0/*default*/, &newRules); + newMapUri = G_ComposeMapUri(mnEpisode, P_TranslateMap(0)); #else - G_DeferredNewGame(mnEpisode, 0, 0/*default*/, &newRules); + newMapUri = G_ComposeMapUri(mnEpisode, 0); #endif + + G_DeferredNewGame(newMapUri, 0/*default*/, &newRules); + Uri_Delete(newMapUri); } int Hu_MenuActionInitNewGame(mn_object_t* ob, mn_actionid_t action, void* parameters) diff --git a/doomsday/plugins/common/src/hu_stuff.cpp b/doomsday/plugins/common/src/hu_stuff.cpp index cc5908cdac..b932a4237a 100644 --- a/doomsday/plugins/common/src/hu_stuff.cpp +++ b/doomsday/plugins/common/src/hu_stuff.cpp @@ -751,7 +751,7 @@ static void drawMapMetaData(float x, float y, float alpha) { #define BORDER 2 - char const *title = P_CurrentMapTitle(); + char const *title = P_MapTitle(0/*current map*/); if(!title) title = "Unnamed"; char buf[256]; @@ -1482,7 +1482,7 @@ int Hu_MapTitleFirstLineHeight(void) dd_bool Hu_IsMapTitleAuthorVisible(void) { - char const *author = P_CurrentMapAuthor(cfg.hideIWADAuthor); + char const *author = P_MapAuthor(0/*current map*/, cfg.hideIWADAuthor); return author != 0 && (actualMapTime <= 6 * TICSPERSEC); } @@ -1501,8 +1501,8 @@ int Hu_MapTitleHeight(void) void Hu_DrawMapTitle(float alpha, dd_bool mapIdInsteadOfAuthor) { - char const *title = P_CurrentMapTitle(); - char const *author = P_CurrentMapAuthor(cfg.hideIWADAuthor); + char const *title = P_MapTitle(0/*current map*/); + char const *author = P_MapAuthor(0/*current map*/, cfg.hideIWADAuthor); float y = 0; @@ -1530,15 +1530,13 @@ void Hu_DrawMapTitle(float alpha, dd_bool mapIdInsteadOfAuthor) if(mapIdInsteadOfAuthor) { - Uri *mapUri = G_CurrentMapUri(); FR_SetFont(FID(GF_FONTA)); #if defined(__JHERETIC__) || defined(__JHEXEN__) FR_SetColorAndAlpha(.85f, .85f, .85f, alpha); #else FR_SetColorAndAlpha(.6f, .6f, .6f, alpha); #endif - FR_DrawTextXY3(Str_Text(Uri_ToString(mapUri)), 0, y, ALIGN_TOP, DTF_ONLY_SHADOW); - Uri_Delete(mapUri); + FR_DrawTextXY3(Str_Text(Uri_ToString(gameMapUri)), 0, y, ALIGN_TOP, DTF_ONLY_SHADOW); } else if(author) { diff --git a/doomsday/plugins/common/src/p_mapsetup.cpp b/doomsday/plugins/common/src/p_mapsetup.cpp index ac96d6b3b3..989f08b074 100644 --- a/doomsday/plugins/common/src/p_mapsetup.cpp +++ b/doomsday/plugins/common/src/p_mapsetup.cpp @@ -1044,7 +1044,8 @@ static void P_ResetWorldState() char const *P_MapTitle(Uri const *mapUri) { - DENG_ASSERT(mapUri != 0); + if(!mapUri) mapUri = gameMapUri; + char const *title = 0; // Perhaps a MapInfo definition exists for the map? @@ -1095,16 +1096,16 @@ char const *P_MapTitle(Uri const *mapUri) char const *P_MapAuthor(Uri const *mapUri, dd_bool supressGameAuthor) { - char const *author = 0; - - AutoStr *path = mapUri? Uri_Resolved(mapUri) : 0; + if(!mapUri) mapUri = gameMapUri; + AutoStr *path = Uri_Resolved(mapUri); if(!path || Str_IsEmpty(path)) return 0; // Perhaps a MapInfo definition exists for the map? ddmapinfo_t mapInfo; - if(Def_Get(DD_DEF_MAP_INFO, Str_Text(Uri_Compose(mapUri)), &mapInfo)) + char const *author = 0; + if(Def_Get(DD_DEF_MAP_INFO, Str_Text(path), &mapInfo)) { author = mapInfo.author; } @@ -1125,22 +1126,6 @@ char const *P_MapAuthor(Uri const *mapUri, dd_bool supressGameAuthor) return author; } -char const *P_CurrentMapTitle() -{ - Uri *mapUri = G_CurrentMapUri(); - char const *title = P_MapTitle(mapUri); - Uri_Delete(mapUri); - return title; -} - -char const *P_CurrentMapAuthor(dd_bool supressGameAuthor) -{ - Uri *mapUri = G_CurrentMapUri(); - char const *author = P_MapAuthor(mapUri, supressGameAuthor); - Uri_Delete(mapUri); - return author; -} - patchid_t P_MapTitlePatch(uint episode, uint map) { #if __JDOOM__ || __JDOOM64__ diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index a6f0fe2ff1..39c4f00f97 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -3689,7 +3689,7 @@ static int SV_LoadState(Str const *path, SaveInfo *info) * Load the map and configure some game settings. */ briefDisabled = true; - G_NewGame(info->episode(), info->map(), 0/*not saved??*/, &info->gameRules()); + G_NewGame(info->mapUri(), 0/*not saved??*/, &info->gameRules()); #if !__JHEXEN__ mapTime = info->mapTime(); @@ -4000,9 +4000,9 @@ void SV_LoadGameClient(uint gameId) } // Do we need to change the map? - if(gameMap != saveInfo->map() || gameEpisode != saveInfo->episode()) + if(!Uri_Equality(gameMapUri, saveInfo->mapUri())) { - G_NewGame(saveInfo->episode(), saveInfo->map(), 0/*default*/, &saveInfo->gameRules()); + G_NewGame(saveInfo->mapUri(), 0/*default*/, &saveInfo->gameRules()); /// @todo Necessary? G_SetGameAction(GA_NONE); } diff --git a/doomsday/plugins/common/src/p_sound.cpp b/doomsday/plugins/common/src/p_sound.cpp index eaff6e6ae0..3ea829702f 100644 --- a/doomsday/plugins/common/src/p_sound.cpp +++ b/doomsday/plugins/common/src/p_sound.cpp @@ -32,7 +32,7 @@ void S_MapMusic(Uri const *mapUri) { - DENG_ASSERT(mapUri != 0); + if(!mapUri) mapUri = gameMapUri; #ifdef __JHEXEN__ mapinfo_t const *mapInfo = P_MapInfo(mapUri); diff --git a/doomsday/plugins/doom/include/g_game.h b/doomsday/plugins/doom/include/g_game.h index 92aac3ac9c..acb8c5598f 100644 --- a/doomsday/plugins/doom/include/g_game.h +++ b/doomsday/plugins/doom/include/g_game.h @@ -51,6 +51,7 @@ extern player_t players[MAXPLAYERS]; extern dd_bool gameInProgress; extern uint gameEpisode; extern uint gameMap; +extern Uri *gameMapUri; extern uint gameMapEntrance; extern GameRuleset gameRules; diff --git a/doomsday/plugins/doom/src/d_main.c b/doomsday/plugins/doom/src/d_main.c index 10b3777c48..cc0292b384 100644 --- a/doomsday/plugins/doom/src/d_main.c +++ b/doomsday/plugins/doom/src/d_main.c @@ -63,10 +63,6 @@ char* borderGraphics[] = { "BRDR_BL" // Bottom left. }; -static uint startEpisode; -static uint startMap; -static dd_bool autoStart; - /** * Get a 32-bit integer value. */ @@ -408,8 +404,9 @@ void D_PreInit(void) */ void D_PostInit(void) { - AutoStr* path; - Uri* uri; + dd_bool autoStart = false; + Uri *startMapUri = 0; + AutoStr *path; int p; /// @todo Kludge: Border background is different in DOOM2. @@ -433,9 +430,6 @@ void D_PostInit(void) // Get skill / episode / map from parms. gameRules.skill = /*startSkill =*/ SM_MEDIUM; - startEpisode = 0; - startMap = 0; - autoStart = false; if(CommandLine_Check("-altdeath")) cfg.netDeathmatch = 2; @@ -487,15 +481,17 @@ void D_PostInit(void) p = CommandLine_Check("-skill"); if(p && p < myargc - 1) { - gameRules.skill = CommandLine_At(p + 1)[0] - '1'; + int skillNumber = atoi(CommandLine_At(p + 1)); + gameRules.skill = (skillmode_t)(skillNumber > 0? skillNumber - 1 : skillNumber); autoStart = true; } p = CommandLine_Check("-episode"); if(p && p < myargc - 1) { - startEpisode = CommandLine_At(p + 1)[0] - '1'; - startMap = 0; + int episodeNumber = atoi(CommandLine_At(p + 1)); + + startMapUri = G_ComposeMapUri(episodeNumber > 0? episodeNumber - 1 : episodeNumber, 0); autoStart = true; } @@ -504,44 +500,47 @@ void D_PostInit(void) { if(gameModeBits & (GM_ANY_DOOM2|GM_DOOM_CHEX)) { - startMap = atoi(CommandLine_At(p + 1)) - 1; + int mapNumber = atoi(CommandLine_At(p + 1)); + + startMapUri = G_ComposeMapUri(0, mapNumber > 0? mapNumber - 1 : mapNumber); autoStart = true; } else if(p < myargc - 2) { - startEpisode = CommandLine_At(p + 1)[0] - '1'; - startMap = CommandLine_At(p + 2)[0] - '1'; + int episodeNumber = atoi(CommandLine_At(p + 1)); + int mapNumber = atoi(CommandLine_At(p + 2)); + + startMapUri = G_ComposeMapUri(episodeNumber > 0? episodeNumber - 1 : episodeNumber, + mapNumber > 0? mapNumber - 1 : mapNumber); autoStart = true; } } - // Are we autostarting? - if(autoStart) + if(!startMapUri) { - if(gameModeBits & (GM_ANY_DOOM2|GM_DOOM_CHEX)) - App_Log(DE2_LOG_NOTE, "Autostart in Map %d, Skill %d", startMap+1, gameRules.skill); - else - App_Log(DE2_LOG_NOTE, "Autostart in Episode %d, Map %d, Skill %d", startEpisode+1, startMap+1, gameRules.skill); + startMapUri = G_ComposeMapUri(0, 0); } - // Validate episode and map. - uri = G_ComposeMapUri((gameModeBits & (GM_DOOM|GM_DOOM_SHAREWARE|GM_DOOM_ULTIMATE))? startEpisode : 0, startMap); - path = Uri_Compose(uri); - if((autoStart || IS_NETGAME) && !P_MapExists(Str_Text(path))) + // Are we autostarting? + if(autoStart) { - startEpisode = 0; - startMap = 0; + App_Log(DE2_LOG_NOTE, "Autostart in Map %s, Skill %d", + F_PrettyPath(Str_Text(Uri_ToString(startMapUri))), + gameRules.skill); } - Uri_Delete(uri); - if(autoStart || IS_NETGAME) + // Validate episode and map. + path = Uri_Compose(startMapUri); + if((autoStart || IS_NETGAME) && P_MapExists(Str_Text(path))) { - G_DeferredNewGame(startEpisode, startMap, 0/*default*/, &gameRules); + G_DeferredNewGame(startMapUri, 0/*default*/, &gameRules); } else { G_StartTitle(); // Start up intro loop. } + + Uri_Delete(startMapUri); } void D_Shutdown(void) diff --git a/doomsday/plugins/doom/src/m_cheat.c b/doomsday/plugins/doom/src/m_cheat.c index bd19ac7f80..53bd9e156d 100644 --- a/doomsday/plugins/doom/src/m_cheat.c +++ b/doomsday/plugins/doom/src/m_cheat.c @@ -669,36 +669,37 @@ D_CMD(CheatWhere) player_t *plr = &players[CONSOLEPLAYER]; char textBuffer[256]; Sector *sector; - AutoStr *path, *mapPath; - Uri *uri, *mapUri; + mobj_t *plrMo; + Uri *matUri; - if(G_GameState() != GS_MAP || !plr->plr->mo) + if(G_GameState() != GS_MAP) return true; - mapUri = G_CurrentMapUri(); - mapPath = Uri_ToString(mapUri); + plrMo = plr->plr->mo; + if(!plrMo) return true; + sprintf(textBuffer, "MAP [%s] X:%g Y:%g Z:%g", - Str_Text(mapPath), plr->plr->mo->origin[VX], plr->plr->mo->origin[VY], - plr->plr->mo->origin[VZ]); + Str_Text(Uri_ToString(gameMapUri)), + plrMo->origin[VX], plrMo->origin[VY], plrMo->origin[VZ]); P_SetMessage(plr, LMF_NO_HIDE, textBuffer); - Uri_Delete(mapUri); // Also print some information to the console. App_Log(DE2_MAP_NOTE, "%s", textBuffer); - sector = Mobj_Sector(plr->plr->mo); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + sector = Mobj_Sector(plrMo); + + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); + App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", + P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); + App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", + P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); App_Log(DE2_MAP_MSG, "Player height:%g Player radius:%g", - plr->plr->mo->height, plr->plr->mo->radius); + plrMo->height, plrMo->radius); return true; } diff --git a/doomsday/plugins/doom/src/p_oldsvg.cpp b/doomsday/plugins/doom/src/p_oldsvg.cpp index f929cc3bb3..ad947bd74e 100644 --- a/doomsday/plugins/doom/src/p_oldsvg.cpp +++ b/doomsday/plugins/doom/src/p_oldsvg.cpp @@ -846,7 +846,7 @@ int SV_LoadState_Dm_v19(Str const *path, SaveInfo *info) briefDisabled = true; // Load a base map. - G_NewGame(info->episode(), info->map(), 0/*not saved??*/, &info->gameRules()); + G_NewGame(info->mapUri(), 0/*not saved??*/, &info->gameRules()); // Recreate map state. mapTime = info->mapTime(); diff --git a/doomsday/plugins/doom/src/wi_stuff.c b/doomsday/plugins/doom/src/wi_stuff.c index 231ec33f51..aec68cdf7e 100644 --- a/doomsday/plugins/doom/src/wi_stuff.c +++ b/doomsday/plugins/doom/src/wi_stuff.c @@ -275,7 +275,7 @@ static void drawFinishedTitle(void) else mapNum = (wbs->episode * 9) + wbs->currentMap; - mapTitle = P_CurrentMapTitle(); + mapTitle = P_MapTitle(0/*current map*/); DGL_Enable(DGL_TEXTURE_2D); DGL_Color4f(1, 1, 1, 1); diff --git a/doomsday/plugins/doom64/include/g_game.h b/doomsday/plugins/doom64/include/g_game.h index 0979b986a1..40d083a731 100644 --- a/doomsday/plugins/doom64/include/g_game.h +++ b/doomsday/plugins/doom64/include/g_game.h @@ -52,6 +52,7 @@ extern uint nextMap; extern dd_bool gameInProgress; extern uint gameEpisode; extern uint gameMap; +extern Uri *gameMapUri; extern uint gameMapEntrance; extern GameRuleset gameRules; diff --git a/doomsday/plugins/doom64/src/d_main.c b/doomsday/plugins/doom64/src/d_main.c index 4b24c0461b..5c953df16d 100644 --- a/doomsday/plugins/doom64/src/d_main.c +++ b/doomsday/plugins/doom64/src/d_main.c @@ -35,14 +35,6 @@ #include "p_map.h" int verbose; - -//dd_bool devParm; // checkparm of -devparm -//dd_bool noMonstersParm; // checkparm of -nomonsters -//dd_bool respawnParm; // checkparm of -respawn -//dd_bool fastParm; // checkparm of -fast -//dd_bool turboParm; // checkparm of -turbo -//dd_bool randomClassParm; // checkparm of -randclass - float turboMul; // Multiplier for turbo. gamemode_t gameMode; @@ -54,7 +46,7 @@ float const defFontRGB2[] = { .85f, 0, 0 }; // The patches used in drawing the view border. // Percent-encoded. -char* borderGraphics[] = { +char *borderGraphics[] = { "Flats:FTILEABC", // Background. "BRDR_T", // Top. "BRDR_R", // Right. @@ -66,10 +58,6 @@ char* borderGraphics[] = { "BRDR_BL" // Bottom left. }; -static uint startEpisode; -static uint startMap; -static dd_bool autoStart; - /** * Get a 32-bit integer value. */ @@ -325,8 +313,9 @@ void D_PreInit(void) */ void D_PostInit(void) { + dd_bool autoStart = false; + Uri *startMapUri = 0; AutoStr *path; - Uri *uri; int p; // Common post init routine. @@ -343,9 +332,6 @@ void D_PostInit(void) // Get skill / episode / map from parms. gameRules.skill = /*startSkill =*/ SM_MEDIUM; - startEpisode = 0; - startMap = 0; - autoStart = false; // Game mode specific settings // None. @@ -400,42 +386,45 @@ void D_PostInit(void) p = CommandLine_Check("-skill"); if(p && p < myargc - 1) { - gameRules.skill = CommandLine_At(p + 1)[0] - '1'; + int skillNumber = atoi(CommandLine_At(p + 1)); + gameRules.skill = (skillmode_t)(skillNumber > 0? skillNumber - 1 : skillNumber); autoStart = true; } p = CommandLine_Check("-warp"); if(p && p < myargc - 1) { - startMap = atoi(CommandLine_At(p + 1)) - '1'; + int mapNumber = atoi(CommandLine_At(p + 1)); + + startMapUri = G_ComposeMapUri(0, mapNumber > 0? mapNumber - 1 : mapNumber); autoStart = true; } - // Are we autostarting? - if(autoStart) + if(!startMapUri) { - App_Log(DE2_LOG_NOTE, "Warp to Episode %d, Map %d, Skill %d", startEpisode+1, - startMap+1, gameRules.skill); + startMapUri = G_ComposeMapUri(0, 0); } - // Validate episode and map. - uri = G_ComposeMapUri(0, startMap); - path = Uri_Compose(uri); - if((autoStart || IS_NETGAME) && !P_MapExists(Str_Text(path))) + // Are we autostarting? + if(autoStart) { - startEpisode = 0; - startMap = 0; + App_Log(DE2_LOG_NOTE, "Autostart in Map %s, Skill %d", + F_PrettyPath(Str_Text(Uri_ToString(startMapUri))), + gameRules.skill); } - Uri_Delete(uri); - if(autoStart || IS_NETGAME) + // Validate episode and map. + path = Uri_Compose(startMapUri); + if((autoStart || IS_NETGAME) && P_MapExists(Str_Text(path))) { - G_DeferredNewGame(startEpisode, startMap, 0/*default*/, &gameRules); + G_DeferredNewGame(startMapUri, 0/*default*/, &gameRules); } else { G_StartTitle(); // Start up intro loop. } + + Uri_Delete(startMapUri); } void D_Shutdown(void) diff --git a/doomsday/plugins/doom64/src/m_cheat.c b/doomsday/plugins/doom64/src/m_cheat.c index 5b2f0bf95a..bf1b626637 100644 --- a/doomsday/plugins/doom64/src/m_cheat.c +++ b/doomsday/plugins/doom64/src/m_cheat.c @@ -185,35 +185,39 @@ void printDebugInfo(player_t *plr) { char textBuffer[256]; Sector *sector; - AutoStr *path, *mapPath; - Uri *uri, *mapUri; + mobj_t *plrMo; + Uri *matUri; - if(G_GameState() != GS_MAP || !plr->plr->mo) + DENG_ASSERT(plr != 0); + + if(G_GameState() != GS_MAP) return; - mapUri = G_CurrentMapUri(); - mapPath = Uri_ToString(mapUri); + plrMo = plr->plr->mo; + if(!plrMo) return; + sprintf(textBuffer, "MAP [%s] X:%g Y:%g Z:%g", - Str_Text(mapPath), plr->plr->mo->origin[VX], plr->plr->mo->origin[VY], - plr->plr->mo->origin[VZ]); + Str_Text(Uri_ToString(gameMapUri)), + plrMo->origin[VX], plrMo->origin[VY], plrMo->origin[VZ]); P_SetMessage(plr, LMF_NO_HIDE, textBuffer); - Uri_Delete(mapUri); // Also print some information to the console. App_Log(DE2_MAP_NOTE, "%s", textBuffer); - sector = Mobj_Sector(plr->plr->mo); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + sector = Mobj_Sector(plrMo); + + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); + App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", + P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); + App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", + P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); - App_Log(DE2_MAP_MSG, "Player height:%g Player radius:%g", plr->plr->mo->height, plr->plr->mo->radius); + App_Log(DE2_MAP_MSG, "Player height:%g Player radius:%g", + plrMo->height, plrMo->radius); } /** diff --git a/doomsday/plugins/doom64/src/wi_stuff.c b/doomsday/plugins/doom64/src/wi_stuff.c index 965037937a..baf7192b3c 100644 --- a/doomsday/plugins/doom64/src/wi_stuff.c +++ b/doomsday/plugins/doom64/src/wi_stuff.c @@ -122,7 +122,7 @@ static void drawFinishedTitle(void) { int x = SCREENWIDTH/2, y = WI_TITLEY; uint mapNum = wbs->currentMap; - char const *mapTitle = P_CurrentMapTitle(); + char const *mapTitle = P_MapTitle(0/*current map*/); patchid_t patchId; patchinfo_t info; diff --git a/doomsday/plugins/heretic/include/g_game.h b/doomsday/plugins/heretic/include/g_game.h index 6be1ac8f61..7c267e151b 100644 --- a/doomsday/plugins/heretic/include/g_game.h +++ b/doomsday/plugins/heretic/include/g_game.h @@ -51,6 +51,7 @@ extern player_t players[MAXPLAYERS]; extern dd_bool gameInProgress; extern uint gameEpisode; extern uint gameMap; +extern Uri *gameMapUri; extern uint gameMapEntrance; extern GameRuleset gameRules; diff --git a/doomsday/plugins/heretic/src/h_main.c b/doomsday/plugins/heretic/src/h_main.c index a26009b98a..a4aca3abe4 100644 --- a/doomsday/plugins/heretic/src/h_main.c +++ b/doomsday/plugins/heretic/src/h_main.c @@ -65,10 +65,6 @@ char* borderGraphics[] = { "BORDBL" // Bottom left. }; -static uint startEpisode; -static uint startMap; -static dd_bool autoStart; - /** * Get a 32-bit integer value. */ @@ -344,8 +340,9 @@ void H_PreInit(void) */ void H_PostInit(void) { - AutoStr* path; - Uri* uri; + dd_bool autoStart = false; + Uri *startMapUri = 0; + AutoStr *path; int p; /// @todo Kludge: Shareware WAD has different border background. @@ -366,9 +363,6 @@ void H_PostInit(void) // Defaults for skill, episode and map. gameRules.skill = /*startSkill =*/ SM_MEDIUM; - startEpisode = 0; - startMap = 0; - autoStart = false; // Game mode specific settings. /* None */ @@ -415,51 +409,56 @@ void H_PostInit(void) p = CommandLine_Check("-skill"); if(p && p < myargc - 1) { - gameRules.skill = CommandLine_At(p + 1)[0] - '1'; + int skillNumber = atoi(CommandLine_At(p + 1)); + gameRules.skill = (skillmode_t)(skillNumber > 0? skillNumber - 1 : skillNumber); autoStart = true; } p = CommandLine_Check("-episode"); if(p && p < myargc - 1) { - startEpisode = CommandLine_At(p + 1)[0] - '1'; - startMap = 0; + int episodeNumber = atoi(CommandLine_At(p + 1)); + + startMapUri = G_ComposeMapUri(episodeNumber > 0? episodeNumber - 1 : episodeNumber, 0); autoStart = true; } p = CommandLine_Check("-warp"); if(p && p < myargc - 2) { - startEpisode = CommandLine_At(p + 1)[0] - '1'; - startMap = CommandLine_At(p + 2)[0] - '1'; + int episodeNumber = atoi(CommandLine_At(p + 1)); + int mapNumber = atoi(CommandLine_At(p + 2)); + + startMapUri = G_ComposeMapUri(episodeNumber > 0? episodeNumber - 1 : episodeNumber, + mapNumber > 0? mapNumber - 1 : mapNumber); autoStart = true; } - // Are we autostarting? - if(autoStart) + if(!startMapUri) { - App_Log(DE2_LOG_NOTE, "Autostart in Episode %d, Map %d, Skill %d", - startEpisode + 1, startMap + 1, gameRules.skill + 1); + startMapUri = G_ComposeMapUri(0, 0); } - // Validate episode and map. - uri = G_ComposeMapUri(startEpisode, startMap); - path = Uri_Compose(uri); - if((autoStart || IS_NETGAME) && !P_MapExists(Str_Text(path))) + // Are we autostarting? + if(autoStart) { - startEpisode = 0; - startMap = 0; + App_Log(DE2_LOG_NOTE, "Autostart in Map %s, Skill %d", + F_PrettyPath(Str_Text(Uri_ToString(startMapUri))), + gameRules.skill); } - Uri_Delete(uri); - if(autoStart || IS_NETGAME) + // Validate episode and map. + path = Uri_Compose(startMapUri); + if((autoStart || IS_NETGAME) && P_MapExists(Str_Text(path))) { - G_DeferredNewGame(startEpisode, startMap, 0/*default*/, &gameRules); + G_DeferredNewGame(startMapUri, 0/*default*/, &gameRules); } else { G_StartTitle(); // Start up intro loop. } + + Uri_Delete(startMapUri); } void H_Shutdown(void) diff --git a/doomsday/plugins/heretic/src/m_cheat.c b/doomsday/plugins/heretic/src/m_cheat.c index 3c0f3f8f8d..5dadeccfb5 100644 --- a/doomsday/plugins/heretic/src/m_cheat.c +++ b/doomsday/plugins/heretic/src/m_cheat.c @@ -670,35 +670,37 @@ D_CMD(CheatWhere) player_t *plr = &players[CONSOLEPLAYER]; char textBuffer[256]; Sector *sector; - AutoStr *path, *mapPath; - Uri *uri, *mapUri; + mobj_t *plrMo; + Uri *matUri; - if(G_GameState() != GS_MAP || !plr->plr->mo) + if(G_GameState() != GS_MAP) return true; - mapUri = G_CurrentMapUri(); - mapPath = Uri_ToString(mapUri); + plrMo = plr->plr->mo; + if(!plrMo) return true; + sprintf(textBuffer, "MAP [%s] X:%g Y:%g Z:%g", - Str_Text(mapPath), plr->plr->mo->origin[VX], plr->plr->mo->origin[VY], - plr->plr->mo->origin[VZ]); + Str_Text(Uri_ToString(gameMapUri)), + plrMo->origin[VX], plrMo->origin[VY], plrMo->origin[VZ]); P_SetMessage(plr, LMF_NO_HIDE, textBuffer); - Uri_Delete(mapUri); - App_Log(DE2_MAP_NOTE, textBuffer); + // Also print some information to the console. + App_Log(DE2_MAP_NOTE, "%s", textBuffer); + + sector = Mobj_Sector(plrMo); - sector = Mobj_Sector(plr->plr->mo); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); + App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", + P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); + App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", + P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); App_Log(DE2_MAP_MSG, "Player height:%g Player radius:%g", - plr->plr->mo->height, plr->plr->mo->radius); + plrMo->height, plrMo->radius); return true; } diff --git a/doomsday/plugins/heretic/src/p_oldsvg.cpp b/doomsday/plugins/heretic/src/p_oldsvg.cpp index 64e0fa430f..01c2c7b9c4 100644 --- a/doomsday/plugins/heretic/src/p_oldsvg.cpp +++ b/doomsday/plugins/heretic/src/p_oldsvg.cpp @@ -866,7 +866,7 @@ int SV_LoadState_Hr_v13(Str const *path, SaveInfo *info) briefDisabled = true; // Load a base map. - G_NewGame(info->episode(), info->map(), 0/*not saved??*/, &info->gameRules()); + G_NewGame(info->mapUri(), 0/*not saved??*/, &info->gameRules()); // Recreate map state. mapTime = info->mapTime(); diff --git a/doomsday/plugins/hexen/include/g_game.h b/doomsday/plugins/hexen/include/g_game.h index 9917f93d2a..cd05d4a6ec 100644 --- a/doomsday/plugins/hexen/include/g_game.h +++ b/doomsday/plugins/hexen/include/g_game.h @@ -48,6 +48,7 @@ extern player_t players[MAXPLAYERS]; extern dd_bool gameInProgress; extern uint gameEpisode; extern uint gameMap; +extern Uri *gameMapUri; extern uint gameMapEntrance; extern GameRuleset gameRules; diff --git a/doomsday/plugins/hexen/include/p_mapinfo.h b/doomsday/plugins/hexen/include/p_mapinfo.h index c505df945c..5ac78a6fef 100644 --- a/doomsday/plugins/hexen/include/p_mapinfo.h +++ b/doomsday/plugins/hexen/include/p_mapinfo.h @@ -59,6 +59,11 @@ void MapInfoParser(Str const *path); */ mapinfo_t *P_MapInfo(Uri const *mapUri); +/** + * Returns MAPINFO data for the @em current map. + */ +mapinfo_t *P_CurrentMapInfo(void); + #define P_INVALID_LOGICAL_MAP 0xffffffff /** diff --git a/doomsday/plugins/hexen/src/acscript.cpp b/doomsday/plugins/hexen/src/acscript.cpp index d44e3322e2..9aca450da3 100644 --- a/doomsday/plugins/hexen/src/acscript.cpp +++ b/doomsday/plugins/hexen/src/acscript.cpp @@ -257,19 +257,16 @@ bool ACScriptInterpreter::startScript(int scriptNumber, Uri const *mapUri, byte const args[], mobj_t *activator, Line *line, int side) { DENG_ASSERT(!IS_CLIENT); + DENG_ASSERT(mapUri != 0); if(mapUri) { - Uri *currentMapUri = G_CurrentMapUri(); - if(!Uri_Equality(mapUri, currentMapUri)) + if(!Uri_Equality(gameMapUri, mapUri)) { - Uri_Delete(currentMapUri); - // Script is not for the current map. // Add it to the store to be started when that map is next entered. return newDeferredTask(mapUri, scriptNumber, args); } - Uri_Delete(currentMapUri); } if(BytecodeScriptInfo *info = scriptInfoPtr(scriptNumber)) diff --git a/doomsday/plugins/hexen/src/h2_main.c b/doomsday/plugins/hexen/src/h2_main.c index f7223ff917..5390ab3dfa 100644 --- a/doomsday/plugins/hexen/src/h2_main.c +++ b/doomsday/plugins/hexen/src/h2_main.c @@ -38,13 +38,6 @@ int verbose; -//dd_bool devParm; // checkparm of -devparm -//dd_bool noMonstersParm; // checkparm of -nomonsters -//dd_bool respawnParm; // checkparm of -respawn -//dd_bool fastParm; // checkparm of -fast -//dd_bool turboParm; // checkparm of -turbo -//dd_bool randomClassParm; // checkparm of -randclass - float turboMul; // Multiplier for turbo. gamemode_t gameMode; @@ -57,7 +50,7 @@ float const defFontRGB3[] = { .9f, .9f, .9f }; // The patches used in drawing the view border. // Percent-encoded. -char* borderGraphics[] = { +char *borderGraphics[] = { "Flats:F_022", // Background. "BORDT", // Top. "BORDR", // Right. @@ -69,11 +62,6 @@ char* borderGraphics[] = { "BORDBL" // Bottom left. }; -static dd_bool autoStart; -static uint startEpisode; -static uint startMap; -static playerclass_t startPlayerClass; - /** * Get a 32-bit integer value. */ @@ -318,9 +306,11 @@ void X_PreInit(void) */ void X_PostInit(void) { + dd_bool autoStart = false; + Uri *startMapUri = 0; + playerclass_t startPlayerClass = PCLASS_NONE; AutoStr *path; - int p, warpMap; - Uri *uri; + int p; // Do this early as other systems need to know. P_InitPlayerClassInfo(); @@ -336,10 +326,6 @@ void X_PostInit(void) // Defaults for skill, episode and map. gameRules.skill = /*startSkill =*/ SM_MEDIUM; - startEpisode = 0; - startMap = 0; - startPlayerClass = PCLASS_NONE; - autoStart = false; // Game mode specific settings. /* None */ @@ -395,7 +381,8 @@ void X_PostInit(void) if((p = CommandLine_CheckWith("-skill", 1)) != 0) { - gameRules.skill = (skillmode_t)(CommandLine_At(p + 1)[0] - '1'); + int skillNumber = atoi(CommandLine_At(p + 1)); + gameRules.skill = (skillmode_t)(skillNumber > 0? skillNumber - 1 : skillNumber); autoStart = true; } @@ -427,40 +414,38 @@ void X_PostInit(void) p = CommandLine_Check("-warp"); if(p && p < CommandLine_Count() - 1) { - warpMap = atoi(CommandLine_At(p + 1)) - 1; - startMap = P_TranslateMap(warpMap); + int warpMap = atoi(CommandLine_At(p + 1)); + + startMapUri = G_ComposeMapUri(0, P_TranslateMap(warpMap - 1)); autoStart = true; } - else + + if(!startMapUri) { - warpMap = 0; - startMap = P_TranslateMap(warpMap); + startMapUri = G_ComposeMapUri(0, P_TranslateMap(0)); } // Are we autostarting? if(autoStart) { - App_Log(DE2_LOG_NOTE, "Autostart in Map %d (%d), Skill %d", warpMap+1, startMap+1, gameRules.skill + 1); + App_Log(DE2_LOG_NOTE, "Autostart in Map %s, Skill %d", + F_PrettyPath(Str_Text(Uri_ToString(startMapUri))), + gameRules.skill); } // Validate episode and map. - uri = G_ComposeMapUri(0, startMap); - path = Uri_Compose(uri); - if((autoStart || IS_NETGAME) && !P_MapExists(Str_Text(path))) + path = Uri_Compose(startMapUri); + if((autoStart || IS_NETGAME) && P_MapExists(Str_Text(path))) { - startMap = 0; - } - Uri_Delete(uri); - - if(autoStart || IS_NETGAME) - { - G_DeferredNewGame(startEpisode, startMap, 0/*default*/, &gameRules); + G_DeferredNewGame(startMapUri, 0/*default*/, &gameRules); } else { // Start up intro loop. G_StartTitle(); } + + Uri_Delete(startMapUri); } void X_Shutdown(void) diff --git a/doomsday/plugins/hexen/src/m_cheat.c b/doomsday/plugins/hexen/src/m_cheat.c index 949fc16b35..076d5341fd 100644 --- a/doomsday/plugins/hexen/src/m_cheat.c +++ b/doomsday/plugins/hexen/src/m_cheat.c @@ -670,36 +670,37 @@ D_CMD(CheatWhere) player_t *plr = &players[CONSOLEPLAYER]; char textBuffer[256]; Sector *sector; - AutoStr *path, *mapPath; - Uri *uri, *mapUri; + mobj_t *plrMo; + Uri *matUri; - if(G_GameState() != GS_MAP || !plr->plr->mo) + if(G_GameState() != GS_MAP) return true; - mapUri = G_CurrentMapUri(); - mapPath = Uri_ToString(mapUri); - sprintf(textBuffer, "Map [%s] x:%g y:%g z:%g", - Str_Text(mapPath), plr->plr->mo->origin[VX], plr->plr->mo->origin[VY], - plr->plr->mo->origin[VZ]); + plrMo = plr->plr->mo; + if(!plrMo) return true; + + sprintf(textBuffer, "MAP [%s] X:%g Y:%g Z:%g", + Str_Text(Uri_ToString(gameMapUri)), + plrMo->origin[VX], plrMo->origin[VY], plrMo->origin[VZ]); P_SetMessage(plr, LMF_NO_HIDE, textBuffer); - Uri_Delete(mapUri); // Also print some information to the console. App_Log(DE2_MAP_NOTE, "%s", textBuffer); - sector = Mobj_Sector(plr->plr->mo); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + sector = Mobj_Sector(plrMo); + + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_FLOOR_MATERIAL)); + App_Log(DE2_MAP_MSG, "FloorZ:%g Material:%s", + P_GetDoublep(sector, DMU_FLOOR_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); - uri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); - path = Uri_ToString(uri); - App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(path)); - Uri_Delete(uri); + matUri = Materials_ComposeUri(P_GetIntp(sector, DMU_CEILING_MATERIAL)); + App_Log(DE2_MAP_MSG, "CeilingZ:%g Material:%s", + P_GetDoublep(sector, DMU_CEILING_HEIGHT), Str_Text(Uri_ToString(matUri))); + Uri_Delete(matUri); App_Log(DE2_MAP_MSG, "Player height:%g Player radius:%g", - plr->plr->mo->height, plr->plr->mo->radius); + plrMo->height, plrMo->radius); return true; } diff --git a/doomsday/plugins/hexen/src/p_mapinfo.cpp b/doomsday/plugins/hexen/src/p_mapinfo.cpp index 0e3e9a2e2d..ba8e20b9ca 100644 --- a/doomsday/plugins/hexen/src/p_mapinfo.cpp +++ b/doomsday/plugins/hexen/src/p_mapinfo.cpp @@ -255,6 +255,11 @@ mapinfo_t *P_MapInfo(Uri const *mapUri) return 0; } +mapinfo_t *P_CurrentMapInfo() +{ + return P_MapInfo(gameMapUri); +} + uint P_TranslateMapIfExists(uint map) { uint matchedWithoutCluster = P_INVALID_LOGICAL_MAP; diff --git a/doomsday/plugins/hexen/src/p_spec.c b/doomsday/plugins/hexen/src/p_spec.c index f226490bf4..3acb99af12 100644 --- a/doomsday/plugins/hexen/src/p_spec.c +++ b/doomsday/plugins/hexen/src/p_spec.c @@ -1072,9 +1072,7 @@ void P_ForceLightning(void) void P_InitLightning(void) { int i, secCount; - Uri *mapUri = G_CurrentMapUri(); - mapinfo_t const *mapInfo = P_MapInfo(mapUri); - Uri_Delete(mapUri); + mapinfo_t const *mapInfo = P_CurrentMapInfo(); if(!mapInfo || !mapInfo->lightning) { From 0dd755f5d8986a8f2c1d777eb1395b4af18eb8b2 Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 8 Feb 2014 23:38:52 +0000 Subject: [PATCH 02/15] libhexen: Cleanup --- doomsday/plugins/common/src/fi_lib.c | 2 +- doomsday/plugins/common/src/g_game.c | 8 ++++---- doomsday/plugins/hexen/include/p_mapinfo.h | 10 ++++------ doomsday/plugins/hexen/src/p_mapinfo.cpp | 8 ++------ doomsday/plugins/hexen/src/p_spec.c | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/doomsday/plugins/common/src/fi_lib.c b/doomsday/plugins/common/src/fi_lib.c index 54d7a5d9f3..6614ed48bd 100644 --- a/doomsday/plugins/common/src/fi_lib.c +++ b/doomsday/plugins/common/src/fi_lib.c @@ -105,7 +105,7 @@ static void initStateConditions(fi_state_t *s) { Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - mapinfo_t *curMapInfo = P_CurrentMapInfo(); + mapinfo_t *curMapInfo = P_MapInfo(0/*current map*/); mapinfo_t *nextMapInfo = P_MapInfo(nextMapUri); if(curMapInfo && nextMapInfo) { diff --git a/doomsday/plugins/common/src/g_game.c b/doomsday/plugins/common/src/g_game.c index 665b9667fb..718d3eb346 100644 --- a/doomsday/plugins/common/src/g_game.c +++ b/doomsday/plugins/common/src/g_game.c @@ -1155,7 +1155,7 @@ static void printMapBanner(void) { char buf[64]; #if __JHEXEN__ - mapinfo_t const *mapInfo = P_CurrentMapInfo(); + mapinfo_t const *mapInfo = P_MapInfo(0/*current map*/); int warpNum = (mapInfo? mapInfo->warpTrans : -1); dd_snprintf(buf, 64, "Map %u (%u): " DE2_ESC(b) "%s", warpNum + 1, gameMap + 1, title); #else @@ -1256,7 +1256,7 @@ static void initFogForMap(ddmapinfo_t *mapInfo) #if __JHEXEN__ { - mapinfo_t const *mapInfo = P_CurrentMapInfo(); + mapinfo_t const *mapInfo = P_MapInfo(0/*current map*/); if(mapInfo) { int fadeTable = mapInfo->fadeTable; @@ -1766,7 +1766,7 @@ void G_PlayerLeaveMap(int player) { Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - newCluster = (P_CurrentMapInfo()->cluster != P_MapInfo(nextMapUri)->cluster); + newCluster = (P_MapInfo(0/*current map*/)->cluster != P_MapInfo(nextMapUri)->cluster); Uri_Delete(nextMapUri); } @@ -2602,7 +2602,7 @@ void G_DoLeaveMap(void) // Same cluster? { Uri *nextMapUri = G_ComposeMapUri(gameEpisode, nextMap); - if(P_CurrentMapInfo()->cluster == P_MapInfo(nextMapUri)->cluster) + if(P_MapInfo(0/*current map*/)->cluster == P_MapInfo(nextMapUri)->cluster) { if(!gameRules.deathmatch) { diff --git a/doomsday/plugins/hexen/include/p_mapinfo.h b/doomsday/plugins/hexen/include/p_mapinfo.h index 5ac78a6fef..4a765ffda7 100644 --- a/doomsday/plugins/hexen/include/p_mapinfo.h +++ b/doomsday/plugins/hexen/include/p_mapinfo.h @@ -55,15 +55,13 @@ extern "C" { void MapInfoParser(Str const *path); /** - * Returns MAPINFO data for the specified @a mapUri; otherwise @c 0 (not found). + * @param mapUri Identifier of the map to lookup info for. Can be @c 0 in which + * case the info for the @em current map will be returned (if set). + * + * @return MAPINFO data for the specified @a mapUri; otherwise @c 0 (not found). */ mapinfo_t *P_MapInfo(Uri const *mapUri); -/** - * Returns MAPINFO data for the @em current map. - */ -mapinfo_t *P_CurrentMapInfo(void); - #define P_INVALID_LOGICAL_MAP 0xffffffff /** diff --git a/doomsday/plugins/hexen/src/p_mapinfo.cpp b/doomsday/plugins/hexen/src/p_mapinfo.cpp index ba8e20b9ca..3bb342928f 100644 --- a/doomsday/plugins/hexen/src/p_mapinfo.cpp +++ b/doomsday/plugins/hexen/src/p_mapinfo.cpp @@ -245,7 +245,8 @@ void MapInfoParser(Str const *path) mapinfo_t *P_MapInfo(Uri const *mapUri) { - DENG_ASSERT(mapUri != 0); + if(!mapUri) mapUri = gameMapUri; + std::string mapPath(Str_Text(Uri_Compose(mapUri))); MapInfos::iterator found = mapInfos.find(mapPath); if(found != mapInfos.end()) @@ -255,11 +256,6 @@ mapinfo_t *P_MapInfo(Uri const *mapUri) return 0; } -mapinfo_t *P_CurrentMapInfo() -{ - return P_MapInfo(gameMapUri); -} - uint P_TranslateMapIfExists(uint map) { uint matchedWithoutCluster = P_INVALID_LOGICAL_MAP; diff --git a/doomsday/plugins/hexen/src/p_spec.c b/doomsday/plugins/hexen/src/p_spec.c index 3acb99af12..96e7ed628f 100644 --- a/doomsday/plugins/hexen/src/p_spec.c +++ b/doomsday/plugins/hexen/src/p_spec.c @@ -1072,7 +1072,7 @@ void P_ForceLightning(void) void P_InitLightning(void) { int i, secCount; - mapinfo_t const *mapInfo = P_CurrentMapInfo(); + mapinfo_t const *mapInfo = P_MapInfo(0/*current map*/); if(!mapInfo || !mapInfo->lightning) { From 732e088b01a47ab813d4ac9bf0212c36befe298c Mon Sep 17 00:00:00 2001 From: danij Date: Sat, 8 Feb 2014 23:44:54 +0000 Subject: [PATCH 03/15] libcommon|SaveInfo: Removed unused map() and episode() methods of SaveInfo --- doomsday/plugins/common/include/saveinfo.h | 4 +--- doomsday/plugins/common/src/saveinfo.cpp | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/doomsday/plugins/common/include/saveinfo.h b/doomsday/plugins/common/include/saveinfo.h index fca01947d2..890dae4436 100644 --- a/doomsday/plugins/common/include/saveinfo.h +++ b/doomsday/plugins/common/include/saveinfo.h @@ -118,13 +118,11 @@ class SaveInfo public: /// @todo refactor away: int magic() const; - uint episode() const; - uint map() const; }; #endif // __cplusplus -// C wrapper API, for legacy modules ------------------------------------------- +// C wrapper API --------------------------------------------------------------- #ifdef __cplusplus extern "C" { diff --git a/doomsday/plugins/common/src/saveinfo.cpp b/doomsday/plugins/common/src/saveinfo.cpp index 44f79e6b39..f1ea10f874 100644 --- a/doomsday/plugins/common/src/saveinfo.cpp +++ b/doomsday/plugins/common/src/saveinfo.cpp @@ -164,16 +164,6 @@ void SaveInfo::setGameId(uint newGameId) _gameId = newGameId; } -uint SaveInfo::episode() const -{ - return _episode; -} - -uint SaveInfo::map() const -{ - return _map; -} - Uri const *SaveInfo::mapUri() const { return _mapUri; @@ -397,6 +387,8 @@ void SaveInfo::read_Hx_v9(Reader *reader) } #endif +// C wrapper API --------------------------------------------------------------- + SaveInfo *SaveInfo_New() { return new SaveInfo; From 2bec63162817390a4851c84956683be0fa1b8ca9 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 01:51:35 +0000 Subject: [PATCH 04/15] libcommon|SaveInfo: Saved games now record the current map as a URI As the save version number has already been bumped to v14 for the Doomsday 1.14 release, saved games made with unstable builds 1131, 1132 and 1133 will NOT be loadable. --- doomsday/plugins/common/include/saveinfo.h | 4 +-- doomsday/plugins/common/src/saveinfo.cpp | 42 ++++++++-------------- doomsday/plugins/doom/src/p_oldsvg.cpp | 9 ++--- doomsday/plugins/heretic/src/p_oldsvg.cpp | 9 ++--- 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/doomsday/plugins/common/include/saveinfo.h b/doomsday/plugins/common/include/saveinfo.h index 890dae4436..aff5f54721 100644 --- a/doomsday/plugins/common/include/saveinfo.h +++ b/doomsday/plugins/common/include/saveinfo.h @@ -36,9 +36,7 @@ class SaveInfo int _magic; int _version; gamemode_t _gameMode; - uint _episode; - uint _map; - Uri *_mapUri; ///< Not currently saved. + Uri *_mapUri; #if !__JHEXEN__ int _mapTime; byte _players[MAXPLAYERS]; diff --git a/doomsday/plugins/common/src/saveinfo.cpp b/doomsday/plugins/common/src/saveinfo.cpp index f1ea10f874..cba37da98c 100644 --- a/doomsday/plugins/common/src/saveinfo.cpp +++ b/doomsday/plugins/common/src/saveinfo.cpp @@ -77,8 +77,6 @@ SaveInfo::SaveInfo() , _magic (0) , _version (0) , _gameMode(NUM_GAME_MODES) - , _episode (0) - , _map (0) , _mapUri (Uri_New()) #if !__JHEXEN__ , _mapTime (0) @@ -96,8 +94,6 @@ SaveInfo::SaveInfo(SaveInfo const &other) , _magic (other._magic) , _version (other._version) , _gameMode(other._gameMode) - , _episode (other._episode) - , _map (other._map) #if !__JHEXEN__ , _mapTime (other._mapTime) #endif @@ -123,8 +119,6 @@ SaveInfo &SaveInfo::operator = (SaveInfo const &other) _magic = other._magic; _version = other._version; _gameMode = other._gameMode; - _episode = other._episode; - _map = other._map; Uri_Copy(_mapUri, other._mapUri); #if !__JHEXEN__ _mapTime = other._mapTime; @@ -186,9 +180,7 @@ void SaveInfo::applyCurrentSessionMetadata() _magic = IS_NETWORK_CLIENT? MY_CLIENT_SAVE_MAGIC : MY_SAVE_MAGIC; _version = MY_SAVE_VERSION; _gameMode = gameMode; - _episode = gameEpisode; - _map = gameMap; - Uri_Copy(_mapUri, G_ComposeMapUri(_episode, _map)); + Uri_Copy(_mapUri, gameMapUri); #if !__JHEXEN__ _mapTime = ::mapTime; #endif @@ -221,8 +213,7 @@ void SaveInfo::write(Writer *writer) const Writer_WriteInt32(writer, _gameMode); Str_Write(&_description, writer); - Writer_WriteByte(writer, _episode); - Writer_WriteByte(writer, _map); + Uri_Write(_mapUri, writer); #if !__JHEXEN__ Writer_WriteInt32(writer, _mapTime); #endif @@ -250,21 +241,15 @@ void SaveInfo::read(Reader *reader) } else { - // Older formats use a fixed-length name (24 characters). -#define OLD_NAME_LENGTH 24 - - char buf[OLD_NAME_LENGTH]; - Reader_Read(reader, buf, OLD_NAME_LENGTH); + // Description is a fixed 24 characters in length. + char buf[24 + 1]; + Reader_Read(reader, buf, 24); buf[24] = 0; Str_Set(&_description, buf); - -#undef OLD_NAME_LENGTH } if(_version >= 14) { - _episode = Reader_ReadByte(reader); - _map = Reader_ReadByte(reader); - Uri_Copy(_mapUri, G_ComposeMapUri(_episode, _map)); + Uri_Read(_mapUri, reader); #if !__JHEXEN__ _mapTime = Reader_ReadInt32(reader); #endif @@ -305,9 +290,9 @@ void SaveInfo::read(Reader *reader) _gameRules.skill = SM_NOTHINGS; } - _episode = Reader_ReadByte(reader) - 1; - _map = Reader_ReadByte(reader) - 1; - Uri_Copy(_mapUri, G_ComposeMapUri(_episode, _map)); + uint episode = Reader_ReadByte(reader) - 1; + uint map = Reader_ReadByte(reader) - 1; + Uri_Copy(_mapUri, G_ComposeMapUri(episode, map)); _gameRules.deathmatch = Reader_ReadByte(reader); #if !__JHEXEN__ @@ -365,15 +350,16 @@ void SaveInfo::read_Hx_v9(Reader *reader) _magic = MY_SAVE_MAGIC; // Lets pretend... _gameMode = gameMode; // Assume the current mode. - _episode = 0; - _map = Reader_ReadByte(reader) - 1; - Uri_Copy(_mapUri, G_ComposeMapUri(_episode, _map)); + uint episode = 0; + uint map = Reader_ReadByte(reader) - 1; + Uri_Copy(_mapUri, G_ComposeMapUri(episode, map)); _gameRules.skill = (skillmode_t) (Reader_ReadByte(reader) & 0x7f); - // Interpret skill modes outside the normal range as "spawn no things". if(_gameRules.skill < SM_BABY || _gameRules.skill >= NUM_SKILL_MODES) + { _gameRules.skill = SM_NOTHINGS; + } _gameRules.deathmatch = Reader_ReadByte(reader); _gameRules.noMonsters = Reader_ReadByte(reader); diff --git a/doomsday/plugins/doom/src/p_oldsvg.cpp b/doomsday/plugins/doom/src/p_oldsvg.cpp index ad947bd74e..8f0fd21290 100644 --- a/doomsday/plugins/doom/src/p_oldsvg.cpp +++ b/doomsday/plugins/doom/src/p_oldsvg.cpp @@ -890,14 +890,15 @@ static void SaveInfo_Read_Dm_v19(SaveInfo *info, Reader *reader) info->_version = atoi(&vcheck[8]); info->_gameRules.skill = (skillmode_t) Reader_ReadByte(reader); - // Interpret skill levels outside the normal range as "spawn no things". if(info->_gameRules.skill < SM_BABY || info->_gameRules.skill >= NUM_SKILL_MODES) + { info->_gameRules.skill = SM_NOTHINGS; + } - info->_episode = Reader_ReadByte(reader) - 1; - info->_map = Reader_ReadByte(reader) - 1; - Uri_Copy(info->_mapUri, G_ComposeMapUri(info->_episode, info->_map)); + uint episode = Reader_ReadByte(reader) - 1; + uint map = Reader_ReadByte(reader) - 1; + Uri_Copy(info->_mapUri, G_ComposeMapUri(episode, map)); for(int i = 0; i < 4; ++i) { diff --git a/doomsday/plugins/heretic/src/p_oldsvg.cpp b/doomsday/plugins/heretic/src/p_oldsvg.cpp index 01c2c7b9c4..3b83c4ee37 100644 --- a/doomsday/plugins/heretic/src/p_oldsvg.cpp +++ b/doomsday/plugins/heretic/src/p_oldsvg.cpp @@ -909,14 +909,15 @@ static void SaveInfo_Read_Hr_v13(SaveInfo *info, Reader *reader) info->_version = atoi(&vcheck[8]); info->_gameRules.skill = (skillmode_t) Reader_ReadByte(reader); - // Interpret skill levels outside the normal range as "spawn no things". if(info->_gameRules.skill < SM_BABY || info->_gameRules.skill >= NUM_SKILL_MODES) + { info->_gameRules.skill = SM_NOTHINGS; + } - info->_episode = Reader_ReadByte(reader) - 1; - info->_map = Reader_ReadByte(reader) - 1; - Uri_Copy(info->_mapUri, G_ComposeMapUri(info->_episode, info->_map)); + uint episode = Reader_ReadByte(reader) - 1; + uint map = Reader_ReadByte(reader) - 1; + Uri_Copy(info->_mapUri, G_ComposeMapUri(episode, map)); for(int i = 0; i < 4; ++i) { From 4641c7aabce044a224174028d0e1704d1d90edec Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 05:38:15 +0000 Subject: [PATCH 05/15] libcommon: Continued work on remodeling saved game writing/reading Moved MapStateWriter/MapStateReader into new source files and applied the pimpl idiom. All map data write/read routines now take pointers to these classes. Each provides access to any relevant utility funcs and/or data structures (e.g., MaterialArchive). --- doomsday/plugins/common/common.pri | 4 + .../plugins/common/include/mapstatereader.h | 54 ++ .../plugins/common/include/mapstatewriter.h | 40 + doomsday/plugins/common/include/p_ceiling.h | 8 +- doomsday/plugins/common/include/p_door.h | 9 +- doomsday/plugins/common/include/p_floor.h | 8 +- doomsday/plugins/common/include/p_plat.h | 8 +- doomsday/plugins/common/include/p_saveg.h | 76 +- doomsday/plugins/common/include/p_scroll.h | 8 +- doomsday/plugins/common/include/p_switch.h | 8 +- doomsday/plugins/common/include/p_xgsec.h | 8 +- doomsday/plugins/common/include/polyobjs.h | 12 +- .../plugins/common/src/mapstatereader.cpp | 545 +++++++++++ .../plugins/common/src/mapstatewriter.cpp | 261 ++++++ doomsday/plugins/common/src/p_ceiling.cpp | 9 +- doomsday/plugins/common/src/p_door.cpp | 9 +- doomsday/plugins/common/src/p_floor.cpp | 13 +- doomsday/plugins/common/src/p_plat.cpp | 9 +- doomsday/plugins/common/src/p_saveg.cpp | 865 ++---------------- doomsday/plugins/common/src/p_scroll.cpp | 11 +- doomsday/plugins/common/src/p_switch.cpp | 15 +- doomsday/plugins/common/src/p_xgsave.cpp | 12 +- doomsday/plugins/common/src/polyobjs.cpp | 18 +- doomsday/plugins/doom/include/p_lights.h | 24 +- doomsday/plugins/doom/src/p_lights.cpp | 35 +- doomsday/plugins/doom64/include/p_lights.h | 28 +- doomsday/plugins/doom64/src/p_lights.cpp | 43 +- doomsday/plugins/heretic/include/p_lights.h | 20 +- doomsday/plugins/heretic/src/p_lights.cpp | 27 +- doomsday/plugins/hexen/include/acscript.h | 8 +- doomsday/plugins/hexen/include/p_lights.h | 16 +- doomsday/plugins/hexen/include/p_pillar.h | 12 +- doomsday/plugins/hexen/include/p_waggle.h | 12 +- doomsday/plugins/hexen/src/acscript.cpp | 9 +- doomsday/plugins/hexen/src/p_lights.cpp | 18 +- doomsday/plugins/hexen/src/p_pillar.cpp | 9 +- doomsday/plugins/hexen/src/p_waggle.cpp | 9 +- 37 files changed, 1333 insertions(+), 947 deletions(-) create mode 100644 doomsday/plugins/common/include/mapstatereader.h create mode 100644 doomsday/plugins/common/include/mapstatewriter.h create mode 100644 doomsday/plugins/common/src/mapstatereader.cpp create mode 100644 doomsday/plugins/common/src/mapstatewriter.cpp diff --git a/doomsday/plugins/common/common.pri b/doomsday/plugins/common/common.pri index 0a9741610f..72c68fdbcb 100644 --- a/doomsday/plugins/common/common.pri +++ b/doomsday/plugins/common/common.pri @@ -35,6 +35,8 @@ HEADERS += \ $$common_inc/hu_pspr.h \ $$common_inc/hu_stuff.h \ $$common_inc/m_argv.h \ + $$common_inc/mapstatereader.h \ + $$common_inc/mapstatewriter.h \ $$common_inc/mobj.h \ $$common_inc/pause.h \ $$common_inc/p_actor.h \ @@ -95,6 +97,8 @@ SOURCES += \ $$common_src/hu_pspr.c \ $$common_src/hu_stuff.cpp \ $$common_src/m_ctrl.c \ + $$common_src/mapstatereader.cpp \ + $$common_src/mapstatewriter.cpp \ $$common_src/mobj.c \ $$common_src/pause.c \ $$common_src/p_actor.cpp \ diff --git a/doomsday/plugins/common/include/mapstatereader.h b/doomsday/plugins/common/include/mapstatereader.h new file mode 100644 index 0000000000..0d62096a1a --- /dev/null +++ b/doomsday/plugins/common/include/mapstatereader.h @@ -0,0 +1,54 @@ +/** @file mapstatereader.h Saved map state reader. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBCOMMON_MAPSTATEREADER_H +#define LIBCOMMON_MAPSTATEREADER_H + +#include "common.h" +#include "dmu_archiveindex.h" + +class MapStateReader +{ +public: + MapStateReader(int saveVersion); + + void read(Reader *reader); + + /** + * Finds and returns a material with the identifier @a serialId. + * + * @param serialId Unique identifier for the material in the material archive. + * @param group Used with previous versions of the material archive, which + * separated materials into groups (0= Flats 1= Textures). + * + * @return Pointer to the associated material; otherwise @c 0 (not archived). + */ + Material *archiveMaterial(materialarchive_serialid_t serialId, int group); + + Reader *reader(); + int mapVersion(); + MaterialArchive *materialArchive(); + dmu_lib::SideArchive &sideArchive(); + +private: + DENG2_PRIVATE(d) +}; + +#endif // LIBCOMMON_MAPSTATEREADER_H diff --git a/doomsday/plugins/common/include/mapstatewriter.h b/doomsday/plugins/common/include/mapstatewriter.h new file mode 100644 index 0000000000..1dce3675b0 --- /dev/null +++ b/doomsday/plugins/common/include/mapstatewriter.h @@ -0,0 +1,40 @@ +/** @file mapstatewriter.h Saved map state writer. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBCOMMON_MAPSTATEWRITER_H +#define LIBCOMMON_MAPSTATEWRITER_H + +#include "common.h" + +class MapStateWriter +{ +public: + MapStateWriter(bool excludePlayers = false); + + void write(Writer *writer); + + Writer *writer(); + MaterialArchive *materialArchive(); + +private: + DENG2_PRIVATE(d) +}; + +#endif // LIBCOMMON_MAPSTATEWRITER_H diff --git a/doomsday/plugins/common/include/p_ceiling.h b/doomsday/plugins/common/include/p_ceiling.h index 457787ae70..48f8365645 100644 --- a/doomsday/plugins/common/include/p_ceiling.h +++ b/doomsday/plugins/common/include/p_ceiling.h @@ -23,6 +23,10 @@ #define LIBCOMMON_THINKER_CEILING_H #include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif #define CEILSPEED (1) #define CEILWAIT (150) @@ -68,8 +72,8 @@ typedef struct ceiling_s { int tag; // id. #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } ceiling_t; diff --git a/doomsday/plugins/common/include/p_door.h b/doomsday/plugins/common/include/p_door.h index b5323565be..4f0f71cfda 100644 --- a/doomsday/plugins/common/include/p_door.h +++ b/doomsday/plugins/common/include/p_door.h @@ -22,6 +22,11 @@ #ifndef LIBCOMMON_THINKER_DOOR_H #define LIBCOMMON_THINKER_DOOR_H +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + #define DOORSPEED (2) #define DOORWAIT (150) @@ -66,8 +71,8 @@ typedef struct door_s { int topCountDown; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } door_t; diff --git a/doomsday/plugins/common/include/p_floor.h b/doomsday/plugins/common/include/p_floor.h index 1f62d77821..22656d4247 100644 --- a/doomsday/plugins/common/include/p_floor.h +++ b/doomsday/plugins/common/include/p_floor.h @@ -23,6 +23,10 @@ #define LIBCOMMON_THINKER_FLOOR_H #include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif #define FLOORSPEED (1) @@ -104,8 +108,8 @@ typedef struct floor_s { #endif #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } floor_t; diff --git a/doomsday/plugins/common/include/p_plat.h b/doomsday/plugins/common/include/p_plat.h index 13f2871fdf..bfce227d19 100644 --- a/doomsday/plugins/common/include/p_plat.h +++ b/doomsday/plugins/common/include/p_plat.h @@ -23,6 +23,10 @@ #define LIBCOMMON_THINKER_PLAT_H #include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif #define PLATWAIT (3) #define PLATSPEED (1) @@ -72,8 +76,8 @@ typedef struct plat_s { plattype_e type; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } plat_t; diff --git a/doomsday/plugins/common/include/p_saveg.h b/doomsday/plugins/common/include/p_saveg.h index f49324e7fd..1e12a78bd1 100644 --- a/doomsday/plugins/common/include/p_saveg.h +++ b/doomsday/plugins/common/include/p_saveg.h @@ -67,11 +67,32 @@ typedef enum thinkclass_e { } thinkerclass_t; #ifdef __cplusplus -extern "C" { +class MapStateReader; +class MapStateWriter; + +// Thinker Save flags +#define TSF_SERVERONLY 0x01 ///< Only saved by servers. + +typedef void (*WriteThinkerFunc)(thinker_t *, MapStateWriter *writer); +typedef int (*ReadThinkerFunc)(thinker_t *, MapStateReader *reader); + +struct ThinkerClassInfo +{ + thinkerclass_t thinkclass; + thinkfunc_t function; + int flags; + WriteThinkerFunc writeFunc; + ReadThinkerFunc readFunc; + size_t size; +}; #endif -typedef void (*WriteThinkerFunc)(thinker_t *, Writer *writer); -typedef int (*ReadThinkerFunc)(thinker_t *, Reader *reader, int mapVersion); +DENG_EXTERN_C int thingArchiveVersion; +DENG_EXTERN_C uint thingArchiveSize; + +#ifdef __cplusplus +extern "C" { +#endif /// Register the console commands and variables of this module. void SV_Register(void); @@ -196,6 +217,18 @@ void SV_LoadGameClient(uint gameId); uint SV_GenerateGameId(void); +#ifdef __cplusplus +/** + * Returns the info for the specified thinker @a tClass; otherwise @c 0 if not found. + */ +ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass); + +/** + * Returns the info for the specified thinker; otherwise @c 0 if not found. + */ +ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker); +#endif + /// Unique identifier associated with each archived thing. #if __JHEXEN__ typedef int ThingSerialId; @@ -224,22 +257,6 @@ ThingSerialId SV_ThingArchiveId(mobj_t const *mobj); */ mobj_t *SV_GetArchiveThing(ThingSerialId thingid, void *address); -/** - * Returns a pointer to the (currently in-use) material archive. - */ -MaterialArchive *SV_MaterialArchive(void); - -/** - * Finds and returns a material with the identifier @a serialId. - * - * @param serialId Unique identifier for the material in the material archive. - * @param group Used with previous versions of the material archive, which - * separated materials into groups (0= Flats 1= Textures). - * - * @return Pointer to the associated material; otherwise @c 0 (not archived). - */ -Material *SV_GetArchiveMaterial(materialarchive_serialid_t serialId, int group); - /** * Update mobj flag values from those used in legacy game-save formats * to their current values. @@ -271,10 +288,29 @@ void SV_HxBackupPlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS]); void SV_HxRestorePlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS], uint entryPoint); #endif +void SV_InitThingArchiveForLoad(uint size); +#if __JHEXEN__ +void SV_InitTargetPlayers(void); +#endif + #ifdef __cplusplus } // extern "C" +#endif + +#ifdef __cplusplus +class MapStateReader; +class MapStateWriter; -dmu_lib::SideArchive &SV_SideArchive(); +void SV_WriteLine(Line *line, MapStateWriter *msw); +void SV_ReadLine(Line *line, MapStateReader *msr); + +void SV_WriteSector(Sector *sec, MapStateWriter *msw); +void SV_ReadSector(Sector *sec, MapStateReader *msr); + +#if __JHEXEN__ +void SV_WritePolyObj(polyobj_s *po, MapStateWriter *msw); +int SV_ReadPolyObj(MapStateReader *msr); #endif +#endif // __cplusplus #endif // LIBCOMMON_SAVESTATE_H diff --git a/doomsday/plugins/common/include/p_scroll.h b/doomsday/plugins/common/include/p_scroll.h index ee42f6b2bd..e8b54cc2f4 100644 --- a/doomsday/plugins/common/include/p_scroll.h +++ b/doomsday/plugins/common/include/p_scroll.h @@ -23,6 +23,10 @@ #define LIBCOMMON_THINKER_SCROLL_H #include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif typedef struct scroll_s { thinker_t thinker; @@ -31,8 +35,8 @@ typedef struct scroll_s { float offset[2]; ///< [x, y] scroll vector delta. #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } scroll_t; diff --git a/doomsday/plugins/common/include/p_switch.h b/doomsday/plugins/common/include/p_switch.h index 93324e933e..28618e18c7 100644 --- a/doomsday/plugins/common/include/p_switch.h +++ b/doomsday/plugins/common/include/p_switch.h @@ -25,6 +25,10 @@ #include "doomsday.h" #include "p_mobj.h" #include "dmu_lib.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif #define BUTTONTIME (TICSPERSEC) // 1 second, in ticks. @@ -36,8 +40,8 @@ typedef struct materialchanger_s { Material *material; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } materialchanger_t; diff --git a/doomsday/plugins/common/include/p_xgsec.h b/doomsday/plugins/common/include/p_xgsec.h index c9245a2c05..63e4fd35f7 100644 --- a/doomsday/plugins/common/include/p_xgsec.h +++ b/doomsday/plugins/common/include/p_xgsec.h @@ -22,6 +22,10 @@ #define LIBCOMMON_XG_SECTORTYPE_H #include "g_common.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif // Sector chain event types. enum { @@ -141,8 +145,8 @@ typedef struct xgplanemover_s { int timer; // Counts down to zero. #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } xgplanemover_t; diff --git a/doomsday/plugins/common/include/polyobjs.h b/doomsday/plugins/common/include/polyobjs.h index 49004799df..fbf73e06b9 100644 --- a/doomsday/plugins/common/include/polyobjs.h +++ b/doomsday/plugins/common/include/polyobjs.h @@ -23,6 +23,10 @@ #define LIBCOMMON_PLAYSIM_POLYOBJS_H #include "common.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif typedef enum { PODOOR_NONE, @@ -39,8 +43,8 @@ typedef struct polyevent_s { coord_t speed[2]; // for sliding doors #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } polyevent_t; @@ -58,8 +62,8 @@ typedef struct polydoor_s { dd_bool close; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } polydoor_t; diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp new file mode 100644 index 0000000000..fb8bfdfc49 --- /dev/null +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -0,0 +1,545 @@ +/** @file mapstatereader.cpp Saved map state reader. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "common.h" +#include "mapstatereader.h" + +#include "dmu_lib.h" +#include "p_actor.h" +#include "p_saveg.h" +#include "p_saveio.h" + +DENG2_PIMPL(MapStateReader) +{ + Reader *reader; + int saveVersion; + int mapVersion; + MaterialArchive *materialArchive; + dmu_lib::SideArchive *sideArchive; + + Instance(Public *i) + : Base(i) + , reader(0) + , saveVersion(0) + , mapVersion(0) + , materialArchive(0) + , sideArchive(0) + {} + + void beginMapSegment() + { + savestatesegment_t segId; + SV_AssertMapSegment(&segId); + +#if __JHEXEN__ + // Maps have their own version number, in Hexen. + mapVersion = (segId == ASEG_MAP_HEADER2? Reader_ReadByte(reader) : 2); + + thingArchiveVersion = mapVersion >= 4? 1 : 0; +#endif + +#if __JHEXEN__ + // Read the map timer. + mapTime = Reader_ReadInt32(reader); +#endif + + // Read the material archive for the map. +#ifdef __JHEXEN__ + materialArchive = MaterialArchive_NewEmpty(true /* segment checks */); +#else + materialArchive = MaterialArchive_NewEmpty(false); +#endif +#if !__JHEXEN__ + if(mapVersion >= 4) +#endif + { + MaterialArchive_Read(materialArchive, reader, mapVersion < 6? 0 : -1); + } + + sideArchive = new dmu_lib::SideArchive; + } + + void endMapSegment() + { + SV_AssertSegment(ASEG_END); + + delete sideArchive; sideArchive = 0; + MaterialArchive_Delete(materialArchive); materialArchive = 0; + } + + void readElements() + { + SV_AssertSegment(ASEG_MAP_ELEMENTS); + + // Sectors. + for(int i = 0; i < numsectors; ++i) + { + SV_ReadSector((Sector *)P_ToPtr(DMU_SECTOR, i), thisPublic); + } + + // Lines. + for(int i = 0; i < numlines; ++i) + { + SV_ReadLine((Line *)P_ToPtr(DMU_LINE, i), thisPublic); + } + } + + void readPolyobjs() + { +#if __JHEXEN__ + SV_AssertSegment(ASEG_POLYOBJS); + + int const writtenPolyobjCount = Reader_ReadInt32(reader); + DENG_ASSERT(writtenPolyobjCount == numpolyobjs); + for(int i = 0; i < writtenPolyobjCount; ++i) + { + SV_ReadPolyObj(thisPublic); + } +#endif + } + + static int removeThinkerWorker(thinker_t *th, void * /*context*/) + { + if(th->function == (thinkfunc_t) P_MobjThinker) + { + P_MobjRemove((mobj_t *) th, true); + } + else + { + Z_Free(th); + } + + return false; // Continue iteration. + } + + void removeLoadSpawnedThinkers() + { +#if !__JHEXEN__ + if(!IS_SERVER) return; // Not for us. +#endif + + Thinker_Iterate(0 /*all thinkers*/, removeThinkerWorker, 0/*no parameters*/); + Thinker_Init(); + } + +#if __JHEXEN__ + static bool mobjtypeHasCorpse(mobjtype_t type) + { + // Only corpses that call A_QueueCorpse from death routine. + /// @todo fixme: What about mods? Look for this action in the death + /// state sequence? + switch(type) + { + case MT_CENTAUR: + case MT_CENTAURLEADER: + case MT_DEMON: + case MT_DEMON2: + case MT_WRAITH: + case MT_WRAITHB: + case MT_BISHOP: + case MT_ETTIN: + case MT_PIG: + case MT_CENTAUR_SHIELD: + case MT_CENTAUR_SWORD: + case MT_DEMONCHUNK1: + case MT_DEMONCHUNK2: + case MT_DEMONCHUNK3: + case MT_DEMONCHUNK4: + case MT_DEMONCHUNK5: + case MT_DEMON2CHUNK1: + case MT_DEMON2CHUNK2: + case MT_DEMON2CHUNK3: + case MT_DEMON2CHUNK4: + case MT_DEMON2CHUNK5: + case MT_FIREDEMON_SPLOTCH1: + case MT_FIREDEMON_SPLOTCH2: + return true; + + default: return false; + } + } + + static int rebuildCorpseQueueWorker(thinker_t *th, void * /*context*/) + { + mobj_t *mo = (mobj_t *) th; + + // Must be a non-iced corpse. + if((mo->flags & MF_CORPSE) && !(mo->flags & MF_ICECORPSE) && + mobjtypeHasCorpse(mobjtype_t(mo->type))) + { + P_AddCorpseToQueue(mo); + } + + return false; // Continue iteration. + } + + /** + * @todo fixme: the corpse queue should be serialized (original order unknown). + */ + void rebuildCorpseQueue() + { + P_InitCorpseQueue(); + // Search the thinker list for corpses and place them in the queue. + Thinker_Iterate((thinkfunc_t) P_MobjThinker, rebuildCorpseQueueWorker, NULL/*no params*/); + } +#endif + + static int restoreMobjLinksWorker(thinker_t *th, void *context) + { + int const mapVersion = *static_cast(context); + + if(th->function != (thinkfunc_t) P_MobjThinker) + return false; // Continue iteration. + + mobj_t *mo = (mobj_t *) th; + mo->target = SV_GetArchiveThing(PTR2INT(mo->target), &mo->target); + mo->onMobj = SV_GetArchiveThing(PTR2INT(mo->onMobj), &mo->onMobj); + +#if __JHEXEN__ + switch(mo->type) + { + // Just tracer + case MT_BISH_FX: + case MT_HOLY_FX: + case MT_DRAGON: + case MT_THRUSTFLOOR_UP: + case MT_THRUSTFLOOR_DOWN: + case MT_MINOTAUR: + case MT_SORCFX1: + if(mapVersion >= 3) + { + mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); + } + else + { + mo->tracer = SV_GetArchiveThing(mo->special1, &mo->tracer); + mo->special1 = 0; + } + break; + + // Just special2 + case MT_LIGHTNING_FLOOR: + case MT_LIGHTNING_ZAP: + mo->special2 = PTR2INT(SV_GetArchiveThing(mo->special2, &mo->special2)); + break; + + // Both tracer and special2 + case MT_HOLY_TAIL: + case MT_LIGHTNING_CEILING: + if(mapVersion >= 3) + { + mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); + } + else + { + mo->tracer = SV_GetArchiveThing(mo->special1, &mo->tracer); + mo->special1 = 0; + } + mo->special2 = PTR2INT(SV_GetArchiveThing(mo->special2, &mo->special2)); + break; + + default: + break; + } +#else +# if __JDOOM__ || __JDOOM64__ + mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); +# endif +# if __JHERETIC__ + mo->generator = SV_GetArchiveThing(PTR2INT(mo->generator), &mo->generator); +# endif +#endif + + return false; // Continue iteration. + +#if !__JHEXEN__ + DENG_UNUSED(mapVersion); +#endif + } + + /** + * Update the references between thinkers. To be called during the load + * process to finalize the loaded thinkers. + */ + void relinkThinkers() + { +#if __JHEXEN__ + Thinker_Iterate((thinkfunc_t) P_MobjThinker, restoreMobjLinksWorker, &mapVersion); + + P_CreateTIDList(); + rebuildCorpseQueue(); + +#else + if(IS_SERVER) + { + Thinker_Iterate((thinkfunc_t) P_MobjThinker, restoreMobjLinksWorker, &mapVersion); + + for(int i = 0; i < numlines; ++i) + { + xline_t *xline = P_ToXLine((Line *)P_ToPtr(DMU_LINE, i)); + if(!xline->xg) continue; + + xline->xg->activator = SV_GetArchiveThing(PTR2INT(xline->xg->activator), + &xline->xg->activator); + } + } +#endif + } + + /** + * Deserialize and then spawns thinkers for both client and server. + */ + void readThinkers() + { + bool const formatHasStasisInfo = (mapVersion >= 6); + + removeLoadSpawnedThinkers(); + +#if __JHEXEN__ + if(mapVersion < 4) + SV_AssertSegment(ASEG_MOBJS); + else +#endif + SV_AssertSegment(ASEG_THINKERS); + +#if __JHEXEN__ + SV_InitTargetPlayers(); + SV_InitThingArchiveForLoad(Reader_ReadInt32(reader) /* num elements */); +#endif + + // Read in saved thinkers. +#if __JHEXEN__ + int i = 0; + bool reachedSpecialsBlock = (mapVersion >= 4); +#else + bool reachedSpecialsBlock = (mapVersion >= 5); +#endif + + byte tClass = 0; + forever + { +#if __JHEXEN__ + if(reachedSpecialsBlock) +#endif + tClass = Reader_ReadByte(reader); + +#if __JHEXEN__ + if(mapVersion < 4) + { + if(reachedSpecialsBlock) // Have we started on the specials yet? + { + // Versions prior to 4 used a different value to mark + // the end of the specials data and the thinker class ids + // are differrent, so we need to manipulate the thinker + // class identifier value. + if(tClass != TC_END) + tClass += 2; + } + else + { + tClass = TC_MOBJ; + } + + if(tClass == TC_MOBJ && (uint)i == thingArchiveSize) + { + SV_AssertSegment(ASEG_THINKERS); + // We have reached the begining of the "specials" block. + reachedSpecialsBlock = true; + continue; + } + } +#else + if(mapVersion < 5) + { + if(reachedSpecialsBlock) + { + // Versions prior to 5 used a different value to mark + // the end of the specials data so we need to manipulate + // the thinker class identifier value. + if(tClass == PRE_VER5_END_SPECIALS) + tClass = TC_END; + else + tClass += 3; + } + else if(tClass == TC_END) + { + // We have reached the begining of the "specials" block. + reachedSpecialsBlock = true; + continue; + } + } +#endif + if(tClass == TC_END) + break; // End of the list. + + ThinkerClassInfo *thInfo = SV_ThinkerInfoForClass(thinkerclass_t(tClass)); + DENG_ASSERT(thInfo != 0); + // Not for us? (it shouldn't be here anyway!). + DENG_ASSERT(!((thInfo->flags & TSF_SERVERONLY) && IS_CLIENT)); + + // Mobjs use a special engine-side allocator. + thinker_t *th = 0; + if(thInfo->thinkclass == TC_MOBJ) + { + th = reinterpret_cast(Mobj_CreateXYZ((thinkfunc_t) P_MobjThinker, 0, 0, 0, 0, 64, 64, 0)); + } + else + { + th = reinterpret_cast(Z_Calloc(thInfo->size, PU_MAP, 0)); + } + + bool putThinkerInStasis = (formatHasStasisInfo? CPP_BOOL(Reader_ReadByte(reader)) : false); + + if(thInfo->readFunc(th, thisPublic)) + { + Thinker_Add(th); + } + + if(putThinkerInStasis) + { + Thinker_SetStasis(th, true); + } + +#if __JHEXEN__ + if(tClass == TC_MOBJ) + i++; +#endif + } + + // Update references between thinkers. + relinkThinkers(); + } + + void readACScriptData() + { +#if __JHEXEN__ + Game_ACScriptInterpreter().readMapScriptData(reader, mapVersion); +#endif + } + + void readSoundSequences() + { +#if __JHEXEN__ + SN_ReadSequences(reader, mapVersion); +#endif + } + + void readMisc() + { +#if __JHEXEN__ + SV_AssertSegment(ASEG_MISC); + + for(int i = 0; i < MAXPLAYERS; ++i) + { + localQuakeHappening[i] = Reader_ReadInt32(reader); + } +#endif + } + + void readBrain() + { +#if __JDOOM__ + P_BrainRead(reader, mapVersion); +#endif + } + + void readSoundTargets() + { +#if !__JHEXEN__ + // Not for us? + if(!IS_SERVER) return; + + // Sound target data was introduced in ver 5 + if(mapVersion < 5) return; + + int numTargets = Reader_ReadInt32(reader); + for(int i = 0; i < numTargets; ++i) + { + xsector_t *xsec = P_ToXSector((Sector *)P_ToPtr(DMU_SECTOR, Reader_ReadInt32(reader))); + DENG_ASSERT(xsec != 0); + + if(!xsec) + { + DENG_UNUSED(Reader_ReadInt16(reader)); + continue; + } + + xsec->soundTarget = INT2PTR(mobj_t, Reader_ReadInt16(reader)); + xsec->soundTarget = + SV_GetArchiveThing(PTR2INT(xsec->soundTarget), &xsec->soundTarget); + } +#endif + } +}; + +MapStateReader::MapStateReader(int saveVersion) + : d(new Instance(this)) +{ + d->saveVersion = saveVersion; + d->mapVersion = saveVersion; // Default: mapVersion == saveVersion +} + +void MapStateReader::read(Reader *reader) +{ + DENG_ASSERT(reader != 0); + d->reader = reader; + + d->beginMapSegment(); + { + d->readElements(); + d->readPolyobjs(); + d->readThinkers(); + d->readACScriptData(); + d->readSoundSequences(); + d->readMisc(); + d->readBrain(); + d->readSoundTargets(); + } + d->endMapSegment(); +} + +Reader *MapStateReader::reader() +{ + DENG_ASSERT(d->reader != 0); + return d->reader; +} + +int MapStateReader::mapVersion() +{ + return d->mapVersion; +} + +Material *MapStateReader::archiveMaterial(materialarchive_serialid_t serialId, int group) +{ + DENG_ASSERT(d->materialArchive != 0); + return MaterialArchive_Find(d->materialArchive, serialId, group); +} + +MaterialArchive *MapStateReader::materialArchive() +{ + DENG_ASSERT(d->materialArchive != 0); + return d->materialArchive; +} + +dmu_lib::SideArchive &MapStateReader::sideArchive() +{ + DENG_ASSERT(d->sideArchive != 0); + return *d->sideArchive; +} diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp new file mode 100644 index 0000000000..9404f8e43b --- /dev/null +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -0,0 +1,261 @@ +/** @file mapstatewriter.cpp Saved map state writer. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "common.h" +#include "mapstatewriter.h" + +#include "dmu_lib.h" +#include "p_saveg.h" +#include "p_saveio.h" + +DENG2_PIMPL(MapStateWriter) +{ + bool excludePlayers; + Writer *writer; + MaterialArchive *materialArchive; + + Instance(Public *i) + : Base(i) + , excludePlayers(false) + , writer(0) + , materialArchive(0) + {} + + void beginMapSegment() + { + SV_BeginSegment(ASEG_MAP_HEADER2); + +#if __JHEXEN__ + Writer_WriteByte(writer, MY_SAVE_VERSION); // Map version also. + + // Write the map timer + Writer_WriteInt32(writer, mapTime); +#endif + + // Create and populate the MaterialArchive. +#ifdef __JHEXEN__ + materialArchive = MaterialArchive_New(true /* segment check */); +#else + materialArchive = MaterialArchive_New(false); +#endif + MaterialArchive_Write(materialArchive, writer); + } + + void endMapSegment() + { + SV_EndSegment(); + + MaterialArchive_Delete(materialArchive); materialArchive = 0; + } + + void writeElements() + { + SV_BeginSegment(ASEG_MAP_ELEMENTS); + + for(int i = 0; i < numsectors; ++i) + { + SV_WriteSector((Sector *)P_ToPtr(DMU_SECTOR, i), thisPublic); + } + + for(int i = 0; i < numlines; ++i) + { + SV_WriteLine((Line *)P_ToPtr(DMU_LINE, i), thisPublic); + } + } + + void writePolyobjs() + { +#if __JHEXEN__ + SV_BeginSegment(ASEG_POLYOBJS); + + Writer_WriteInt32(writer, numpolyobjs); + for(int i = 0; i < numpolyobjs; ++i) + { + SV_WritePolyObj(Polyobj_ById(i), thisPublic); + } +#endif + } + + struct writethinkerworker_params_t + { + MapStateWriter *msw; + bool excludePlayers; + }; + + /** + * Serializes the specified thinker and writes it to save state. + */ + static int writeThinkerWorker(thinker_t *th, void *context) + { + writethinkerworker_params_t &p = *static_cast(context); + + // We are only concerned with thinkers we have save info for. + ThinkerClassInfo *thInfo = SV_ThinkerInfo(*th); + if(!thInfo) return false; + + // Are we excluding players? + if(p.excludePlayers) + { + if(th->function == (thinkfunc_t) P_MobjThinker && ((mobj_t *) th)->player) + return false; // Continue iteration. + } + + // Only the server saves this class of thinker? + if((thInfo->flags & TSF_SERVERONLY) && IS_CLIENT) + return false; + + // Write the header block for this thinker. + Writer_WriteByte(p.msw->writer(), thInfo->thinkclass); // Thinker type byte. + Writer_WriteByte(p.msw->writer(), th->inStasis? 1 : 0); // In stasis? + + // Write the thinker data. + thInfo->writeFunc(th, p.msw); + + return false; // Continue iteration. + } + + /** + * Serializes thinkers for both client and server. + * + * @note Clients do not save data for all thinkers. In some cases the server + * will send it anyway (so saving it would just bloat client save states). + * + * @note Some thinker classes are NEVER saved by clients. + */ + void writeThinkers() + { + SV_BeginSegment(ASEG_THINKERS); + +#if __JHEXEN__ + Writer_WriteInt32(writer, thingArchiveSize); // number of mobjs. +#endif + + // Serialize qualifying thinkers. + writethinkerworker_params_t parm; de::zap(parm); + parm.msw = thisPublic; + parm.excludePlayers = excludePlayers; + Thinker_Iterate(0/*all thinkers*/, writeThinkerWorker, &parm); + + // Mark the end of the thinkers. + Writer_WriteByte(writer, TC_END); + } + + void writeACScriptData() + { +#if __JHEXEN__ + Game_ACScriptInterpreter().writeMapScriptData(writer); +#endif + } + + void writeSoundSequences() + { +#if __JHEXEN__ + SN_WriteSequences(writer); +#endif + } + + void writeBrain() + { +#if __JDOOM__ + P_BrainWrite(writer); +#endif + } + + void writeSoundTargets() + { +#if !__JHEXEN__ + // Not for us? + if(!IS_SERVER) return; + + // Write the total number. + int count = 0; + for(int i = 0; i < numsectors; ++i) + { + xsector_t *xsec = P_ToXSector((Sector *)P_ToPtr(DMU_SECTOR, i)); + if(xsec->soundTarget) + { + count += 1; + } + } + Writer_WriteInt32(writer, count); + + // Write the mobj references using the mobj archive. + for(int i = 0; i < numsectors; ++i) + { + xsector_t *xsec = P_ToXSector((Sector *)P_ToPtr(DMU_SECTOR, i)); + + if(xsec->soundTarget) + { + Writer_WriteInt32(writer, i); + Writer_WriteInt16(writer, SV_ThingArchiveId(xsec->soundTarget)); + } + } +#endif + } + + void writeMisc() + { +#if __JHEXEN__ + SV_BeginSegment(ASEG_MISC); + + for(int i = 0; i < MAXPLAYERS; ++i) + { + Writer_WriteInt32(writer, localQuakeHappening[i]); + } +#endif + } +}; + +MapStateWriter::MapStateWriter(bool excludePlayers) + : d(new Instance(this)) +{ + d->excludePlayers = excludePlayers; +} + +void MapStateWriter::write(Writer *writer) +{ + DENG_ASSERT(writer != 0); + writer = writer; + + d->beginMapSegment(); + { + d->writeElements(); + d->writePolyobjs(); + d->writeThinkers(); + d->writeACScriptData(); + d->writeSoundSequences(); + d->writeMisc(); + d->writeBrain(); + d->writeSoundTargets(); + } + d->endMapSegment(); +} + +Writer *MapStateWriter::writer() +{ + DENG_ASSERT(d->writer != 0); + return d->writer; +} + +MaterialArchive *MapStateWriter::materialArchive() +{ + DENG_ASSERT(d->materialArchive != 0); + return d->materialArchive; +} diff --git a/doomsday/plugins/common/src/p_ceiling.cpp b/doomsday/plugins/common/src/p_ceiling.cpp index dd9092c4f7..0af720c3c2 100644 --- a/doomsday/plugins/common/src/p_ceiling.cpp +++ b/doomsday/plugins/common/src/p_ceiling.cpp @@ -228,8 +228,10 @@ void T_MoveCeiling(void *ceilingThinkerPtr) } } -void ceiling_s::write(Writer *writer) const +void ceiling_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 2); // Write a version byte. Writer_WriteByte(writer, (byte) type); @@ -246,8 +248,11 @@ void ceiling_s::write(Writer *writer) const Writer_WriteByte(writer, (byte) oldState); } -int ceiling_s::read(Reader *reader, int mapVersion) +int ceiling_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + #if __JHEXEN__ if(mapVersion >= 4) #else diff --git a/doomsday/plugins/common/src/p_door.cpp b/doomsday/plugins/common/src/p_door.cpp index c212519144..75a844fef3 100644 --- a/doomsday/plugins/common/src/p_door.cpp +++ b/doomsday/plugins/common/src/p_door.cpp @@ -285,8 +285,10 @@ void T_Door(void *doorThinkerPtr) } } -void door_s::write(Writer *writer) const +void door_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -304,8 +306,11 @@ void door_s::write(Writer *writer) const Writer_WriteInt32(writer, topCountDown); } -int door_s::read(Reader *reader, int mapVersion) +int door_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + #if __JHEXEN__ if(mapVersion >= 4) #else diff --git a/doomsday/plugins/common/src/p_floor.cpp b/doomsday/plugins/common/src/p_floor.cpp index e84a0ffc33..631208302a 100644 --- a/doomsday/plugins/common/src/p_floor.cpp +++ b/doomsday/plugins/common/src/p_floor.cpp @@ -395,8 +395,10 @@ void T_MoveFloor(void *floorThinkerPtr) } } -void floor_s::write(Writer *writer) const +void floor_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 3); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -411,7 +413,7 @@ void floor_s::write(Writer *writer) const Writer_WriteInt32(writer, (int) state); Writer_WriteInt32(writer, newSpecial); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(SV_MaterialArchive(), material)); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), material)); Writer_WriteInt16(writer, (int) floorDestHeight); Writer_WriteInt32(writer, FLT2FIX(speed)); @@ -427,8 +429,11 @@ void floor_s::write(Writer *writer) const #endif } -int floor_s::read(Reader *reader, int mapVersion) +int floor_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + #if __JHEXEN__ if(mapVersion >= 4) #else @@ -446,7 +451,7 @@ int floor_s::read(Reader *reader, int mapVersion) if(ver >= 2) { - material = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 0); + material = msr->archiveMaterial(Reader_ReadInt16(reader), 0); } else { diff --git a/doomsday/plugins/common/src/p_plat.cpp b/doomsday/plugins/common/src/p_plat.cpp index 600488f3f6..96b714ca07 100644 --- a/doomsday/plugins/common/src/p_plat.cpp +++ b/doomsday/plugins/common/src/p_plat.cpp @@ -199,8 +199,10 @@ void T_PlatRaise(void *platThinkerPtr) } } -void plat_t::write(Writer *writer) const +void plat_t::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. Writer_WriteByte(writer, (byte) type); @@ -221,8 +223,11 @@ void plat_t::write(Writer *writer) const Writer_WriteInt32(writer, tag); } -int plat_t::read(Reader *reader, int mapVersion) +int plat_t::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + #if __JHEXEN__ if(mapVersion >= 4) #else diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 39c4f00f97..5db4f3a173 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -51,6 +51,8 @@ #if __JHEXEN__ # include "acscript.h" #endif +#include "mapstatereader.h" +#include "mapstatewriter.h" #include #include #include @@ -83,19 +85,6 @@ typedef struct playerheader_s { #endif } playerheader_t; -// Thinker Save flags -#define TSF_SERVERONLY 0x01 ///< Only saved by servers. - -struct ThinkerClassInfo -{ - thinkerclass_t thinkclass; - thinkfunc_t function; - int flags; - WriteThinkerFunc writeFunc; - ReadThinkerFunc readFunc; - size_t size; -}; - typedef enum { sc_normal, sc_ploff, ///< plane offset @@ -115,12 +104,12 @@ typedef enum { static bool recogniseGameState(Str const *path, SaveInfo *info); -static void SV_WriteMobj(thinker_t *th, Writer *writer); -static int SV_ReadMobj(thinker_t *th, Reader *reader, int mapVersion); +static void SV_WriteMobj(thinker_t *th, MapStateWriter *msWriter); +static int SV_ReadMobj(thinker_t *th, MapStateReader *msReader); #if __JHEXEN__ -static void SV_WriteMovePoly(polyevent_t const *movepoly, Writer *writer); -static int SV_ReadMovePoly(polyevent_t *movepoly, Reader *reader, int mapVersion); +static void SV_WriteMovePoly(polyevent_t const *movepoly, MapStateWriter *msWriter); +static int SV_ReadMovePoly(polyevent_t *movepoly, MapStateReader *msReader); #endif #if __JHEXEN__ @@ -147,33 +136,28 @@ static playerheader_t playerHeader; static dd_bool playerHeaderOK; static mobj_t **thingArchive; -static int thingArchiveVersion; -static uint thingArchiveSize; +int thingArchiveVersion; +uint thingArchiveSize; static bool thingArchiveExcludePlayers; static int saveToRealPlayerNum[MAXPLAYERS]; #if __JHEXEN__ static targetplraddress_t *targetPlayerAddrs; static byte *saveBuffer; -#else -static int numSoundTargets; #endif -static MaterialArchive *materialArchive; -static SideArchive *sideArchive; - template -static void writeThinkerAs(thinker_t const *th, Writer *writer) +static void writeThinkerAs(thinker_t const *th, MapStateWriter *msWriter) { Type *t = (Type*)th; - t->write(writer); + t->write(msWriter); } template -static int readThinkerAs(thinker_t *th, Reader *reader, int mapVersion) +static int readThinkerAs(thinker_t *th, MapStateReader *msReader) { Type *t = (Type *)th; - return t->read(reader, mapVersion); + return t->read(msReader); } static ThinkerClassInfo thinkerInfo[] = { @@ -864,10 +848,7 @@ uint SV_GenerateGameId() return Timer_RealMilliseconds() + (mapTime << 24); } -/** - * Returns the info for the specified thinker @a tClass; otherwise @c 0 if not found. - */ -static ThinkerClassInfo *infoForThinkerClass(thinkerclass_t tClass) +ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass) { for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) { @@ -877,10 +858,7 @@ static ThinkerClassInfo *infoForThinkerClass(thinkerclass_t tClass) return 0; // Not found. } -/** - * Returns the info for the specified thinker; otherwise @c 0 if not found. - */ -static ThinkerClassInfo *infoForThinker(thinker_t const &thinker) +ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker) { for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) { @@ -890,7 +868,7 @@ static ThinkerClassInfo *infoForThinker(thinker_t const &thinker) return 0; // Not found. } -static void initThingArchiveForLoad(uint size) +void SV_InitThingArchiveForLoad(uint size) { thingArchiveSize = size; thingArchive = reinterpret_cast(M_Calloc(thingArchiveSize * sizeof(*thingArchive))); @@ -997,20 +975,8 @@ ThingSerialId SV_ThingArchiveId(mobj_t const *mo) return firstUnused + 1; } -static void clearMaterialArchive() -{ - MaterialArchive_Delete(materialArchive); materialArchive = 0; -} - -Material *SV_GetArchiveMaterial(materialarchive_serialid_t serialId, int group) -{ - DENG_ASSERT(inited); - DENG_ASSERT(materialArchive != 0); - return MaterialArchive_Find(materialArchive, serialId, group); -} - #if __JHEXEN__ -static void initTargetPlayers() +void SV_InitTargetPlayers() { targetPlayerAddrs = 0; } @@ -1506,8 +1472,10 @@ static void SV_ReadPlayer(player_t *p, Reader *reader) # define MOBJ_SAVEVERSION 10 #endif -static void SV_WriteMobj(thinker_t *th, Writer *writer) +static void SV_WriteMobj(thinker_t *th, MapStateWriter *msw) { + Writer *writer = msw->writer(); + mobj_t const *original = (mobj_t*) th; mobj_t temp, *mo = &temp; @@ -1845,8 +1813,9 @@ static void RestoreMobj(mobj_t *mo, int ver) * Always returns @c false as a thinker will have already been allocated in * the mobj creation process. */ -static int SV_ReadMobj(thinker_t *th, Reader *reader, int /*mapVersion*/) +static int SV_ReadMobj(thinker_t *th, MapStateReader *msr) { + Reader *reader = msr->reader(); mobj_t *mo = (mobj_t *) th; int ver = Reader_ReadByte(reader); @@ -2306,8 +2275,10 @@ static void readPlayers(SaveInfo &info, dd_bool *infile, dd_bool *loaded, #endif } -static void SV_WriteSector(Sector *sec, Writer *writer) +void SV_WriteSector(Sector *sec, MapStateWriter *msw) { + Writer *writer = msw->writer(); + int i, type; float flooroffx = P_GetFloatp(sec, DMU_FLOOR_MATERIAL_OFFSET_X); float flooroffy = P_GetFloatp(sec, DMU_FLOOR_MATERIAL_OFFSET_Y); @@ -2344,8 +2315,8 @@ static void SV_WriteSector(Sector *sec, Writer *writer) Writer_WriteInt16(writer, floorheight); Writer_WriteInt16(writer, ceilingheight); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(materialArchive, floorMaterial)); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(materialArchive, ceilingMaterial)); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), floorMaterial)); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), ceilingMaterial)); Writer_WriteInt16(writer, floorFlags); Writer_WriteInt16(writer, ceilingFlags); #if __JHEXEN__ @@ -2391,10 +2362,6 @@ static void SV_WriteSector(Sector *sec, Writer *writer) { SV_WriteXGSector(sec, writer); } - - // Count the number of sound targets - if(xsec->soundTarget) - numSoundTargets++; #endif } @@ -2402,8 +2369,11 @@ static void SV_WriteSector(Sector *sec, Writer *writer) * Reads all versions of archived sectors. * Including the old Ver1. */ -static void SV_ReadSector(Sector *sec, Reader *reader, int mapVersion) +void SV_ReadSector(Sector *sec, MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + int i, ver = 1; int type = 0; Material *floorMaterial = 0, *ceilingMaterial = 0; @@ -2461,8 +2431,8 @@ static void SV_ReadSector(Sector *sec, Reader *reader, int mapVersion) #endif { // The flat numbers are actually archive numbers. - floorMaterial = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 0); - ceilingMaterial = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 0); + floorMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 0); + ceilingMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 0); } P_SetPtrp(sec, DMU_FLOOR_MATERIAL, floorMaterial); @@ -2545,8 +2515,10 @@ static void SV_ReadSector(Sector *sec, Reader *reader, int mapVersion) xsec->soundTarget = 0; } -static void SV_WriteLine(Line *li, Writer *writer) +void SV_WriteLine(Line *li, MapStateWriter *msw) { + Writer *writer = msw->writer(); + xline_t *xli = P_ToXLine(li); lineclass_t type; @@ -2602,9 +2574,9 @@ static void SV_WriteLine(Line *li, Writer *writer) Writer_WriteInt16(writer, P_GetIntp(si, DMU_MIDDLE_FLAGS)); Writer_WriteInt16(writer, P_GetIntp(si, DMU_BOTTOM_FLAGS)); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(materialArchive, (Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(materialArchive, (Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(materialArchive, (Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); P_GetFloatpv(si, DMU_TOP_COLOR, rgba); for(int k = 0; k < 3; ++k) @@ -2635,8 +2607,11 @@ static void SV_WriteLine(Line *li, Writer *writer) * Reads all versions of archived lines. * Including the old Ver1. */ -static void SV_ReadLine(Line *li, Reader *reader, int mapVersion) +void SV_ReadLine(Line *li, MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + Material *topMaterial = 0, *bottomMaterial = 0, *middleMaterial = 0; xline_t *xli = P_ToXLine(li); @@ -2780,9 +2755,9 @@ static void SV_ReadLine(Line *li, Reader *reader, int mapVersion) if(mapVersion >= 4) #endif { - topMaterial = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 1); - bottomMaterial = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 1); - middleMaterial = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 1); + topMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); + bottomMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); + middleMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); } P_SetPtrp(si, DMU_TOP_MATERIAL, topMaterial); @@ -2832,9 +2807,9 @@ static void SV_ReadLine(Line *li, Reader *reader, int mapVersion) } #if __JHEXEN__ -static void SV_WritePolyObj(Polyobj *po, Writer *writer) +void SV_WritePolyObj(Polyobj *po, MapStateWriter *msw) { - DENG_ASSERT(po != 0); + Writer *writer = msw->writer(); Writer_WriteByte(writer, 1); // write a version byte. @@ -2844,8 +2819,11 @@ static void SV_WritePolyObj(Polyobj *po, Writer *writer) Writer_WriteInt32(writer, FLT2FIX(po->origin[VY])); } -static int SV_ReadPolyObj(Reader *reader, int mapVersion) +int SV_ReadPolyObj(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + int ver = (mapVersion >= 3)? Reader_ReadByte(reader) : 0; DENG_UNUSED(ver); @@ -2867,9 +2845,9 @@ static int SV_ReadPolyObj(Reader *reader, int mapVersion) #endif #if __JHEXEN__ -static void SV_WriteMovePoly(polyevent_t const *th, Writer *writer) +static void SV_WriteMovePoly(polyevent_t const *th, MapStateWriter *msw) { - DENG_ASSERT(th != 0); + Writer *writer = msw->writer(); Writer_WriteByte(writer, 1); // Write a version byte. @@ -2884,9 +2862,10 @@ static void SV_WriteMovePoly(polyevent_t const *th, Writer *writer) Writer_WriteInt32(writer, FLT2FIX(th->speed[VY])); } -static int SV_ReadMovePoly(polyevent_t *th, Reader *reader, int mapVersion) +static int SV_ReadMovePoly(polyevent_t *th, MapStateReader *msr) { - DENG_ASSERT(th != 0); + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); if(mapVersion >= 4) { @@ -2923,668 +2902,6 @@ static int SV_ReadMovePoly(polyevent_t *th, Reader *reader, int mapVersion) } #endif // __JHEXEN__ -class MapStateWriter -{ -public: - MapStateWriter(Writer *writer) - : _writer(writer) - { - DENG_ASSERT(_writer != 0); - } - - void write() - { - beginMapSegment(); - { - writeElements(); - writePolyobjs(); - writeThinkers(); - writeACScriptData(); - writeSoundSequences(); - writeMisc(); - writeBrain(); - writeSoundTargets(); - } - endMapSegment(); - } - -private: - void beginMapSegment() - { -#if !__JHEXEN__ - // Clear the sound target count (determined while saving sectors). - numSoundTargets = 0; -#endif - - SV_BeginSegment(ASEG_MAP_HEADER2); - -#if __JHEXEN__ - Writer_WriteByte(_writer, MY_SAVE_VERSION); // Map version also. - - // Write the map timer - Writer_WriteInt32(_writer, mapTime); -#endif - MaterialArchive_Write(materialArchive, _writer); - } - - void endMapSegment() - { - SV_EndSegment(); - } - - void writeElements() - { - SV_BeginSegment(ASEG_MAP_ELEMENTS); - - for(int i = 0; i < numsectors; ++i) - { - SV_WriteSector((Sector *)P_ToPtr(DMU_SECTOR, i), _writer); - } - - for(int i = 0; i < numlines; ++i) - { - SV_WriteLine((Line *)P_ToPtr(DMU_LINE, i), _writer); - } - } - - void writePolyobjs() - { -#if __JHEXEN__ - SV_BeginSegment(ASEG_POLYOBJS); - - Writer_WriteInt32(_writer, numpolyobjs); - for(int i = 0; i < numpolyobjs; ++i) - { - SV_WritePolyObj(Polyobj_ById(i), _writer); - } -#endif - } - - /** - * Serializes the specified thinker and writes it to save state. - * - * @param th The thinker to be serialized. - */ - static int writeThinkerWorker(thinker_t *th, void *context) - { - DENG_ASSERT(th != 0 && context != 0); - Writer *writer = (Writer *) context; - - // We are only concerned with thinkers we have save info for. - ThinkerClassInfo *thInfo = infoForThinker(*th); - if(!thInfo) return false; - - // Are we excluding players? - if(thingArchiveExcludePlayers) - { - if(th->function == (thinkfunc_t) P_MobjThinker && ((mobj_t *) th)->player) - return false; // Continue iteration. - } - - // Only the server saves this class of thinker? - if((thInfo->flags & TSF_SERVERONLY) && IS_CLIENT) - return false; - - // Write the header block for this thinker. - Writer_WriteByte(writer, thInfo->thinkclass); // Thinker type byte. - Writer_WriteByte(writer, th->inStasis? 1 : 0); // In stasis? - - // Write the thinker data. - thInfo->writeFunc(th, writer); - - return false; // Continue iteration. - } - - /** - * Serializes thinkers for both client and server. - * - * @note Clients do not save data for all thinkers. In some cases the server - * will send it anyway (so saving it would just bloat client save states). - * - * @note Some thinker classes are NEVER saved by clients. - */ - void writeThinkers() - { - SV_BeginSegment(ASEG_THINKERS); - -#if __JHEXEN__ - Writer_WriteInt32(_writer, thingArchiveSize); // number of mobjs. -#endif - - // Serialize qualifying thinkers. - Thinker_Iterate(0/*all thinkers*/, writeThinkerWorker, _writer); - - // Mark the end of the thinkers. - Writer_WriteByte(_writer, TC_END); - } - - void writeACScriptData() - { -#if __JHEXEN__ - Game_ACScriptInterpreter().writeMapScriptData(_writer); -#endif - } - - void writeSoundSequences() - { -#if __JHEXEN__ - SN_WriteSequences(_writer); -#endif - } - - void writeBrain() - { -#if __JDOOM__ - P_BrainWrite(_writer); -#endif - } - - void writeSoundTargets() - { -#if !__JHEXEN__ - // Not for us? - if(!IS_SERVER) return; - - // Write the total number. - Writer_WriteInt32(_writer, numSoundTargets); - - // Write the mobj references using the mobj archive. - for(int i = 0; i < numsectors; ++i) - { - xsector_t *xsec = P_ToXSector((Sector *)P_ToPtr(DMU_SECTOR, i)); - - if(xsec->soundTarget) - { - Writer_WriteInt32(_writer, i); - Writer_WriteInt16(_writer, SV_ThingArchiveId(xsec->soundTarget)); - } - } -#endif - } - - void writeMisc() - { -#if __JHEXEN__ - SV_BeginSegment(ASEG_MISC); - - for(int i = 0; i < MAXPLAYERS; ++i) - { - Writer_WriteInt32(_writer, localQuakeHappening[i]); - } -#endif - } - - Writer *_writer; -}; - -class MapStateReader -{ -public: - MapStateReader(Reader *reader, int saveVersion) - : _reader(reader) - , _saveVersion(saveVersion) - , _mapVersion(saveVersion) // Default: mapVersion == saveVersion - { - DENG_ASSERT(_reader != 0); - } - - void read() - { - beginMapSegment(); - { - readElements(); - readPolyobjs(); - readThinkers(); - readACScriptData(); - readSoundSequences(); - readMisc(); - readBrain(); - readSoundTargets(); - } - endMapSegment(); - } - -private: - void beginMapSegment() - { - savestatesegment_t segId; - SV_AssertMapSegment(&segId); - -#if __JHEXEN__ - // Maps have their own version number, in Hexen. - _mapVersion = (segId == ASEG_MAP_HEADER2? Reader_ReadByte(_reader) : 2); - - thingArchiveVersion = _mapVersion >= 4? 1 : 0; -#endif - -#if __JHEXEN__ - // Read the map timer. - mapTime = Reader_ReadInt32(_reader); -#endif - - // Read the material archive for the map. -#if !__JHEXEN__ - if(_mapVersion >= 4) -#endif - { - MaterialArchive_Read(materialArchive, _reader, _mapVersion < 6? 0 : -1); - } - - sideArchive = new SideArchive; - } - - void endMapSegment() - { - SV_AssertSegment(ASEG_END); - - delete sideArchive; sideArchive = 0; - } - - void readElements() - { - SV_AssertSegment(ASEG_MAP_ELEMENTS); - - // Sectors. - for(int i = 0; i < numsectors; ++i) - { - SV_ReadSector((Sector *)P_ToPtr(DMU_SECTOR, i), _reader, _mapVersion); - } - - // Lines. - for(int i = 0; i < numlines; ++i) - { - SV_ReadLine((Line *)P_ToPtr(DMU_LINE, i), _reader, _mapVersion); - } - } - - void readPolyobjs() - { -#if __JHEXEN__ - SV_AssertSegment(ASEG_POLYOBJS); - - int const writtenPolyobjCount = Reader_ReadInt32(_reader); - DENG_ASSERT(writtenPolyobjCount == numpolyobjs); - for(int i = 0; i < writtenPolyobjCount; ++i) - { - SV_ReadPolyObj(_reader, _mapVersion); - } -#endif - } - - static int removeThinkerWorker(thinker_t *th, void * /*context*/) - { - if(th->function == (thinkfunc_t) P_MobjThinker) - P_MobjRemove((mobj_t *) th, true); - else - Z_Free(th); - - return false; // Continue iteration. - } - - void removeLoadSpawnedThinkers() - { -#if !__JHEXEN__ - if(!IS_SERVER) return; // Not for us. -#endif - - Thinker_Iterate(0 /*all thinkers*/, removeThinkerWorker, 0/*no parameters*/); - Thinker_Init(); - } - -#if __JHEXEN__ - static bool mobjtypeHasCorpse(mobjtype_t type) - { - // Only corpses that call A_QueueCorpse from death routine. - /// @todo fixme: What about mods? Look for this action in the death - /// state sequence? - switch(type) - { - case MT_CENTAUR: - case MT_CENTAURLEADER: - case MT_DEMON: - case MT_DEMON2: - case MT_WRAITH: - case MT_WRAITHB: - case MT_BISHOP: - case MT_ETTIN: - case MT_PIG: - case MT_CENTAUR_SHIELD: - case MT_CENTAUR_SWORD: - case MT_DEMONCHUNK1: - case MT_DEMONCHUNK2: - case MT_DEMONCHUNK3: - case MT_DEMONCHUNK4: - case MT_DEMONCHUNK5: - case MT_DEMON2CHUNK1: - case MT_DEMON2CHUNK2: - case MT_DEMON2CHUNK3: - case MT_DEMON2CHUNK4: - case MT_DEMON2CHUNK5: - case MT_FIREDEMON_SPLOTCH1: - case MT_FIREDEMON_SPLOTCH2: - return true; - - default: return false; - } - } - - static int rebuildCorpseQueueWorker(thinker_t *th, void * /*context*/) - { - mobj_t *mo = (mobj_t *) th; - - // Must be a non-iced corpse. - if((mo->flags & MF_CORPSE) && !(mo->flags & MF_ICECORPSE) && - mobjtypeHasCorpse(mobjtype_t(mo->type))) - { - P_AddCorpseToQueue(mo); - } - - return false; // Continue iteration. - } - - /** - * @todo fixme: the corpse queue should be serialized (original order unknown). - */ - void rebuildCorpseQueue() - { - P_InitCorpseQueue(); - // Search the thinker list for corpses and place them in the queue. - Thinker_Iterate((thinkfunc_t) P_MobjThinker, rebuildCorpseQueueWorker, NULL/*no params*/); - } -#endif - - static int restoreMobjLinksWorker(thinker_t *th, void *context) - { - int const mapVersion = *static_cast(context); - - if(th->function != (thinkfunc_t) P_MobjThinker) - return false; // Continue iteration. - - mobj_t *mo = (mobj_t *) th; - mo->target = SV_GetArchiveThing(PTR2INT(mo->target), &mo->target); - mo->onMobj = SV_GetArchiveThing(PTR2INT(mo->onMobj), &mo->onMobj); - -#if __JHEXEN__ - switch(mo->type) - { - // Just tracer - case MT_BISH_FX: - case MT_HOLY_FX: - case MT_DRAGON: - case MT_THRUSTFLOOR_UP: - case MT_THRUSTFLOOR_DOWN: - case MT_MINOTAUR: - case MT_SORCFX1: - if(mapVersion >= 3) - { - mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); - } - else - { - mo->tracer = SV_GetArchiveThing(mo->special1, &mo->tracer); - mo->special1 = 0; - } - break; - - // Just special2 - case MT_LIGHTNING_FLOOR: - case MT_LIGHTNING_ZAP: - mo->special2 = PTR2INT(SV_GetArchiveThing(mo->special2, &mo->special2)); - break; - - // Both tracer and special2 - case MT_HOLY_TAIL: - case MT_LIGHTNING_CEILING: - if(mapVersion >= 3) - { - mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); - } - else - { - mo->tracer = SV_GetArchiveThing(mo->special1, &mo->tracer); - mo->special1 = 0; - } - mo->special2 = PTR2INT(SV_GetArchiveThing(mo->special2, &mo->special2)); - break; - - default: - break; - } -#else -# if __JDOOM__ || __JDOOM64__ - mo->tracer = SV_GetArchiveThing(PTR2INT(mo->tracer), &mo->tracer); -# endif -# if __JHERETIC__ - mo->generator = SV_GetArchiveThing(PTR2INT(mo->generator), &mo->generator); -# endif -#endif - - return false; // Continue iteration. - -#if !__JHEXEN__ - DENG_UNUSED(mapVersion); -#endif - } - - /** - * Update the references between thinkers. To be called during the load - * process to finalize the loaded thinkers. - */ - void relinkThinkers() - { -#if __JHEXEN__ - Thinker_Iterate((thinkfunc_t) P_MobjThinker, restoreMobjLinksWorker, &_mapVersion); - - P_CreateTIDList(); - rebuildCorpseQueue(); - -#else - if(IS_SERVER) - { - Thinker_Iterate((thinkfunc_t) P_MobjThinker, restoreMobjLinksWorker, &_mapVersion); - - for(int i = 0; i < numlines; ++i) - { - xline_t *xline = P_ToXLine((Line *)P_ToPtr(DMU_LINE, i)); - if(!xline->xg) continue; - - xline->xg->activator = SV_GetArchiveThing(PTR2INT(xline->xg->activator), - &xline->xg->activator); - } - } -#endif - } - - /** - * Deserialize and then spawns thinkers for both client and server. - */ - void readThinkers() - { - bool const formatHasStasisInfo = (_mapVersion >= 6); - - removeLoadSpawnedThinkers(); - -#if __JHEXEN__ - if(_mapVersion < 4) - SV_AssertSegment(ASEG_MOBJS); - else -#endif - SV_AssertSegment(ASEG_THINKERS); - -#if __JHEXEN__ - initTargetPlayers(); - initThingArchiveForLoad(Reader_ReadInt32(_reader) /* num elements */); -#endif - - // Read in saved thinkers. -#if __JHEXEN__ - int i = 0; - bool reachedSpecialsBlock = (_mapVersion >= 4); -#else - bool reachedSpecialsBlock = (_mapVersion >= 5); -#endif - - byte tClass = 0; - for(;;) - { -#if __JHEXEN__ - if(reachedSpecialsBlock) -#endif - tClass = Reader_ReadByte(_reader); - -#if __JHEXEN__ - if(_mapVersion < 4) - { - if(reachedSpecialsBlock) // Have we started on the specials yet? - { - // Versions prior to 4 used a different value to mark - // the end of the specials data and the thinker class ids - // are differrent, so we need to manipulate the thinker - // class identifier value. - if(tClass != TC_END) - tClass += 2; - } - else - { - tClass = TC_MOBJ; - } - - if(tClass == TC_MOBJ && (uint)i == thingArchiveSize) - { - SV_AssertSegment(ASEG_THINKERS); - // We have reached the begining of the "specials" block. - reachedSpecialsBlock = true; - continue; - } - } -#else - if(_mapVersion < 5) - { - if(reachedSpecialsBlock) - { - // Versions prior to 5 used a different value to mark - // the end of the specials data so we need to manipulate - // the thinker class identifier value. - if(tClass == PRE_VER5_END_SPECIALS) - tClass = TC_END; - else - tClass += 3; - } - else if(tClass == TC_END) - { - // We have reached the begining of the "specials" block. - reachedSpecialsBlock = true; - continue; - } - } -#endif - if(tClass == TC_END) - break; // End of the list. - - ThinkerClassInfo *thInfo = infoForThinkerClass(thinkerclass_t(tClass)); - DENG_ASSERT(thInfo != 0); - // Not for us? (it shouldn't be here anyway!). - DENG_ASSERT(!((thInfo->flags & TSF_SERVERONLY) && IS_CLIENT)); - - // Mobjs use a special engine-side allocator. - thinker_t *th = 0; - if(thInfo->thinkclass == TC_MOBJ) - { - th = reinterpret_cast(Mobj_CreateXYZ((thinkfunc_t) P_MobjThinker, 0, 0, 0, 0, 64, 64, 0)); - } - else - { - th = reinterpret_cast(Z_Calloc(thInfo->size, PU_MAP, 0)); - } - - bool putThinkerInStasis = (formatHasStasisInfo? CPP_BOOL(Reader_ReadByte(_reader)) : false); - - if(thInfo->readFunc(th, _reader, _mapVersion)) - { - Thinker_Add(th); - } - - if(putThinkerInStasis) - { - Thinker_SetStasis(th, true); - } - -#if __JHEXEN__ - if(tClass == TC_MOBJ) - i++; -#endif - } - - // Update references between thinkers. - relinkThinkers(); - } - - void readACScriptData() - { -#if __JHEXEN__ - Game_ACScriptInterpreter().readMapScriptData(_reader, _mapVersion); -#endif - } - - void readSoundSequences() - { -#if __JHEXEN__ - SN_ReadSequences(_reader, _mapVersion); -#endif - } - - void readMisc() - { -#if __JHEXEN__ - SV_AssertSegment(ASEG_MISC); - - for(int i = 0; i < MAXPLAYERS; ++i) - { - localQuakeHappening[i] = Reader_ReadInt32(_reader); - } -#endif - } - - void readBrain() - { -#if __JDOOM__ - P_BrainRead(_reader, _mapVersion); -#endif - } - - void readSoundTargets() - { -#if !__JHEXEN__ - // Not for us? - if(!IS_SERVER) return; - - // Sound target data was introduced in ver 5 - if(_mapVersion < 5) return; - - int numTargets = Reader_ReadInt32(_reader); - for(int i = 0; i < numTargets; ++i) - { - xsector_t *xsec = P_ToXSector((Sector *)P_ToPtr(DMU_SECTOR, Reader_ReadInt32(_reader))); - DENG_ASSERT(xsec != 0); - - if(!xsec) - { - DENG_UNUSED(Reader_ReadInt16(_reader)); - continue; - } - - xsec->soundTarget = INT2PTR(mobj_t, Reader_ReadInt16(_reader)); - xsec->soundTarget = - SV_GetArchiveThing(PTR2INT(xsec->soundTarget), &xsec->soundTarget); - } -#endif - } - - Reader *_reader; - int _saveVersion; - int _mapVersion; -}; - void SV_Initialize() { static bool firstInit = true; @@ -3599,12 +2916,9 @@ void SV_Initialize() playerHeaderOK = false; thingArchive = 0; thingArchiveSize = 0; - materialArchive = 0; #if __JHEXEN__ targetPlayerAddrs = 0; saveBuffer = 0; -#else - numSoundTargets = 0; #endif // -1 = Not yet chosen/determined. cvarLastSlot = -1; @@ -3628,19 +2942,6 @@ void SV_Shutdown() inited = false; } -MaterialArchive *SV_MaterialArchive() -{ - DENG_ASSERT(inited); - return materialArchive; -} - -SideArchive &SV_SideArchive() -{ - DENG_ASSERT(inited); - DENG_ASSERT(sideArchive != 0); - return *sideArchive; -} - static bool openGameSaveFile(Str const *fileName, bool write) { #if __JHEXEN__ @@ -3698,7 +2999,7 @@ static int SV_LoadState(Str const *path, SaveInfo *info) G_SetGameAction(GA_NONE); /// @todo Necessary? #if !__JHEXEN__ - initThingArchiveForLoad(info->version() >= 5? Reader_ReadInt32(reader) : 1024 /* num elements */); + SV_InitThingArchiveForLoad(info->version() >= 5? Reader_ReadInt32(reader) : 1024 /* num elements */); #endif readPlayerHeader(reader, info->version()); @@ -3716,13 +3017,6 @@ static int SV_LoadState(Str const *path, SaveInfo *info) Z_Free(saveBuffer); #endif - // Create and populate the MaterialArchive. -#ifdef __JHEXEN__ - materialArchive = MaterialArchive_NewEmpty(true /* segment checks */); -#else - materialArchive = MaterialArchive_NewEmpty(false); -#endif - // Load the current map state. #if __JHEXEN__ readMapState(reader, info->version(), composeGameSavePathForSlot(BASE_SLOT, gameMap+1)); @@ -3738,7 +3032,6 @@ static int SV_LoadState(Str const *path, SaveInfo *info) /* * Cleanup: */ - clearMaterialArchive(); #if !__JHEXEN__ clearThingArchive(); #endif @@ -3948,14 +3241,9 @@ void SV_SaveGameClient(uint gameId) writePlayerHeader(writer); SV_WritePlayer(CONSOLEPLAYER, writer); - // Create and populate the MaterialArchive. - materialArchive = MaterialArchive_New(false); - - MapStateWriter(writer).write(); + MapStateWriter(thingArchiveExcludePlayers).write(writer); /// @todo No consistency bytes in client saves? - clearMaterialArchive(); - SV_CloseFile(); Writer_Delete(writer); delete info; @@ -4026,18 +3314,7 @@ void SV_LoadGameClient(uint gameId) readPlayerHeader(reader, saveInfo->version()); SV_ReadPlayer(cpl, reader); - /** - * Create and populate the MaterialArchive. - * - * @todo Does this really need to be done at all as a client? - * When the client connects to the server it should send a copy - * of the map upon joining, so why are we reading it here? - */ - materialArchive = MaterialArchive_New(false); - - MapStateReader(reader, saveInfo->version()).read(); - - clearMaterialArchive(); + MapStateReader(saveInfo->version()).read(reader); SV_CloseFile(); Reader_Delete(reader); @@ -4070,7 +3347,7 @@ static void readMapState(Reader *reader, int saveVersion) SV_HxSetSaveEndPtr(saveBuffer + bufferSize); #endif - MapStateReader(reader, saveVersion).read(); + MapStateReader(saveVersion).read(reader); #if __JHEXEN__ clearThingArchive(); @@ -4111,13 +3388,6 @@ static int saveStateWorker(Str const *path, SaveInfo *saveInfo) Writer_WriteInt32(writer, thingArchiveSize); #endif - // Create and populate the MaterialArchive. -#ifdef __JHEXEN__ - materialArchive = MaterialArchive_New(true /* segment check */); -#else - materialArchive = MaterialArchive_New(false); -#endif - writePlayerHeader(writer); writePlayers(writer); @@ -4134,12 +3404,11 @@ static int saveStateWorker(Str const *path, SaveInfo *saveInfo) SV_OpenFile(composeGameSavePathForSlot(BASE_SLOT, gameMap+1), "wp"); #endif - MapStateWriter(writer).write(); + MapStateWriter(thingArchiveExcludePlayers).write(writer); SV_WriteConsistencyBytes(); // To be absolutely sure... SV_CloseFile(); - clearMaterialArchive(); #if !__JHEXEN___ clearThingArchive(); #endif @@ -4233,12 +3502,7 @@ void SV_HxSaveClusterMap() Writer *writer = SV_NewWriter(); - // Create and populate the MaterialArchive. - materialArchive = MaterialArchive_New(true); - - MapStateWriter(writer).write(); - - clearMaterialArchive(); + MapStateWriter(thingArchiveExcludePlayers).write(writer); // Close the output file SV_CloseFile(); @@ -4258,16 +3522,11 @@ void SV_HxLoadClusterMap() playerHeaderOK = false; // Uninitialized. - // Create the MaterialArchive. - materialArchive = MaterialArchive_NewEmpty(true); - Reader *reader = SV_NewReader(); // Been here before, load the previous map state. readMapState(reader, info->version(), composeGameSavePathForSlot(BASE_SLOT, gameMap+1)); - clearMaterialArchive(); - Reader_Delete(reader); } diff --git a/doomsday/plugins/common/src/p_scroll.cpp b/doomsday/plugins/common/src/p_scroll.cpp index 9778b7ee68..20a4473b3f 100644 --- a/doomsday/plugins/common/src/p_scroll.cpp +++ b/doomsday/plugins/common/src/p_scroll.cpp @@ -64,8 +64,10 @@ void T_Scroll(scroll_t *s) } } -void scroll_s::write(Writer *writer) const +void scroll_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -80,8 +82,11 @@ void scroll_s::write(Writer *writer) const Writer_WriteInt32(writer, FLT2FIX(offset[1])); } -int scroll_s::read(Reader *reader, int mapVersion) +int scroll_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + /*int ver =*/ Reader_ReadByte(reader); // version byte. // Note: the thinker class byte has already been read. @@ -96,7 +101,7 @@ int scroll_s::read(Reader *reader, int mapVersion) else { // Side index is actually a DMU_ARCHIVE_INDEX. - dmuObject = (Side *)SV_SideArchive().at(sideIndex); + dmuObject = (Side *)msr->sideArchive().at(sideIndex); } DENG_ASSERT(dmuObject != 0); diff --git a/doomsday/plugins/common/src/p_switch.cpp b/doomsday/plugins/common/src/p_switch.cpp index c339a6d513..3f1b8ae26a 100644 --- a/doomsday/plugins/common/src/p_switch.cpp +++ b/doomsday/plugins/common/src/p_switch.cpp @@ -297,8 +297,10 @@ void T_MaterialChanger(void *materialChangerThinker) } } -void materialchanger_s::write(Writer *writer) const +void materialchanger_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -310,11 +312,14 @@ void materialchanger_s::write(Writer *writer) const Writer_WriteInt32(writer, timer); Writer_WriteInt32(writer, P_ToIndex(side)); Writer_WriteByte(writer, (byte) section); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(SV_MaterialArchive(), material)); + Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), material)); } -int materialchanger_s::read(Reader *reader, int mapVersion) +int materialchanger_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + /*int ver =*/ Reader_ReadByte(reader); // Note: the thinker class byte has already been read. @@ -330,12 +335,12 @@ int materialchanger_s::read(Reader *reader, int mapVersion) else { // Side index is actually a DMU_ARCHIVE_INDEX. - side = (Side *)SV_SideArchive().at(sideIndex); + side = (Side *)msr->sideArchive().at(sideIndex); } DENG_ASSERT(side != 0); section = (SideSection) Reader_ReadByte(reader); - material = SV_GetArchiveMaterial(Reader_ReadInt16(reader), 0); + material = msr->archiveMaterial(Reader_ReadInt16(reader), 0); thinker.function = T_MaterialChanger; diff --git a/doomsday/plugins/common/src/p_xgsave.cpp b/doomsday/plugins/common/src/p_xgsave.cpp index 1f386a4814..85ca73f0e3 100644 --- a/doomsday/plugins/common/src/p_xgsave.cpp +++ b/doomsday/plugins/common/src/p_xgsave.cpp @@ -172,8 +172,10 @@ void SV_ReadXGSector(Sector *sec, Reader *reader, int mapVersion) SV_ReadXGFunction(xg, &xg->light, reader, mapVersion); } -void xgplanemover_s::write(Writer *writer) const +void xgplanemover_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 3); // Version. Writer_WriteInt32(writer, P_ToIndex(sector)); @@ -191,7 +193,7 @@ void xgplanemover_s::write(Writer *writer) const Writer_WriteInt32(writer, FLT2FIX(destination)); Writer_WriteInt32(writer, FLT2FIX(speed)); Writer_WriteInt32(writer, FLT2FIX(crushSpeed)); - Writer_WriteInt32(writer, MaterialArchive_FindUniqueSerialId(SV_MaterialArchive(), setMaterial)); + Writer_WriteInt32(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), setMaterial)); Writer_WriteInt32(writer, setSectorType); Writer_WriteInt32(writer, startSound); Writer_WriteInt32(writer, endSound); @@ -201,8 +203,10 @@ void xgplanemover_s::write(Writer *writer) const Writer_WriteInt32(writer, timer); } -int xgplanemover_s::read(Reader *reader, int /*mapVersion*/) +int xgplanemover_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + byte ver = Reader_ReadByte(reader); // Version. sector = (Sector *)P_ToPtr(DMU_SECTOR, Reader_ReadInt32(reader)); @@ -219,7 +223,7 @@ int xgplanemover_s::read(Reader *reader, int /*mapVersion*/) if(ver >= 3) { - setMaterial = SV_GetArchiveMaterial(Reader_ReadInt32(reader), 0); + setMaterial = msr->archiveMaterial(Reader_ReadInt32(reader), 0); } else { diff --git a/doomsday/plugins/common/src/polyobjs.cpp b/doomsday/plugins/common/src/polyobjs.cpp index 6ad8e29a97..91a4d0221c 100644 --- a/doomsday/plugins/common/src/polyobjs.cpp +++ b/doomsday/plugins/common/src/polyobjs.cpp @@ -276,8 +276,10 @@ void T_MovePoly(void *polyThinker) } } -void polyevent_s::write(Writer *writer) const +void polyevent_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -291,8 +293,11 @@ void polyevent_s::write(Writer *writer) const Writer_WriteInt32(writer, FLT2FIX(speed[VY])); } -int polyevent_s::read(Reader *reader, int mapVersion) +int polyevent_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { // Note: the thinker class byte has already been read. @@ -525,8 +530,10 @@ void T_PolyDoor(void *polyDoorThinker) } } -void polydoor_s::write(Writer *writer) const +void polydoor_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. Writer_WriteByte(writer, type); @@ -546,8 +553,11 @@ void polydoor_s::write(Writer *writer) const Writer_WriteByte(writer, close); } -int polydoor_s::read(Reader *reader, int mapVersion) +int polydoor_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/doom/include/p_lights.h b/doomsday/plugins/doom/include/p_lights.h index f2af8ddf90..6bc0781b10 100644 --- a/doomsday/plugins/doom/include/p_lights.h +++ b/doomsday/plugins/doom/include/p_lights.h @@ -20,12 +20,16 @@ #ifndef LIBDOOM_PLAY_LIGHTS_H #define LIBDOOM_PLAY_LIGHTS_H -#include "doomsday.h" - #ifndef __JDOOM__ # error "Using jDoom headers without __JDOOM__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + #define GLOWSPEED (8) #define STROBEBRIGHT (5) #define FASTDARK (15) @@ -39,8 +43,8 @@ typedef struct fireflicker_s { float minLight; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } fireflicker_t; @@ -54,8 +58,8 @@ typedef struct lightflash_s { int minTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } lightflash_t; @@ -69,8 +73,8 @@ typedef struct strobe_s { int brightTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } strobe_t; @@ -82,8 +86,8 @@ typedef struct glow_s { int direction; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } glow_t; diff --git a/doomsday/plugins/doom/src/p_lights.cpp b/doomsday/plugins/doom/src/p_lights.cpp index 2434ca0101..ab13bd62c6 100644 --- a/doomsday/plugins/doom/src/p_lights.cpp +++ b/doomsday/plugins/doom/src/p_lights.cpp @@ -48,8 +48,10 @@ void T_FireFlicker(void *flickPtr) flick->count = 4; } -void fireflicker_s::write(Writer *writer) const +void fireflicker_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -65,8 +67,10 @@ void fireflicker_s::write(Writer *writer) const * T_FireFlicker was added to save games in ver5, therefore we don't have * an old format to support. */ -int fireflicker_s::read(Reader *reader, int /*mapVersion*/) +int fireflicker_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + /*int ver =*/ Reader_ReadByte(reader); // version byte. // Note: the thinker class byte has already been read. @@ -129,8 +133,10 @@ void T_LightFlash(lightflash_t *flash) } } -void lightflash_s::write(Writer *writer) const +void lightflash_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -145,8 +151,11 @@ void lightflash_s::write(Writer *writer) const Writer_WriteInt32(writer, minTime); } -int lightflash_s::read(Reader *reader, int mapVersion) +int lightflash_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -239,8 +248,10 @@ void T_StrobeFlash(strobe_t *flash) } } -void strobe_s::write(Writer *writer) const +void strobe_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -255,8 +266,11 @@ void strobe_s::write(Writer *writer) const Writer_WriteInt32(writer, brightTime); } -int strobe_s::read(Reader *reader, int mapVersion) +int strobe_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -440,8 +454,10 @@ void T_Glow(glow_t *g) P_SetFloatp(g->sector, DMU_LIGHT_LEVEL, lightLevel); } -void glow_s::write(Writer *writer) const +void glow_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -454,8 +470,11 @@ void glow_s::write(Writer *writer) const Writer_WriteInt32(writer, direction); } -int glow_s::read(Reader *reader, int mapVersion) +int glow_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/doom64/include/p_lights.h b/doomsday/plugins/doom64/include/p_lights.h index dbb53b1096..fb4d86a779 100644 --- a/doomsday/plugins/doom64/include/p_lights.h +++ b/doomsday/plugins/doom64/include/p_lights.h @@ -23,12 +23,16 @@ #ifndef LIBDOOM64_PLAY_LIGHTS_H #define LIBDOOM64_PLAY_LIGHTS_H -#include "doomsday.h" - #ifndef __JDOOM64__ # error "Using jDoom64 headers without __JDOOM64__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + #define GLOWSPEED (8) #define STROBEBRIGHT (5) #define FASTDARK (15) @@ -42,8 +46,8 @@ typedef struct fireflicker_s { float minLight; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } fireflicker_t; @@ -57,8 +61,8 @@ typedef struct lightflash_s { int minTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } lightflash_t; @@ -72,8 +76,8 @@ typedef struct lightblink_s { int minTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } lightblink_t; @@ -87,8 +91,8 @@ typedef struct strobe_s { int brightTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } strobe_t; @@ -100,8 +104,8 @@ typedef struct glow_s { int direction; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } glow_t; diff --git a/doomsday/plugins/doom64/src/p_lights.cpp b/doomsday/plugins/doom64/src/p_lights.cpp index ec8717acfd..943ae7e840 100644 --- a/doomsday/plugins/doom64/src/p_lights.cpp +++ b/doomsday/plugins/doom64/src/p_lights.cpp @@ -45,8 +45,10 @@ void T_FireFlicker(fireflicker_t *flick) flick->count = 4; } -void fireflicker_s::write(Writer *writer) const +void fireflicker_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -62,8 +64,10 @@ void fireflicker_s::write(Writer *writer) const * T_FireFlicker was added to save games in ver5, therefore we don't have * an old format to support. */ -int fireflicker_s::read(Reader *reader, int /*mapVersion*/) +int fireflicker_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + /*int ver =*/ Reader_ReadByte(reader); // version byte. // Note: the thinker class byte has already been read. @@ -126,8 +130,10 @@ void T_LightFlash(lightflash_t *flash) } } -void lightflash_s::write(Writer *writer) const +void lightflash_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -142,8 +148,11 @@ void lightflash_s::write(Writer *writer) const Writer_WriteInt32(writer, minTime); } -int lightflash_s::read(Reader *reader, int mapVersion) +int lightflash_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -235,8 +244,10 @@ void T_LightBlink(lightblink_t *flash) } } -void lightblink_s::write(Writer *writer) const +void lightblink_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -255,8 +266,10 @@ void lightblink_s::write(Writer *writer) const * T_LightBlink was added to save games in ver5, therefore we don't have an * old format to support */ -int lightblink_s::read(Reader *reader, int /*mapVersion*/) +int lightblink_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + /*int ver =*/ Reader_ReadByte(reader); // version byte. // Note: the thinker class byte has already been read. @@ -313,8 +326,10 @@ void T_StrobeFlash(strobe_t *flash) } } -void strobe_s::write(Writer *writer) const +void strobe_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -329,8 +344,11 @@ void strobe_s::write(Writer *writer) const Writer_WriteInt32(writer, brightTime); } -int strobe_s::read(Reader *reader, int mapVersion) +int strobe_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -505,8 +523,10 @@ void T_Glow(glow_t *g) P_SetFloatp(g->sector, DMU_LIGHT_LEVEL, lightLevel); } -void glow_s::write(Writer *writer) const +void glow_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -519,8 +539,11 @@ void glow_s::write(Writer *writer) const Writer_WriteInt32(writer, direction); } -int glow_s::read(Reader *reader, int mapVersion) +int glow_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/heretic/include/p_lights.h b/doomsday/plugins/heretic/include/p_lights.h index c7676f0cd9..b5e055e428 100644 --- a/doomsday/plugins/heretic/include/p_lights.h +++ b/doomsday/plugins/heretic/include/p_lights.h @@ -20,12 +20,16 @@ #ifndef LIBHERETIC_PLAY_LIGHTS_H #define LIBHERETIC_PLAY_LIGHTS_H -#include "doomsday.h" - #ifndef __JHERETIC__ # error "Using jHeretic headers without __JHERETIC__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + #define GLOWSPEED (8) #define STROBEBRIGHT (5) #define FASTDARK (15) @@ -41,8 +45,8 @@ typedef struct lightflash_s { int minTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } lightflash_t; @@ -56,8 +60,8 @@ typedef struct strobe_s { int brightTime; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } strobe_t; @@ -69,8 +73,8 @@ typedef struct glow_s { int direction; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } glow_t; diff --git a/doomsday/plugins/heretic/src/p_lights.cpp b/doomsday/plugins/heretic/src/p_lights.cpp index f321f7b5d7..eb3b4fa895 100644 --- a/doomsday/plugins/heretic/src/p_lights.cpp +++ b/doomsday/plugins/heretic/src/p_lights.cpp @@ -49,8 +49,10 @@ void T_LightFlash(lightflash_t *flash) } } -void lightflash_s::write(Writer *writer) const +void lightflash_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -65,8 +67,11 @@ void lightflash_s::write(Writer *writer) const Writer_WriteInt32(writer, minTime); } -int lightflash_s::read(Reader *reader, int mapVersion) +int lightflash_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -158,8 +163,10 @@ void T_StrobeFlash(strobe_t *flash) } } -void strobe_s::write(Writer *writer) const +void strobe_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -174,8 +181,11 @@ void strobe_s::write(Writer *writer) const Writer_WriteInt32(writer, brightTime); } -int strobe_s::read(Reader *reader, int mapVersion) +int strobe_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. @@ -355,8 +365,10 @@ void T_Glow(glow_t *g) P_SetFloatp(g->sector, DMU_LIGHT_LEVEL, lightlevel); } -void glow_s::write(Writer *writer) const +void glow_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -369,8 +381,11 @@ void glow_s::write(Writer *writer) const Writer_WriteInt32(writer, direction); } -int glow_s::read(Reader *reader, int mapVersion) +int glow_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 5) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/hexen/include/acscript.h b/doomsday/plugins/hexen/include/acscript.h index 326a8fac94..35a764a29d 100644 --- a/doomsday/plugins/hexen/include/acscript.h +++ b/doomsday/plugins/hexen/include/acscript.h @@ -28,6 +28,10 @@ #include "jhexen.h" #include "p_mobj.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif #define MAX_ACS_SCRIPT_VARS 10 #define MAX_ACS_MAP_VARS 32 @@ -73,12 +77,12 @@ typedef struct acscript_s { /** * Serialize the thinker to the currently open save file. */ - void write(Writer *writer) const; + void write(MapStateWriter *msw) const; /** * Deserialize the thinker from the currently open save file. */ - int read(Reader *reader, int mapVersion); + int read(MapStateReader *msr); #endif // __cplusplus } ACScript; diff --git a/doomsday/plugins/hexen/include/p_lights.h b/doomsday/plugins/hexen/include/p_lights.h index 387243a5a1..49bdaf5f02 100644 --- a/doomsday/plugins/hexen/include/p_lights.h +++ b/doomsday/plugins/hexen/include/p_lights.h @@ -22,12 +22,16 @@ #ifndef LIBHEXEN_PLAY_LIGHTS_H #define LIBHEXEN_PLAY_LIGHTS_H -#include "doomsday.h" - #ifndef __JHEXEN__ # error "Using jHexen headers without __JHEXEN__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + #define LIGHT_SEQUENCE_START (2) #define LIGHT_SEQUENCE (3) #define LIGHT_SEQUENCE_ALT (4) @@ -53,8 +57,8 @@ typedef struct light_s { int count; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } light_t; @@ -65,8 +69,8 @@ typedef struct phase_s { float baseValue; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } phase_t; diff --git a/doomsday/plugins/hexen/include/p_pillar.h b/doomsday/plugins/hexen/include/p_pillar.h index a69f753bd7..19ed466c34 100644 --- a/doomsday/plugins/hexen/include/p_pillar.h +++ b/doomsday/plugins/hexen/include/p_pillar.h @@ -22,12 +22,16 @@ #ifndef LIBHEXEN_P_PILLAR_H #define LIBHEXEN_P_PILLAR_H -#include "doomsday.h" - #ifndef __JHEXEN__ # error "Using jHexen headers without __JHEXEN__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + typedef struct pillar_s { thinker_t thinker; Sector *sector; @@ -39,8 +43,8 @@ typedef struct pillar_s { int crush; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } pillar_t; diff --git a/doomsday/plugins/hexen/include/p_waggle.h b/doomsday/plugins/hexen/include/p_waggle.h index 739f28e3e4..99e0bea5bf 100644 --- a/doomsday/plugins/hexen/include/p_waggle.h +++ b/doomsday/plugins/hexen/include/p_waggle.h @@ -22,12 +22,16 @@ #ifndef LIBHEXEN_P_WAGGLE_H #define LIBHEXEN_P_WAGGLE_H -#include "doomsday.h" - #ifndef __JHEXEN__ # error "Using jHexen headers without __JHEXEN__" #endif +#include "doomsday.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif + typedef enum { WS_EXPAND = 1, WS_STABLE, @@ -47,8 +51,8 @@ typedef struct waggle_s { wagglestate_e state; #ifdef __cplusplus - void write(Writer *writer) const; - int read(Reader *reader, int mapVersion); + void write(MapStateWriter *msw) const; + int read(MapStateReader *msr); #endif } waggle_t; diff --git a/doomsday/plugins/hexen/src/acscript.cpp b/doomsday/plugins/hexen/src/acscript.cpp index 9aca450da3..fcb7ac5197 100644 --- a/doomsday/plugins/hexen/src/acscript.cpp +++ b/doomsday/plugins/hexen/src/acscript.cpp @@ -1720,8 +1720,10 @@ void ACScript::Stack::drop() height--; } -void ACScript::write(Writer *writer) const +void ACScript::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 2); // Write a version byte. Writer_WriteInt32(writer, SV_ThingArchiveId(activator)); @@ -1741,8 +1743,11 @@ void ACScript::write(Writer *writer) const Writer_WriteInt32(writer, ((byte const *)pcodePtr) - interpreter().bytecode()); } -int ACScript::read(Reader *reader, int mapVersion) +int ACScript::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/hexen/src/p_lights.cpp b/doomsday/plugins/hexen/src/p_lights.cpp index 89047cc685..957b0a2b0e 100644 --- a/doomsday/plugins/hexen/src/p_lights.cpp +++ b/doomsday/plugins/hexen/src/p_lights.cpp @@ -114,8 +114,10 @@ void T_Light(light_t *light) } } -void light_s::write(Writer *writer) const +void light_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -132,8 +134,11 @@ void light_s::write(Writer *writer) const Writer_WriteInt32(writer, count); } -int light_s::read(Reader *reader, int mapVersion) +int light_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { /*int ver =*/ Reader_ReadByte(reader); // version byte. @@ -295,8 +300,10 @@ void T_Phase(phase_t *phase) phase->baseValue + phaseTable[phase->index]); } -void phase_s::write(Writer *writer) const +void phase_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -308,8 +315,11 @@ void phase_s::write(Writer *writer) const Writer_WriteInt32(writer, (int) (255.0f * baseValue)); } -int phase_s::read(Reader *reader, int mapVersion) +int phase_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/hexen/src/p_pillar.cpp b/doomsday/plugins/hexen/src/p_pillar.cpp index fe423c7609..51e75a4750 100644 --- a/doomsday/plugins/hexen/src/p_pillar.cpp +++ b/doomsday/plugins/hexen/src/p_pillar.cpp @@ -43,8 +43,10 @@ void T_BuildPillar(pillar_t *pillar) } } -void pillar_s::write(Writer *writer) const +void pillar_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -60,8 +62,11 @@ void pillar_s::write(Writer *writer) const Writer_WriteInt32(writer, crush); } -int pillar_s::read(Reader *reader, int mapVersion) +int pillar_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { // Note: the thinker class byte has already been read. diff --git a/doomsday/plugins/hexen/src/p_waggle.cpp b/doomsday/plugins/hexen/src/p_waggle.cpp index d26009125a..24649be345 100644 --- a/doomsday/plugins/hexen/src/p_waggle.cpp +++ b/doomsday/plugins/hexen/src/p_waggle.cpp @@ -75,8 +75,10 @@ void T_FloorWaggle(waggle_t *waggle) P_ChangeSector(waggle->sector, 1 /*crush damage*/); } -void waggle_s::write(Writer *writer) const +void waggle_s::write(MapStateWriter *msw) const { + Writer *writer = msw->writer(); + Writer_WriteByte(writer, 1); // Write a version byte. // Note we don't bother to save a byte to tell if the function @@ -94,8 +96,11 @@ void waggle_s::write(Writer *writer) const Writer_WriteInt32(writer, state); } -int waggle_s::read(Reader *reader, int mapVersion) +int waggle_s::read(MapStateReader *msr) { + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); + if(mapVersion >= 4) { /*int ver =*/ Reader_ReadByte(reader); // version byte. From 0d92b47f8b1c7834c01cd19dd65671de056c3981 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 05:43:55 +0000 Subject: [PATCH 06/15] libcommon|MapStateWriter: Typo --- doomsday/plugins/common/src/mapstatewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index 9404f8e43b..19a8a0f9c7 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -232,7 +232,7 @@ MapStateWriter::MapStateWriter(bool excludePlayers) void MapStateWriter::write(Writer *writer) { DENG_ASSERT(writer != 0); - writer = writer; + d->writer = writer; d->beginMapSegment(); { From 919a3f981e785a0b7693d2fafe8e5c5f8fda0606 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 06:23:06 +0000 Subject: [PATCH 07/15] Documentation|libcommon: Improved apidocs for MapStateWriter, MapStateReader; cleanup --- .../plugins/common/include/mapstatereader.h | 27 ++++++++++++++++--- .../plugins/common/include/mapstatewriter.h | 20 +++++++++++++- .../plugins/common/src/mapstatereader.cpp | 13 --------- .../plugins/common/src/mapstatewriter.cpp | 4 +-- doomsday/plugins/common/src/p_floor.cpp | 2 +- doomsday/plugins/common/src/p_saveg.cpp | 10 +++---- doomsday/plugins/common/src/p_switch.cpp | 2 +- doomsday/plugins/common/src/p_xgsave.cpp | 2 +- 8 files changed, 53 insertions(+), 27 deletions(-) diff --git a/doomsday/plugins/common/include/mapstatereader.h b/doomsday/plugins/common/include/mapstatereader.h index 0d62096a1a..97a6ed0c75 100644 --- a/doomsday/plugins/common/include/mapstatereader.h +++ b/doomsday/plugins/common/include/mapstatereader.h @@ -24,13 +24,34 @@ #include "common.h" #include "dmu_archiveindex.h" +/** + * Performs saved game map state deserialization. + * + * @ingroup libcommon + */ class MapStateReader { public: + /** + * @param saveVersion Logical saved state version number. + */ MapStateReader(int saveVersion); + /** + * Deserialize the saved map state using the specified @a reader. + */ void read(Reader *reader); + /** + * Returns the logical map version of the saved map state. + */ + int mapVersion(); + + /** + * Returns the reader to use when deserializing the saved map state. + */ + Reader *reader(); + /** * Finds and returns a material with the identifier @a serialId. * @@ -42,9 +63,9 @@ class MapStateReader */ Material *archiveMaterial(materialarchive_serialid_t serialId, int group); - Reader *reader(); - int mapVersion(); - MaterialArchive *materialArchive(); + /** + * Provides access to the side archive to use when serializing the map state. + */ dmu_lib::SideArchive &sideArchive(); private: diff --git a/doomsday/plugins/common/include/mapstatewriter.h b/doomsday/plugins/common/include/mapstatewriter.h index 1dce3675b0..97e61cbc81 100644 --- a/doomsday/plugins/common/include/mapstatewriter.h +++ b/doomsday/plugins/common/include/mapstatewriter.h @@ -23,15 +23,33 @@ #include "common.h" +/** + * Performs saved game map state serialization. + * + * @ingroup libcommon + */ class MapStateWriter { public: + /** + * @param excludePlayers Exclude player data. Used by Hexen when serializing hubs. + */ MapStateWriter(bool excludePlayers = false); + /** + * Serialize the map state using the specified @a reader. + */ void write(Writer *writer); + /** + * Returns a unique SerialId for the specified @a material. + */ + materialarchive_serialid_t archiveMaterialId(Material *material); + + /** + * Returns the writer to use when serializing the map state. + */ Writer *writer(); - MaterialArchive *materialArchive(); private: DENG2_PRIVATE(d) diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index fb8bfdfc49..cdc2002c2e 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -274,10 +274,6 @@ DENG2_PIMPL(MapStateReader) #endif } - /** - * Update the references between thinkers. To be called during the load - * process to finalize the loaded thinkers. - */ void relinkThinkers() { #if __JHEXEN__ @@ -303,9 +299,6 @@ DENG2_PIMPL(MapStateReader) #endif } - /** - * Deserialize and then spawns thinkers for both client and server. - */ void readThinkers() { bool const formatHasStasisInfo = (mapVersion >= 6); @@ -532,12 +525,6 @@ Material *MapStateReader::archiveMaterial(materialarchive_serialid_t serialId, i return MaterialArchive_Find(d->materialArchive, serialId, group); } -MaterialArchive *MapStateReader::materialArchive() -{ - DENG_ASSERT(d->materialArchive != 0); - return d->materialArchive; -} - dmu_lib::SideArchive &MapStateReader::sideArchive() { DENG_ASSERT(d->sideArchive != 0); diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index 19a8a0f9c7..855413d50a 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -254,8 +254,8 @@ Writer *MapStateWriter::writer() return d->writer; } -MaterialArchive *MapStateWriter::materialArchive() +materialarchive_serialid_t MapStateWriter::archiveMaterialId(Material *material) { DENG_ASSERT(d->materialArchive != 0); - return d->materialArchive; + return MaterialArchive_FindUniqueSerialId(d->materialArchive, material); } diff --git a/doomsday/plugins/common/src/p_floor.cpp b/doomsday/plugins/common/src/p_floor.cpp index 631208302a..24df97a6ee 100644 --- a/doomsday/plugins/common/src/p_floor.cpp +++ b/doomsday/plugins/common/src/p_floor.cpp @@ -413,7 +413,7 @@ void floor_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, (int) state); Writer_WriteInt32(writer, newSpecial); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), material)); + Writer_WriteInt16(writer, msw->archiveMaterialId(material)); Writer_WriteInt16(writer, (int) floorDestHeight); Writer_WriteInt32(writer, FLT2FIX(speed)); diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 5db4f3a173..411dcf3ee2 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -2315,8 +2315,8 @@ void SV_WriteSector(Sector *sec, MapStateWriter *msw) Writer_WriteInt16(writer, floorheight); Writer_WriteInt16(writer, ceilingheight); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), floorMaterial)); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), ceilingMaterial)); + Writer_WriteInt16(writer, msw->archiveMaterialId(floorMaterial)); + Writer_WriteInt16(writer, msw->archiveMaterialId(ceilingMaterial)); Writer_WriteInt16(writer, floorFlags); Writer_WriteInt16(writer, ceilingFlags); #if __JHEXEN__ @@ -2574,9 +2574,9 @@ void SV_WriteLine(Line *li, MapStateWriter *msw) Writer_WriteInt16(writer, P_GetIntp(si, DMU_MIDDLE_FLAGS)); Writer_WriteInt16(writer, P_GetIntp(si, DMU_BOTTOM_FLAGS)); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), (Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); + Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); + Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); + Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); P_GetFloatpv(si, DMU_TOP_COLOR, rgba); for(int k = 0; k < 3; ++k) diff --git a/doomsday/plugins/common/src/p_switch.cpp b/doomsday/plugins/common/src/p_switch.cpp index 3f1b8ae26a..3b6d18e32e 100644 --- a/doomsday/plugins/common/src/p_switch.cpp +++ b/doomsday/plugins/common/src/p_switch.cpp @@ -312,7 +312,7 @@ void materialchanger_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, timer); Writer_WriteInt32(writer, P_ToIndex(side)); Writer_WriteByte(writer, (byte) section); - Writer_WriteInt16(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), material)); + Writer_WriteInt16(writer, msw->archiveMaterialId(material)); } int materialchanger_s::read(MapStateReader *msr) diff --git a/doomsday/plugins/common/src/p_xgsave.cpp b/doomsday/plugins/common/src/p_xgsave.cpp index 85ca73f0e3..b9d35e1301 100644 --- a/doomsday/plugins/common/src/p_xgsave.cpp +++ b/doomsday/plugins/common/src/p_xgsave.cpp @@ -193,7 +193,7 @@ void xgplanemover_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, FLT2FIX(destination)); Writer_WriteInt32(writer, FLT2FIX(speed)); Writer_WriteInt32(writer, FLT2FIX(crushSpeed)); - Writer_WriteInt32(writer, MaterialArchive_FindUniqueSerialId(msw->materialArchive(), setMaterial)); + Writer_WriteInt32(writer, msw->archiveMaterialId(setMaterial)); Writer_WriteInt32(writer, setSectorType); Writer_WriteInt32(writer, startSound); Writer_WriteInt32(writer, endSound); From d03d8dd57bc1df006e9ba3e7a37d3122504500fd Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 06:33:51 +0000 Subject: [PATCH 08/15] Refactor|libcommon|MapStateWriter|MapStateReader: Better names for some MapStateWriter/Reader methods --- .../plugins/common/include/mapstatereader.h | 4 ++-- .../plugins/common/include/mapstatewriter.h | 2 +- .../plugins/common/src/mapstatereader.cpp | 2 +- .../plugins/common/src/mapstatewriter.cpp | 2 +- doomsday/plugins/common/src/p_floor.cpp | 4 ++-- doomsday/plugins/common/src/p_saveg.cpp | 20 +++++++++---------- doomsday/plugins/common/src/p_switch.cpp | 4 ++-- doomsday/plugins/common/src/p_xgsave.cpp | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/doomsday/plugins/common/include/mapstatereader.h b/doomsday/plugins/common/include/mapstatereader.h index 97a6ed0c75..6ce7f28cea 100644 --- a/doomsday/plugins/common/include/mapstatereader.h +++ b/doomsday/plugins/common/include/mapstatereader.h @@ -61,10 +61,10 @@ class MapStateReader * * @return Pointer to the associated material; otherwise @c 0 (not archived). */ - Material *archiveMaterial(materialarchive_serialid_t serialId, int group); + Material *material(materialarchive_serialid_t serialId, int group); /** - * Provides access to the side archive to use when serializing the map state. + * Provides access to the side archive to use when deserializing the map state. */ dmu_lib::SideArchive &sideArchive(); diff --git a/doomsday/plugins/common/include/mapstatewriter.h b/doomsday/plugins/common/include/mapstatewriter.h index 97e61cbc81..3b7210e16d 100644 --- a/doomsday/plugins/common/include/mapstatewriter.h +++ b/doomsday/plugins/common/include/mapstatewriter.h @@ -44,7 +44,7 @@ class MapStateWriter /** * Returns a unique SerialId for the specified @a material. */ - materialarchive_serialid_t archiveMaterialId(Material *material); + materialarchive_serialid_t serialIdFor(Material *material); /** * Returns the writer to use when serializing the map state. diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index cdc2002c2e..f293adb52b 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -519,7 +519,7 @@ int MapStateReader::mapVersion() return d->mapVersion; } -Material *MapStateReader::archiveMaterial(materialarchive_serialid_t serialId, int group) +Material *MapStateReader::material(materialarchive_serialid_t serialId, int group) { DENG_ASSERT(d->materialArchive != 0); return MaterialArchive_Find(d->materialArchive, serialId, group); diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index 855413d50a..1a4dd85265 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -254,7 +254,7 @@ Writer *MapStateWriter::writer() return d->writer; } -materialarchive_serialid_t MapStateWriter::archiveMaterialId(Material *material) +materialarchive_serialid_t MapStateWriter::serialIdFor(Material *material) { DENG_ASSERT(d->materialArchive != 0); return MaterialArchive_FindUniqueSerialId(d->materialArchive, material); diff --git a/doomsday/plugins/common/src/p_floor.cpp b/doomsday/plugins/common/src/p_floor.cpp index 24df97a6ee..58d4c54a92 100644 --- a/doomsday/plugins/common/src/p_floor.cpp +++ b/doomsday/plugins/common/src/p_floor.cpp @@ -413,7 +413,7 @@ void floor_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, (int) state); Writer_WriteInt32(writer, newSpecial); - Writer_WriteInt16(writer, msw->archiveMaterialId(material)); + Writer_WriteInt16(writer, msw->serialIdFor(material)); Writer_WriteInt16(writer, (int) floorDestHeight); Writer_WriteInt32(writer, FLT2FIX(speed)); @@ -451,7 +451,7 @@ int floor_s::read(MapStateReader *msr) if(ver >= 2) { - material = msr->archiveMaterial(Reader_ReadInt16(reader), 0); + material = msr->material(Reader_ReadInt16(reader), 0); } else { diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 411dcf3ee2..46c6d677ce 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -2315,8 +2315,8 @@ void SV_WriteSector(Sector *sec, MapStateWriter *msw) Writer_WriteInt16(writer, floorheight); Writer_WriteInt16(writer, ceilingheight); - Writer_WriteInt16(writer, msw->archiveMaterialId(floorMaterial)); - Writer_WriteInt16(writer, msw->archiveMaterialId(ceilingMaterial)); + Writer_WriteInt16(writer, msw->serialIdFor(floorMaterial)); + Writer_WriteInt16(writer, msw->serialIdFor(ceilingMaterial)); Writer_WriteInt16(writer, floorFlags); Writer_WriteInt16(writer, ceilingFlags); #if __JHEXEN__ @@ -2431,8 +2431,8 @@ void SV_ReadSector(Sector *sec, MapStateReader *msr) #endif { // The flat numbers are actually archive numbers. - floorMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 0); - ceilingMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 0); + floorMaterial = msr->material(Reader_ReadInt16(reader), 0); + ceilingMaterial = msr->material(Reader_ReadInt16(reader), 0); } P_SetPtrp(sec, DMU_FLOOR_MATERIAL, floorMaterial); @@ -2574,9 +2574,9 @@ void SV_WriteLine(Line *li, MapStateWriter *msw) Writer_WriteInt16(writer, P_GetIntp(si, DMU_MIDDLE_FLAGS)); Writer_WriteInt16(writer, P_GetIntp(si, DMU_BOTTOM_FLAGS)); - Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); - Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); - Writer_WriteInt16(writer, msw->archiveMaterialId((Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); + Writer_WriteInt16(writer, msw->serialIdFor((Material *)P_GetPtrp(si, DMU_TOP_MATERIAL))); + Writer_WriteInt16(writer, msw->serialIdFor((Material *)P_GetPtrp(si, DMU_BOTTOM_MATERIAL))); + Writer_WriteInt16(writer, msw->serialIdFor((Material *)P_GetPtrp(si, DMU_MIDDLE_MATERIAL))); P_GetFloatpv(si, DMU_TOP_COLOR, rgba); for(int k = 0; k < 3; ++k) @@ -2755,9 +2755,9 @@ void SV_ReadLine(Line *li, MapStateReader *msr) if(mapVersion >= 4) #endif { - topMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); - bottomMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); - middleMaterial = msr->archiveMaterial(Reader_ReadInt16(reader), 1); + topMaterial = msr->material(Reader_ReadInt16(reader), 1); + bottomMaterial = msr->material(Reader_ReadInt16(reader), 1); + middleMaterial = msr->material(Reader_ReadInt16(reader), 1); } P_SetPtrp(si, DMU_TOP_MATERIAL, topMaterial); diff --git a/doomsday/plugins/common/src/p_switch.cpp b/doomsday/plugins/common/src/p_switch.cpp index 3b6d18e32e..7fccf0bdb6 100644 --- a/doomsday/plugins/common/src/p_switch.cpp +++ b/doomsday/plugins/common/src/p_switch.cpp @@ -312,7 +312,7 @@ void materialchanger_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, timer); Writer_WriteInt32(writer, P_ToIndex(side)); Writer_WriteByte(writer, (byte) section); - Writer_WriteInt16(writer, msw->archiveMaterialId(material)); + Writer_WriteInt16(writer, msw->serialIdFor(material)); } int materialchanger_s::read(MapStateReader *msr) @@ -340,7 +340,7 @@ int materialchanger_s::read(MapStateReader *msr) DENG_ASSERT(side != 0); section = (SideSection) Reader_ReadByte(reader); - material = msr->archiveMaterial(Reader_ReadInt16(reader), 0); + material = msr->material(Reader_ReadInt16(reader), 0); thinker.function = T_MaterialChanger; diff --git a/doomsday/plugins/common/src/p_xgsave.cpp b/doomsday/plugins/common/src/p_xgsave.cpp index b9d35e1301..3b65ec5511 100644 --- a/doomsday/plugins/common/src/p_xgsave.cpp +++ b/doomsday/plugins/common/src/p_xgsave.cpp @@ -193,7 +193,7 @@ void xgplanemover_s::write(MapStateWriter *msw) const Writer_WriteInt32(writer, FLT2FIX(destination)); Writer_WriteInt32(writer, FLT2FIX(speed)); Writer_WriteInt32(writer, FLT2FIX(crushSpeed)); - Writer_WriteInt32(writer, msw->archiveMaterialId(setMaterial)); + Writer_WriteInt32(writer, msw->serialIdFor(setMaterial)); Writer_WriteInt32(writer, setSectorType); Writer_WriteInt32(writer, startSound); Writer_WriteInt32(writer, endSound); @@ -223,7 +223,7 @@ int xgplanemover_s::read(MapStateReader *msr) if(ver >= 3) { - setMaterial = msr->archiveMaterial(Reader_ReadInt32(reader), 0); + setMaterial = msr->material(Reader_ReadInt32(reader), 0); } else { From 4f2e70e511baa89c838f236e4ecfaf1257e9b3ec Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 07:42:16 +0000 Subject: [PATCH 09/15] libcommon|MapStateReader: Throw a ReadError if a map saved state fails segment alignment check --- .../plugins/common/include/mapstatereader.h | 5 +++ .../plugins/common/src/mapstatereader.cpp | 31 ++++++++++++++----- .../plugins/common/src/mapstatewriter.cpp | 23 +++++++++----- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/doomsday/plugins/common/include/mapstatereader.h b/doomsday/plugins/common/include/mapstatereader.h index 6ce7f28cea..9294f67528 100644 --- a/doomsday/plugins/common/include/mapstatereader.h +++ b/doomsday/plugins/common/include/mapstatereader.h @@ -23,6 +23,7 @@ #include "common.h" #include "dmu_archiveindex.h" +#include /** * Performs saved game map state deserialization. @@ -31,6 +32,10 @@ */ class MapStateReader { +public: + /// Base class for read-related errors. @ingroup errors + DENG2_ERROR(ReadError); + public: /** * @param saveVersion Logical saved state version number. diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index f293adb52b..ba2037a530 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -25,6 +25,7 @@ #include "p_actor.h" #include "p_saveg.h" #include "p_saveio.h" +#include DENG2_PIMPL(MapStateReader) { @@ -43,6 +44,22 @@ DENG2_PIMPL(MapStateReader) , sideArchive(0) {} + void checkSegment(int segId) + { +#if __JHEXEN__ + if(segId == ASEG_END && SV_HxBytesLeft() < 4) + { + App_Log(DE2_LOG_WARNING, "Savegame lacks ASEG_END marker (unexpected end-of-file)"); + return; + } + if(Reader_ReadInt32(reader) != segId) + { + /// @throw ReadError Failed alignment check. + throw ReadError("MapStateReader::assertSegment", "Corrupt save game, segment " + de::String::number(segId) + " failed alignment check"); + } +#endif + } + void beginMapSegment() { savestatesegment_t segId; @@ -78,7 +95,7 @@ DENG2_PIMPL(MapStateReader) void endMapSegment() { - SV_AssertSegment(ASEG_END); + checkSegment(ASEG_END); delete sideArchive; sideArchive = 0; MaterialArchive_Delete(materialArchive); materialArchive = 0; @@ -86,7 +103,7 @@ DENG2_PIMPL(MapStateReader) void readElements() { - SV_AssertSegment(ASEG_MAP_ELEMENTS); + checkSegment(ASEG_MAP_ELEMENTS); // Sectors. for(int i = 0; i < numsectors; ++i) @@ -104,7 +121,7 @@ DENG2_PIMPL(MapStateReader) void readPolyobjs() { #if __JHEXEN__ - SV_AssertSegment(ASEG_POLYOBJS); + checkSegment(ASEG_POLYOBJS); int const writtenPolyobjCount = Reader_ReadInt32(reader); DENG_ASSERT(writtenPolyobjCount == numpolyobjs); @@ -307,10 +324,10 @@ DENG2_PIMPL(MapStateReader) #if __JHEXEN__ if(mapVersion < 4) - SV_AssertSegment(ASEG_MOBJS); + checkSegment(ASEG_MOBJS); else #endif - SV_AssertSegment(ASEG_THINKERS); + checkSegment(ASEG_THINKERS); #if __JHEXEN__ SV_InitTargetPlayers(); @@ -352,7 +369,7 @@ DENG2_PIMPL(MapStateReader) if(tClass == TC_MOBJ && (uint)i == thingArchiveSize) { - SV_AssertSegment(ASEG_THINKERS); + checkSegment(ASEG_THINKERS); // We have reached the begining of the "specials" block. reachedSpecialsBlock = true; continue; @@ -437,7 +454,7 @@ DENG2_PIMPL(MapStateReader) void readMisc() { #if __JHEXEN__ - SV_AssertSegment(ASEG_MISC); + checkSegment(ASEG_MISC); for(int i = 0; i < MAXPLAYERS; ++i) { diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index 1a4dd85265..c6d2b9be74 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -38,9 +38,19 @@ DENG2_PIMPL(MapStateWriter) , materialArchive(0) {} + void beginSegment(int segId) + { + SV_BeginSegment(segId); + } + + void endSegment() + { + SV_EndSegment(); + } + void beginMapSegment() { - SV_BeginSegment(ASEG_MAP_HEADER2); + beginSegment(ASEG_MAP_HEADER2); #if __JHEXEN__ Writer_WriteByte(writer, MY_SAVE_VERSION); // Map version also. @@ -60,14 +70,13 @@ DENG2_PIMPL(MapStateWriter) void endMapSegment() { - SV_EndSegment(); - + endSegment(); MaterialArchive_Delete(materialArchive); materialArchive = 0; } void writeElements() { - SV_BeginSegment(ASEG_MAP_ELEMENTS); + beginSegment(ASEG_MAP_ELEMENTS); for(int i = 0; i < numsectors; ++i) { @@ -83,7 +92,7 @@ DENG2_PIMPL(MapStateWriter) void writePolyobjs() { #if __JHEXEN__ - SV_BeginSegment(ASEG_POLYOBJS); + beginSegment(ASEG_POLYOBJS); Writer_WriteInt32(writer, numpolyobjs); for(int i = 0; i < numpolyobjs; ++i) @@ -141,7 +150,7 @@ DENG2_PIMPL(MapStateWriter) */ void writeThinkers() { - SV_BeginSegment(ASEG_THINKERS); + beginSegment(ASEG_THINKERS); #if __JHEXEN__ Writer_WriteInt32(writer, thingArchiveSize); // number of mobjs. @@ -213,7 +222,7 @@ DENG2_PIMPL(MapStateWriter) void writeMisc() { #if __JHEXEN__ - SV_BeginSegment(ASEG_MISC); + beginSegment(ASEG_MISC); for(int i = 0; i < MAXPLAYERS; ++i) { From 8d79dbde8888148b135397625ede7dd40b9798bc Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 08:07:26 +0000 Subject: [PATCH 10/15] libcommon|MapStateWriter|MapStateReader: Moved more logic into MapStateWriter/Reader --- doomsday/plugins/common/include/p_saveio.h | 9 ------- .../plugins/common/src/mapstatereader.cpp | 26 +++++++++++++++---- .../plugins/common/src/mapstatewriter.cpp | 6 +++-- doomsday/plugins/common/src/p_saveg.cpp | 5 ++++ doomsday/plugins/common/src/p_saveio.cpp | 14 ---------- doomsday/plugins/hexen/src/acscript.cpp | 7 ----- doomsday/plugins/hexen/src/sn_sonix.cpp | 4 --- 7 files changed, 30 insertions(+), 41 deletions(-) diff --git a/doomsday/plugins/common/include/p_saveio.h b/doomsday/plugins/common/include/p_saveio.h index 19cddf04e8..5017527d2e 100644 --- a/doomsday/plugins/common/include/p_saveio.h +++ b/doomsday/plugins/common/include/p_saveio.h @@ -85,15 +85,6 @@ dd_bool SV_HxBytesLeft(void); */ void SV_AssertSegment(int segmentId); -/** - * Special case segment check for the map state. - * - * @param retSegmentId If not @c 0 return the determined segment id. - * - * @todo Refactor away. - */ -void SV_AssertMapSegment(savestatesegment_t *retSegmentId); - void SV_BeginSegment(int segmentId); void SV_EndSegment(); diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index ba2037a530..0c8d8cb222 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -55,20 +55,34 @@ DENG2_PIMPL(MapStateReader) if(Reader_ReadInt32(reader) != segId) { /// @throw ReadError Failed alignment check. - throw ReadError("MapStateReader::assertSegment", "Corrupt save game, segment " + de::String::number(segId) + " failed alignment check"); + throw ReadError("MapStateReader::checkSegment", "Corrupt save game, segment " + de::String::number(segId) + " failed alignment check"); } #endif } - void beginMapSegment() + /// Special case check for the top-level map state segment. + void checkMapSegment() { - savestatesegment_t segId; - SV_AssertMapSegment(&segId); - #if __JHEXEN__ + int segId = Reader_ReadInt32(reader); + if(segId != ASEG_MAP_HEADER2 && segId != ASEG_MAP_HEADER) + { + /// @throw ReadError Failed alignment check. + throw ReadError("MapStateReader::checkSegment", "Corrupt save game, segment " + de::String::number(segId) + " failed alignment check"); + } + // Maps have their own version number, in Hexen. mapVersion = (segId == ASEG_MAP_HEADER2? Reader_ReadByte(reader) : 2); +#else + checkSegment(ASEG_MAP_HEADER2); +#endif + } + + void beginMapSegment() + { + checkMapSegment(); +#if __JHEXEN__ thingArchiveVersion = mapVersion >= 4? 1 : 0; #endif @@ -440,6 +454,7 @@ DENG2_PIMPL(MapStateReader) void readACScriptData() { #if __JHEXEN__ + checkSegment(ASEG_SCRIPTS); Game_ACScriptInterpreter().readMapScriptData(reader, mapVersion); #endif } @@ -447,6 +462,7 @@ DENG2_PIMPL(MapStateReader) void readSoundSequences() { #if __JHEXEN__ + checkSegment(ASEG_SOUNDS); SN_ReadSequences(reader, mapVersion); #endif } diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index c6d2b9be74..f8a409d861 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -38,9 +38,9 @@ DENG2_PIMPL(MapStateWriter) , materialArchive(0) {} - void beginSegment(int segId) + void beginSegment(int segmentId) { - SV_BeginSegment(segId); + SV_BeginSegment(segmentId); } void endSegment() @@ -169,6 +169,7 @@ DENG2_PIMPL(MapStateWriter) void writeACScriptData() { #if __JHEXEN__ + beginSegment(ASEG_SCRIPTS); Game_ACScriptInterpreter().writeMapScriptData(writer); #endif } @@ -176,6 +177,7 @@ DENG2_PIMPL(MapStateWriter) void writeSoundSequences() { #if __JHEXEN__ + beginSegment(ASEG_SOUNDS); SN_WriteSequences(writer); #endif } diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 46c6d677ce..bdc62a4668 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -2983,6 +2983,10 @@ static int SV_LoadState(Str const *path, SaveInfo *info) curInfo = info; #if __JHEXEN__ + if(info->version() >= 7) + { + SV_AssertSegment(ASEG_GLOBALSCRIPTDATA); + } Game_ACScriptInterpreter().readWorldScriptData(reader, info->version()); #endif @@ -3378,6 +3382,7 @@ static int saveStateWorker(Str const *path, SaveInfo *saveInfo) saveInfo->write(writer); #if __JHEXEN__ + SV_BeginSegment(ASEG_GLOBALSCRIPTDATA); Game_ACScriptInterpreter().writeWorldScriptData(writer); #endif diff --git a/doomsday/plugins/common/src/p_saveio.cpp b/doomsday/plugins/common/src/p_saveio.cpp index 266893a449..a0b08dd15d 100644 --- a/doomsday/plugins/common/src/p_saveio.cpp +++ b/doomsday/plugins/common/src/p_saveio.cpp @@ -348,20 +348,6 @@ void SV_AssertSegment(int segmentId) #endif } -void SV_AssertMapSegment(savestatesegment_t *retSegmentId) -{ -#if __JHEXEN__ - int segmentId = SV_ReadLong(); - if(segmentId != ASEG_MAP_HEADER2 && segmentId != ASEG_MAP_HEADER) - Con_Error("Corrupt save game: Segment [%d] failed alignment check", segmentId); - - if(retSegmentId) *retSegmentId = savestatesegment_t(segmentId); -#else - SV_AssertSegment(ASEG_MAP_HEADER2); - if(retSegmentId) *retSegmentId = ASEG_MAP_HEADER2; -#endif -} - void SV_BeginSegment(int segType) { errorIfNotInited("SV_BeginSegment"); diff --git a/doomsday/plugins/hexen/src/acscript.cpp b/doomsday/plugins/hexen/src/acscript.cpp index fcb7ac5197..ebc19a5b34 100644 --- a/doomsday/plugins/hexen/src/acscript.cpp +++ b/doomsday/plugins/hexen/src/acscript.cpp @@ -477,8 +477,6 @@ void ACScriptInterpreter::scriptFinished(ACScript *script) void ACScriptInterpreter::writeWorldScriptData(Writer *writer) { - SV_BeginSegment(ASEG_GLOBALSCRIPTDATA); - Writer_WriteByte(writer, 4); // version byte for(int i = 0; i < MAX_ACS_WORLD_VARS; ++i) @@ -500,7 +498,6 @@ void ACScriptInterpreter::readWorldScriptData(Reader *reader, int mapVersion) if(mapVersion >= 7) { - SV_AssertSegment(ASEG_GLOBALSCRIPTDATA); ver = Reader_ReadByte(reader); } @@ -553,8 +550,6 @@ void ACScriptInterpreter::readWorldScriptData(Reader *reader, int mapVersion) void ACScriptInterpreter::writeMapScriptData(Writer *writer) { - SV_BeginSegment(ASEG_SCRIPTS); - for(int i = 0; i < _scriptCount; ++i) { BytecodeScriptInfo &info = _scriptInfo[i]; @@ -570,8 +565,6 @@ void ACScriptInterpreter::writeMapScriptData(Writer *writer) void ACScriptInterpreter::readMapScriptData(Reader *reader, int /*mapVersion*/) { - SV_AssertSegment(ASEG_SCRIPTS); - for(int i = 0; i < _scriptCount; ++i) { BytecodeScriptInfo &info = _scriptInfo[i]; diff --git a/doomsday/plugins/hexen/src/sn_sonix.cpp b/doomsday/plugins/hexen/src/sn_sonix.cpp index c7a2808431..8a8fbbf58d 100644 --- a/doomsday/plugins/hexen/src/sn_sonix.cpp +++ b/doomsday/plugins/hexen/src/sn_sonix.cpp @@ -492,8 +492,6 @@ void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume, void SN_WriteSequences(Writer *writer) { - SV_BeginSegment(ASEG_SOUNDS); - Writer_WriteInt32(writer, activeSequenceCount); for(seqnode_t *node = sequences; node; node = node->next) { @@ -536,8 +534,6 @@ void SN_WriteSequences(Writer *writer) void SN_ReadSequences(Reader *reader, int mapVersion) { - SV_AssertSegment(ASEG_SOUNDS); - // Reload and restart all sound sequences int numSequences = Reader_ReadInt32(reader); From f7873024185cd986a27fb1272bdbc96a3450410a Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 09:36:26 +0000 Subject: [PATCH 11/15] Refactor|libcommon: Separated saved game thinker info db into new source files --- doomsday/plugins/common/common.pri | 2 + doomsday/plugins/common/include/p_saveg.h | 84 +----- doomsday/plugins/common/include/p_tick.h | 56 ++-- doomsday/plugins/common/include/thinkerinfo.h | 97 +++++++ .../plugins/common/src/mapstatereader.cpp | 1 + .../plugins/common/src/mapstatewriter.cpp | 1 + doomsday/plugins/common/src/p_saveg.cpp | 257 +----------------- doomsday/plugins/common/src/p_tick.c | 7 - doomsday/plugins/common/src/thinkerinfo.cpp | 251 +++++++++++++++++ 9 files changed, 399 insertions(+), 357 deletions(-) create mode 100644 doomsday/plugins/common/include/thinkerinfo.h create mode 100644 doomsday/plugins/common/src/thinkerinfo.cpp diff --git a/doomsday/plugins/common/common.pri b/doomsday/plugins/common/common.pri index 72c68fdbcb..fdba754ce6 100644 --- a/doomsday/plugins/common/common.pri +++ b/doomsday/plugins/common/common.pri @@ -67,6 +67,7 @@ HEADERS += \ $$common_inc/polyobjs.h \ $$common_inc/r_common.h \ $$common_inc/saveinfo.h \ + $$common_inc/thinkerinfo.h \ $$common_inc/x_hair.h \ $$common_inc/xgclass.h @@ -129,4 +130,5 @@ SOURCES += \ $$common_src/polyobjs.cpp \ $$common_src/r_common.c \ $$common_src/saveinfo.cpp \ + $$common_src/thinkerinfo.cpp \ $$common_src/x_hair.c diff --git a/doomsday/plugins/common/include/p_saveg.h b/doomsday/plugins/common/include/p_saveg.h index 1e12a78bd1..37713ab771 100644 --- a/doomsday/plugins/common/include/p_saveg.h +++ b/doomsday/plugins/common/include/p_saveg.h @@ -21,72 +21,12 @@ #ifndef LIBCOMMON_SAVESTATE_H #define LIBCOMMON_SAVESTATE_H +#include "common.h" #ifdef __cplusplus -#include "dmu_archiveindex.h" +# include "dmu_archiveindex.h" #endif #include "p_saveio.h" -/** - * Original indices must remain unchanged! - * Added new think classes to the end. - */ -typedef enum thinkclass_e { - TC_NULL = -1, - TC_END, - TC_MOBJ, - TC_XGMOVER, - TC_CEILING, - TC_DOOR, - TC_FLOOR, - TC_PLAT, -#if __JHEXEN__ - TC_INTERPRET_ACS, - TC_FLOOR_WAGGLE, - TC_LIGHT, - TC_PHASE, - TC_BUILD_PILLAR, - TC_ROTATE_POLY, - TC_MOVE_POLY, - TC_POLY_DOOR, -#else - TC_FLASH, - TC_STROBE, -# if __JDOOM__ || __JDOOM64__ - TC_GLOW, - TC_FLICKER, -# if __JDOOM64__ - TC_BLINK, -# endif -# else - TC_GLOW, -# endif -#endif - TC_MATERIALCHANGER, - TC_SCROLL, - NUMTHINKERCLASSES -} thinkerclass_t; - -#ifdef __cplusplus -class MapStateReader; -class MapStateWriter; - -// Thinker Save flags -#define TSF_SERVERONLY 0x01 ///< Only saved by servers. - -typedef void (*WriteThinkerFunc)(thinker_t *, MapStateWriter *writer); -typedef int (*ReadThinkerFunc)(thinker_t *, MapStateReader *reader); - -struct ThinkerClassInfo -{ - thinkerclass_t thinkclass; - thinkfunc_t function; - int flags; - WriteThinkerFunc writeFunc; - ReadThinkerFunc readFunc; - size_t size; -}; -#endif - DENG_EXTERN_C int thingArchiveVersion; DENG_EXTERN_C uint thingArchiveSize; @@ -217,18 +157,6 @@ void SV_LoadGameClient(uint gameId); uint SV_GenerateGameId(void); -#ifdef __cplusplus -/** - * Returns the info for the specified thinker @a tClass; otherwise @c 0 if not found. - */ -ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass); - -/** - * Returns the info for the specified thinker; otherwise @c 0 if not found. - */ -ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker); -#endif - /// Unique identifier associated with each archived thing. #if __JHEXEN__ typedef int ThingSerialId; @@ -301,6 +229,14 @@ void SV_InitTargetPlayers(void); class MapStateReader; class MapStateWriter; +void SV_WriteMobj(thinker_t *th, MapStateWriter *msw); +int SV_ReadMobj(thinker_t *th, MapStateReader *msr); + +#if __JHEXEN__ +void SV_WriteMovePoly(struct polyevent_s const *movepoly, MapStateWriter *msw); +int SV_ReadMovePoly(struct polyevent_s *movepoly, MapStateReader *msr); +#endif + void SV_WriteLine(Line *line, MapStateWriter *msw); void SV_ReadLine(Line *line, MapStateReader *msr); diff --git a/doomsday/plugins/common/include/p_tick.h b/doomsday/plugins/common/include/p_tick.h index 25fec671f9..111af4c662 100644 --- a/doomsday/plugins/common/include/p_tick.h +++ b/doomsday/plugins/common/include/p_tick.h @@ -1,29 +1,21 @@ -/**\file p_tick.h - *\section License - * License: GPL - * Online License Link: http://www.gnu.org/licenses/gpl.html +/** @file p_tick.h Common top-level tick stuff. * - *\author Copyright © 2006-2013 Jaakko Keränen - *\author Copyright © 2006-2013 Daniel Swanson + * @authors Copyright © 2006-2013 Jaakko Keränen + * @authors Copyright © 2006-2013 Daniel Swanson * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -/** - * Common top-level tick stuff. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA */ #ifndef LIBCOMMON_P_TICK_H @@ -32,16 +24,24 @@ #include "dd_types.h" #include "pause.h" +DENG_EXTERN_C int mapTime; +DENG_EXTERN_C int actualMapTime; +DENG_EXTERN_C int timerGame; + #ifdef __cplusplus extern "C" { #endif -extern int mapTime; -extern int actualMapTime; -extern int timerGame; +/** + * This is called at all times, no matter gamestate. + */ +void P_RunPlayers(timespan_t ticLength); -void P_RunPlayers(timespan_t ticLength); -void P_DoTick(void); +/** + * Called 35 times per second. + * The heart of play sim. + */ +void P_DoTick(void); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/plugins/common/include/thinkerinfo.h b/doomsday/plugins/common/include/thinkerinfo.h new file mode 100644 index 0000000000..ce4b8ee6be --- /dev/null +++ b/doomsday/plugins/common/include/thinkerinfo.h @@ -0,0 +1,97 @@ +/** @file thinkerinfo.h Game save thinker info. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBCOMMON_SAVESTATE_THINKERINFO_H +#define LIBCOMMON_SAVESTATE_THINKERINFO_H + +#include "common.h" + +/** + * Original indices must remain unchanged! + * Added new think classes to the end. + */ +typedef enum thinkclass_e { + TC_NULL = -1, + TC_END, + TC_MOBJ, + TC_XGMOVER, + TC_CEILING, + TC_DOOR, + TC_FLOOR, + TC_PLAT, +#if __JHEXEN__ + TC_INTERPRET_ACS, + TC_FLOOR_WAGGLE, + TC_LIGHT, + TC_PHASE, + TC_BUILD_PILLAR, + TC_ROTATE_POLY, + TC_MOVE_POLY, + TC_POLY_DOOR, +#else + TC_FLASH, + TC_STROBE, +# if __JDOOM__ || __JDOOM64__ + TC_GLOW, + TC_FLICKER, +# if __JDOOM64__ + TC_BLINK, +# endif +# else + TC_GLOW, +# endif +#endif + TC_MATERIALCHANGER, + TC_SCROLL, + NUMTHINKERCLASSES +} thinkerclass_t; + +#ifdef __cplusplus +class MapStateReader; +class MapStateWriter; + +// Thinker Save flags +#define TSF_SERVERONLY 0x01 ///< Only saved by servers. + +typedef void (*WriteThinkerFunc)(thinker_t *, MapStateWriter *writer); +typedef int (*ReadThinkerFunc)(thinker_t *, MapStateReader *reader); + +struct ThinkerClassInfo +{ + thinkerclass_t thinkclass; + thinkfunc_t function; + int flags; + WriteThinkerFunc writeFunc; + ReadThinkerFunc readFunc; + size_t size; +}; + +/** + * Returns the info for the specified thinker @a tClass; otherwise @c 0 if not found. + */ +ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass); + +/** + * Returns the info for the specified thinker; otherwise @c 0 if not found. + */ +ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker); +#endif + +#endif // LIBCOMMON_SAVESTATE_THINKERINFO_H diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index 0c8d8cb222..d818906a98 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -25,6 +25,7 @@ #include "p_actor.h" #include "p_saveg.h" #include "p_saveio.h" +#include "thinkerinfo.h" #include DENG2_PIMPL(MapStateReader) diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index f8a409d861..34dca4e59e 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -24,6 +24,7 @@ #include "dmu_lib.h" #include "p_saveg.h" #include "p_saveio.h" +#include "thinkerinfo.h" DENG2_PIMPL(MapStateWriter) { diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index bdc62a4668..563d239e5f 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -21,36 +21,20 @@ #include "common.h" #include "p_saveg.h" -#include "g_common.h" #include "d_net.h" #include "dmu_lib.h" -#include "fi_lib.h" +#if __JHERETIC__ || __JHEXEN__ +# include "hu_inventory.h" +#endif +#include "mobj.h" +#include "p_actor.h" #include "p_map.h" #include "p_mapsetup.h" -#include "p_player.h" -#include "mobj.h" #include "p_inventory.h" -#include "am_map.h" #include "p_tick.h" -#include "p_actor.h" -#include "p_ceiling.h" -#include "p_door.h" -#include "p_floor.h" -#include "p_plat.h" -#include "p_scroll.h" -#include "p_switch.h" -#include "hu_log.h" -#if __JHERETIC__ || __JHEXEN__ -#include "hu_inventory.h" -#endif #include "r_common.h" -#include "api_materialarchive.h" #include "p_savedef.h" -#include "dmu_archiveindex.h" #include "polyobjs.h" -#if __JHEXEN__ -# include "acscript.h" -#endif #include "mapstatereader.h" #include "mapstatewriter.h" #include @@ -104,14 +88,6 @@ typedef enum { static bool recogniseGameState(Str const *path, SaveInfo *info); -static void SV_WriteMobj(thinker_t *th, MapStateWriter *msWriter); -static int SV_ReadMobj(thinker_t *th, MapStateReader *msReader); - -#if __JHEXEN__ -static void SV_WriteMovePoly(polyevent_t const *movepoly, MapStateWriter *msWriter); -static int SV_ReadMovePoly(polyevent_t *movepoly, MapStateReader *msReader); -#endif - #if __JHEXEN__ static void readMapState(Reader *reader, int saveVersion, Str const *path); #else @@ -146,201 +122,6 @@ static targetplraddress_t *targetPlayerAddrs; static byte *saveBuffer; #endif -template -static void writeThinkerAs(thinker_t const *th, MapStateWriter *msWriter) -{ - Type *t = (Type*)th; - t->write(msWriter); -} - -template -static int readThinkerAs(thinker_t *th, MapStateReader *msReader) -{ - Type *t = (Type *)th; - return t->read(msReader); -} - -static ThinkerClassInfo thinkerInfo[] = { - { - TC_MOBJ, - (thinkfunc_t) P_MobjThinker, - TSF_SERVERONLY, - (WriteThinkerFunc) SV_WriteMobj, - (ReadThinkerFunc) SV_ReadMobj, - sizeof(mobj_t) - }, -#if !__JHEXEN__ - { - TC_XGMOVER, - (thinkfunc_t) XS_PlaneMover, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(xgplanemover_t) - }, -#endif - { - TC_CEILING, - T_MoveCeiling, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(ceiling_t) - }, - { - TC_DOOR, - T_Door, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(door_t) - }, - { - TC_FLOOR, - T_MoveFloor, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(floor_t) - }, - { - TC_PLAT, - T_PlatRaise, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(plat_t) - }, -#if __JHEXEN__ - { - TC_INTERPRET_ACS, - (thinkfunc_t) ACScript_Thinker, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(ACScript) - }, - { - TC_FLOOR_WAGGLE, - (thinkfunc_t) T_FloorWaggle, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(waggle_t) - }, - { - TC_LIGHT, - (thinkfunc_t) T_Light, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(light_t) - }, - { - TC_PHASE, - (thinkfunc_t) T_Phase, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(phase_t) - }, - { - TC_BUILD_PILLAR, - (thinkfunc_t) T_BuildPillar, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(pillar_t) - }, - { - TC_ROTATE_POLY, - T_RotatePoly, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(polyevent_t) - }, - { - TC_MOVE_POLY, - T_MovePoly, - 0, - de::function_cast(SV_WriteMovePoly), - de::function_cast(SV_ReadMovePoly), - sizeof(polyevent_t) - }, - { - TC_POLY_DOOR, - T_PolyDoor, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(polydoor_t) - }, -#else - { - TC_FLASH, - (thinkfunc_t) T_LightFlash, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(lightflash_s) - }, - { - TC_STROBE, - (thinkfunc_t) T_StrobeFlash, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(strobe_t) - }, - { - TC_GLOW, - (thinkfunc_t) T_Glow, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(glow_t) - }, -# if __JDOOM__ || __JDOOM64__ - { - TC_FLICKER, - (thinkfunc_t) T_FireFlicker, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(fireflicker_t) - }, -# endif -# if __JDOOM64__ - { - TC_BLINK, - (thinkfunc_t) T_LightBlink, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(lightblink_t) - }, -# endif -#endif - { - TC_MATERIALCHANGER, - T_MaterialChanger, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(materialchanger_s) - }, - { - TC_SCROLL, - (thinkfunc_t) T_Scroll, - 0, - de::function_cast(writeThinkerAs), - de::function_cast(readThinkerAs), - sizeof(scroll_t) - }, - { TC_NULL, NULL, 0, NULL, NULL, 0 } -}; - void SV_Register() { #if !__JHEXEN__ @@ -848,26 +629,6 @@ uint SV_GenerateGameId() return Timer_RealMilliseconds() + (mapTime << 24); } -ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass) -{ - for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) - { - if(info->thinkclass == tClass) - return info; - } - return 0; // Not found. -} - -ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker) -{ - for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) - { - if(info->function == thinker.function) - return info; - } - return 0; // Not found. -} - void SV_InitThingArchiveForLoad(uint size) { thingArchiveSize = size; @@ -1472,7 +1233,7 @@ static void SV_ReadPlayer(player_t *p, Reader *reader) # define MOBJ_SAVEVERSION 10 #endif -static void SV_WriteMobj(thinker_t *th, MapStateWriter *msw) +void SV_WriteMobj(thinker_t *th, MapStateWriter *msw) { Writer *writer = msw->writer(); @@ -1813,7 +1574,7 @@ static void RestoreMobj(mobj_t *mo, int ver) * Always returns @c false as a thinker will have already been allocated in * the mobj creation process. */ -static int SV_ReadMobj(thinker_t *th, MapStateReader *msr) +int SV_ReadMobj(thinker_t *th, MapStateReader *msr) { Reader *reader = msr->reader(); mobj_t *mo = (mobj_t *) th; @@ -2845,7 +2606,7 @@ int SV_ReadPolyObj(MapStateReader *msr) #endif #if __JHEXEN__ -static void SV_WriteMovePoly(polyevent_t const *th, MapStateWriter *msw) +void SV_WriteMovePoly(polyevent_t const *th, MapStateWriter *msw) { Writer *writer = msw->writer(); @@ -2862,7 +2623,7 @@ static void SV_WriteMovePoly(polyevent_t const *th, MapStateWriter *msw) Writer_WriteInt32(writer, FLT2FIX(th->speed[VY])); } -static int SV_ReadMovePoly(polyevent_t *th, MapStateReader *msr) +int SV_ReadMovePoly(polyevent_t *th, MapStateReader *msr) { Reader *reader = msr->reader(); int mapVersion = msr->mapVersion(); diff --git a/doomsday/plugins/common/src/p_tick.c b/doomsday/plugins/common/src/p_tick.c index c24ebddeb1..76ef18bc52 100644 --- a/doomsday/plugins/common/src/p_tick.c +++ b/doomsday/plugins/common/src/p_tick.c @@ -70,9 +70,6 @@ int timerGame; // CODE -------------------------------------------------------------------- -/** - * This is called at all times, no matter gamestate. - */ void P_RunPlayers(timespan_t ticLength) { uint i; @@ -85,10 +82,6 @@ void P_RunPlayers(timespan_t ticLength) } } -/** - * Called 35 times per second. - * The heart of play sim. - */ void P_DoTick(void) { int i; diff --git a/doomsday/plugins/common/src/thinkerinfo.cpp b/doomsday/plugins/common/src/thinkerinfo.cpp new file mode 100644 index 0000000000..e29025adce --- /dev/null +++ b/doomsday/plugins/common/src/thinkerinfo.cpp @@ -0,0 +1,251 @@ +/** @file thinkerinfo.cpp Game save thinker info. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "common.h" +#include "thinkerinfo.h" + +#include "p_saveg.h" +#include "p_ceiling.h" +#include "p_door.h" +#include "p_floor.h" +#include "p_plat.h" +#include "p_scroll.h" +#include "p_switch.h" +#if __JHEXEN__ +# include "acscript.h" +# include "p_pillar.h" +# include "p_waggle.h" +#endif +#include "polyobjs.h" + +template +static void writeThinkerAs(thinker_t const *th, MapStateWriter *msWriter) +{ + Type *t = (Type*)th; + t->write(msWriter); +} + +template +static int readThinkerAs(thinker_t *th, MapStateReader *msReader) +{ + Type *t = (Type *)th; + return t->read(msReader); +} + +static ThinkerClassInfo thinkerInfo[] = { + { + TC_MOBJ, + (thinkfunc_t) P_MobjThinker, + TSF_SERVERONLY, + (WriteThinkerFunc) SV_WriteMobj, + (ReadThinkerFunc) SV_ReadMobj, + sizeof(mobj_t) + }, +#if !__JHEXEN__ + { + TC_XGMOVER, + (thinkfunc_t) XS_PlaneMover, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(xgplanemover_t) + }, +#endif + { + TC_CEILING, + T_MoveCeiling, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(ceiling_t) + }, + { + TC_DOOR, + T_Door, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(door_t) + }, + { + TC_FLOOR, + T_MoveFloor, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(floor_t) + }, + { + TC_PLAT, + T_PlatRaise, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(plat_t) + }, +#if __JHEXEN__ + { + TC_INTERPRET_ACS, + (thinkfunc_t) ACScript_Thinker, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(ACScript) + }, + { + TC_FLOOR_WAGGLE, + (thinkfunc_t) T_FloorWaggle, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(waggle_t) + }, + { + TC_LIGHT, + (thinkfunc_t) T_Light, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(light_t) + }, + { + TC_PHASE, + (thinkfunc_t) T_Phase, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(phase_t) + }, + { + TC_BUILD_PILLAR, + (thinkfunc_t) T_BuildPillar, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(pillar_t) + }, + { + TC_ROTATE_POLY, + T_RotatePoly, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(polyevent_t) + }, + { + TC_MOVE_POLY, + T_MovePoly, + 0, + de::function_cast(SV_WriteMovePoly), + de::function_cast(SV_ReadMovePoly), + sizeof(polyevent_t) + }, + { + TC_POLY_DOOR, + T_PolyDoor, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(polydoor_t) + }, +#else + { + TC_FLASH, + (thinkfunc_t) T_LightFlash, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(lightflash_s) + }, + { + TC_STROBE, + (thinkfunc_t) T_StrobeFlash, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(strobe_t) + }, + { + TC_GLOW, + (thinkfunc_t) T_Glow, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(glow_t) + }, +# if __JDOOM__ || __JDOOM64__ + { + TC_FLICKER, + (thinkfunc_t) T_FireFlicker, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(fireflicker_t) + }, +# endif +# if __JDOOM64__ + { + TC_BLINK, + (thinkfunc_t) T_LightBlink, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(lightblink_t) + }, +# endif +#endif + { + TC_MATERIALCHANGER, + T_MaterialChanger, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(materialchanger_s) + }, + { + TC_SCROLL, + (thinkfunc_t) T_Scroll, + 0, + de::function_cast(writeThinkerAs), + de::function_cast(readThinkerAs), + sizeof(scroll_t) + }, + { TC_NULL, NULL, 0, NULL, NULL, 0 } +}; + +ThinkerClassInfo *SV_ThinkerInfoForClass(thinkerclass_t tClass) +{ + for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) + { + if(info->thinkclass == tClass) + return info; + } + return 0; // Not found. +} + +ThinkerClassInfo *SV_ThinkerInfo(thinker_t const &thinker) +{ + for(ThinkerClassInfo *info = thinkerInfo; info->thinkclass != TC_NULL; info++) + { + if(info->function == thinker.function) + return info; + } + return 0; // Not found. +} From 2f4e8dd0d0037ffae2fa8dd08651388048928bc1 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 09:48:29 +0000 Subject: [PATCH 12/15] libcommon: Cleanup --- doomsday/plugins/common/include/thinkerinfo.h | 11 +- doomsday/plugins/common/src/p_saveg.cpp | 305 +++++++++--------- 2 files changed, 156 insertions(+), 160 deletions(-) diff --git a/doomsday/plugins/common/include/thinkerinfo.h b/doomsday/plugins/common/include/thinkerinfo.h index ce4b8ee6be..a71a2bc508 100644 --- a/doomsday/plugins/common/include/thinkerinfo.h +++ b/doomsday/plugins/common/include/thinkerinfo.h @@ -22,6 +22,10 @@ #define LIBCOMMON_SAVESTATE_THINKERINFO_H #include "common.h" +#ifdef __cplusplus +# include "mapstatereader.h" +# include "mapstatewriter.h" +#endif /** * Original indices must remain unchanged! @@ -64,14 +68,11 @@ typedef enum thinkclass_e { } thinkerclass_t; #ifdef __cplusplus -class MapStateReader; -class MapStateWriter; - // Thinker Save flags #define TSF_SERVERONLY 0x01 ///< Only saved by servers. -typedef void (*WriteThinkerFunc)(thinker_t *, MapStateWriter *writer); -typedef int (*ReadThinkerFunc)(thinker_t *, MapStateReader *reader); +typedef void (*WriteThinkerFunc)(thinker_t *, MapStateWriter *msw); +typedef int (*ReadThinkerFunc)(thinker_t *, MapStateReader *msr); struct ThinkerClassInfo { diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 563d239e5f..61160c4985 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -54,7 +54,8 @@ using namespace dmu_lib; static ThingSerialId const TargetPlayerId = -2; #endif -typedef struct playerheader_s { +struct playerheader_t +{ int numPowers; int numKeys; int numFrags; @@ -67,32 +68,26 @@ typedef struct playerheader_s { #if __JHEXEN__ int numArmorTypes; #endif -} playerheader_t; +}; -typedef enum { +enum sectorclass_t +{ sc_normal, sc_ploff, ///< plane offset #if !__JHEXEN__ sc_xg1, #endif NUM_SECTORCLASSES -} sectorclass_t; +}; -typedef enum { +enum lineclass_t +{ lc_normal, #if !__JHEXEN__ lc_xg1, #endif NUM_LINECLASSES -} lineclass_t; - -static bool recogniseGameState(Str const *path, SaveInfo *info); - -#if __JHEXEN__ -static void readMapState(Reader *reader, int saveVersion, Str const *path); -#else -static void readMapState(Reader *reader, int saveVersion); -#endif +}; static bool inited = false; @@ -122,21 +117,6 @@ static targetplraddress_t *targetPlayerAddrs; static byte *saveBuffer; #endif -void SV_Register() -{ -#if !__JHEXEN__ - C_VAR_BYTE("game-save-auto-loadonreborn", &cfg.loadAutoSaveOnReborn, 0, 0, 1); -#endif - C_VAR_BYTE("game-save-confirm", &cfg.confirmQuickGameSave, 0, 0, 1); - C_VAR_BYTE("game-save-confirm-loadonreborn", &cfg.confirmRebornLoad, 0, 0, 1); - C_VAR_BYTE("game-save-last-loadonreborn", &cfg.loadLastSaveOnReborn, 0, 0, 1); - C_VAR_INT ("game-save-last-slot", &cvarLastSlot, CVF_NO_MIN|CVF_NO_MAX|CVF_NO_ARCHIVE|CVF_READ_ONLY, 0, 0); - C_VAR_INT ("game-save-quick-slot", &cvarQuickSlot, CVF_NO_MAX|CVF_NO_ARCHIVE, -1, 0); - - // Aliases for obsolete cvars: - C_VAR_BYTE("menu-quick-ask", &cfg.confirmQuickGameSave, 0, 0, 1); -} - /** * Compose the (possibly relative) path to the game-save associated * with the logical save @a slot. @@ -218,6 +198,101 @@ static void clearSaveInfo() } } +static void SV_SaveInfo_Read(SaveInfo *info, Reader *reader) +{ +#if __JHEXEN__ + // Read the magic byte to determine the high-level format. + int magic = Reader_ReadInt32(reader); + SV_HxSavePtr()->b -= 4; // Rewind the stream. + + if((!IS_NETWORK_CLIENT && magic != MY_SAVE_MAGIC) || + ( IS_NETWORK_CLIENT && magic != MY_CLIENT_SAVE_MAGIC)) + { + // Perhaps the old v9 format? + info->read_Hx_v9(reader); + } + else +#endif + { + info->read(reader); + } +} + +static bool recogniseNativeState(Str const *path, SaveInfo *info) +{ + DENG_ASSERT(path != 0 && info != 0); + + if(!SV_ExistingFile(path)) return false; + +#if __JHEXEN__ + /// @todo Do not buffer the whole file. + byte *saveBuffer; + size_t fileSize = M_ReadFile(Str_Text(path), (char **) &saveBuffer); + if(!fileSize) return false; + // Set the save pointer. + SV_HxSavePtr()->b = saveBuffer; + SV_HxSetSaveEndPtr(saveBuffer + fileSize); +#else + if(!SV_OpenFile(path, "rp")) + return false; +#endif + + Reader *reader = SV_NewReader(); + SV_SaveInfo_Read(info, reader); + Reader_Delete(reader); + +#if __JHEXEN__ + Z_Free(saveBuffer); +#else + SV_CloseFile(); +#endif + + // Magic must match. + if(info->magic() != MY_SAVE_MAGIC && info->magic() != MY_CLIENT_SAVE_MAGIC) + { + return false; + } + + /* + * Check for unsupported versions. + */ + if(info->version() > MY_SAVE_VERSION) // Future version? + { + return false; + } + +#if __JHEXEN__ + // We are incompatible with v3 saves due to an invalid test used to determine + // present sides (ver3 format's sides contain chunks of junk data). + if(info->version() == 3) + { + return false; + } +#endif + + return true; +} + +static bool recogniseGameState(Str const *path, SaveInfo *info) +{ + if(path && info) + { + if(recogniseNativeState(path, info)) + return true; + + // Perhaps an original game state? +#if __JDOOM__ + if(SV_RecogniseState_Dm_v19(path, info)) + return true; +#endif +#if __JHERETIC__ + if(SV_RecogniseState_Hr_v13(path, info)) + return true; +#endif + } + return false; +} + static void updateSaveInfo(Str const *path, SaveInfo *info) { if(!info) return; @@ -397,101 +472,6 @@ dd_bool SV_IsUserWritableSlot(int slot) return SV_IsValidSlot(slot); } -static void SV_SaveInfo_Read(SaveInfo *info, Reader *reader) -{ -#if __JHEXEN__ - // Read the magic byte to determine the high-level format. - int magic = Reader_ReadInt32(reader); - SV_HxSavePtr()->b -= 4; // Rewind the stream. - - if((!IS_NETWORK_CLIENT && magic != MY_SAVE_MAGIC) || - ( IS_NETWORK_CLIENT && magic != MY_CLIENT_SAVE_MAGIC)) - { - // Perhaps the old v9 format? - info->read_Hx_v9(reader); - } - else -#endif - { - info->read(reader); - } -} - -static bool recogniseNativeState(Str const *path, SaveInfo *info) -{ - DENG_ASSERT(path != 0 && info != 0); - - if(!SV_ExistingFile(path)) return false; - -#if __JHEXEN__ - /// @todo Do not buffer the whole file. - byte *saveBuffer; - size_t fileSize = M_ReadFile(Str_Text(path), (char **) &saveBuffer); - if(!fileSize) return false; - // Set the save pointer. - SV_HxSavePtr()->b = saveBuffer; - SV_HxSetSaveEndPtr(saveBuffer + fileSize); -#else - if(!SV_OpenFile(path, "rp")) - return false; -#endif - - Reader *reader = SV_NewReader(); - SV_SaveInfo_Read(info, reader); - Reader_Delete(reader); - -#if __JHEXEN__ - Z_Free(saveBuffer); -#else - SV_CloseFile(); -#endif - - // Magic must match. - if(info->magic() != MY_SAVE_MAGIC && info->magic() != MY_CLIENT_SAVE_MAGIC) - { - return false; - } - - /* - * Check for unsupported versions. - */ - if(info->version() > MY_SAVE_VERSION) // Future version? - { - return false; - } - -#if __JHEXEN__ - // We are incompatible with v3 saves due to an invalid test used to determine - // present sides (ver3 format's sides contain chunks of junk data). - if(info->version() == 3) - { - return false; - } -#endif - - return true; -} - -static bool recogniseGameState(Str const *path, SaveInfo *info) -{ - if(path && info) - { - if(recogniseNativeState(path, info)) - return true; - - // Perhaps an original game state? -#if __JDOOM__ - if(SV_RecogniseState_Dm_v19(path, info)) - return true; -#endif -#if __JHERETIC__ - if(SV_RecogniseState_Hr_v13(path, info)) - return true; -#endif - } - return false; -} - SaveInfo *SV_SaveInfoForSlot(int slot) { DENG_ASSERT(inited); @@ -2722,6 +2702,37 @@ static bool openGameSaveFile(Str const *fileName, bool write) return SV_File() != 0; } +#if __JHEXEN__ +static void readMapState(Reader *reader, int saveVersion, Str const *path) +#else +static void readMapState(Reader *reader, int saveVersion) +#endif +{ +#if __JHEXEN__ + DENG_ASSERT(path != 0); + + App_Log(DE2_DEV_MAP_MSG, "readMapState: Opening file \"%s\"\n", Str_Text(path)); + + // Load the file + size_t bufferSize = M_ReadFile(Str_Text(path), (char **)&saveBuffer); + if(!bufferSize) + { + App_Log(DE2_RES_ERROR, "readMapState: Failed opening \"%s\" for reading", Str_Text(path)); + return; + } + + SV_HxSavePtr()->b = saveBuffer; + SV_HxSetSaveEndPtr(saveBuffer + bufferSize); +#endif + + MapStateReader(saveVersion).read(reader); + +#if __JHEXEN__ + clearThingArchive(); + Z_Free(saveBuffer); +#endif +} + static int SV_LoadState(Str const *path, SaveInfo *info) { DENG_ASSERT(path != 0 && info != 0); @@ -3089,37 +3100,6 @@ void SV_LoadGameClient(uint gameId) #endif } -#if __JHEXEN__ -static void readMapState(Reader *reader, int saveVersion, Str const *path) -#else -static void readMapState(Reader *reader, int saveVersion) -#endif -{ -#if __JHEXEN__ - DENG_ASSERT(path != 0); - - App_Log(DE2_DEV_MAP_MSG, "readMapState: Opening file \"%s\"\n", Str_Text(path)); - - // Load the file - size_t bufferSize = M_ReadFile(Str_Text(path), (char **)&saveBuffer); - if(!bufferSize) - { - App_Log(DE2_RES_ERROR, "readMapState: Failed opening \"%s\" for reading", Str_Text(path)); - return; - } - - SV_HxSavePtr()->b = saveBuffer; - SV_HxSetSaveEndPtr(saveBuffer + bufferSize); -#endif - - MapStateReader(saveVersion).read(reader); - -#if __JHEXEN__ - clearThingArchive(); - Z_Free(saveBuffer); -#endif -} - static int saveStateWorker(Str const *path, SaveInfo *saveInfo) { App_Log(DE2_LOG_VERBOSE, "saveStateWorker: Attempting save game to \"%s\"", Str_Text(path)); @@ -3462,3 +3442,18 @@ void SV_HxRestorePlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS], P_TelefragMobjsTouchingPlayers(); } #endif + +void SV_Register() +{ +#if !__JHEXEN__ + C_VAR_BYTE("game-save-auto-loadonreborn", &cfg.loadAutoSaveOnReborn, 0, 0, 1); +#endif + C_VAR_BYTE("game-save-confirm", &cfg.confirmQuickGameSave, 0, 0, 1); + C_VAR_BYTE("game-save-confirm-loadonreborn", &cfg.confirmRebornLoad, 0, 0, 1); + C_VAR_BYTE("game-save-last-loadonreborn", &cfg.loadLastSaveOnReborn, 0, 0, 1); + C_VAR_INT ("game-save-last-slot", &cvarLastSlot, CVF_NO_MIN|CVF_NO_MAX|CVF_NO_ARCHIVE|CVF_READ_ONLY, 0, 0); + C_VAR_INT ("game-save-quick-slot", &cvarQuickSlot, CVF_NO_MAX|CVF_NO_ARCHIVE, -1, 0); + + // Aliases for obsolete cvars: + C_VAR_BYTE("menu-quick-ask", &cfg.confirmQuickGameSave, 0, 0, 1); +} From 0aa892f52cf12d7410b59256e636a1c4057824b2 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 11:34:36 +0000 Subject: [PATCH 13/15] Refactor|libdoom: Moved "Boss brain" to new source files --- doomsday/plugins/doom/doom.pro | 2 + doomsday/plugins/doom/include/bossbrain.h | 62 +++++++++++ doomsday/plugins/doom/include/jdoom.h | 1 + doomsday/plugins/doom/include/p_enemy.h | 19 ---- doomsday/plugins/doom/src/bossbrain.cpp | 123 ++++++++++++++++++++++ doomsday/plugins/doom/src/p_enemy.c | 113 ++------------------ 6 files changed, 194 insertions(+), 126 deletions(-) create mode 100644 doomsday/plugins/doom/include/bossbrain.h create mode 100644 doomsday/plugins/doom/src/bossbrain.cpp diff --git a/doomsday/plugins/doom/doom.pro b/doomsday/plugins/doom/doom.pro index 64ab353d97..91562e5e49 100644 --- a/doomsday/plugins/doom/doom.pro +++ b/doomsday/plugins/doom/doom.pro @@ -31,6 +31,7 @@ INCLUDEPATH += include HEADERS += \ include/acfnlink.h \ + include/bossbrain.h \ include/d_api.h \ include/d_config.h \ include/d_console.h \ @@ -70,6 +71,7 @@ HEADERS += \ SOURCES += \ src/acfnlink.c \ + src/bossbrain.cpp \ src/d_api.c \ src/d_console.c \ src/d_items.c \ diff --git a/doomsday/plugins/doom/include/bossbrain.h b/doomsday/plugins/doom/include/bossbrain.h new file mode 100644 index 0000000000..782a4a98f8 --- /dev/null +++ b/doomsday/plugins/doom/include/bossbrain.h @@ -0,0 +1,62 @@ +/** @file bossbrain.h Playsim "Boss Brain" management. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * @authors Copyright © 1999 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman (PrBoom 2.2.6) + * @authors Copyright © 1999-2000 Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze (PrBoom 2.2.6) + * @authors Copyright © 1993-1996 id Software, Inc. + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LIBDOOM_PLAY_BOSSBRAIN_H +#define LIBDOOM_PLAY_BOSSBRAIN_H + +#ifndef __JDOOM__ +# error "Using jDoom headers without __JDOOM__" +#endif + +#include "doomsday.h" +#include "p_mobj.h" + +/** + * Global state of boss brain. + */ +typedef struct bossbrain_s { + int easy; + int targetOn; + int numTargets; + int maxTargets; + mobj_t **targets; +} bossbrain_t; + +DENG_EXTERN_C bossbrain_t bossBrain; + +#ifdef __cplusplus +extern "C" { +#endif + +void P_BrainInitForMap(void); +void P_BrainShutdown(void); +void P_BrainClearTargets(void); +void P_BrainWrite(Writer *writer); +void P_BrainRead(Reader *reader, int mapVersion); +void P_BrainAddTarget(mobj_t *mo); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LIBDOOM_PLAY_BOSSBRAIN_H diff --git a/doomsday/plugins/doom/include/jdoom.h b/doomsday/plugins/doom/include/jdoom.h index b4cf015717..fe19f70fd1 100644 --- a/doomsday/plugins/doom/include/jdoom.h +++ b/doomsday/plugins/doom/include/jdoom.h @@ -32,6 +32,7 @@ #define __JDOOM_CONVENIENCE_H__ #include "../../doom/include/acfnlink.h" +#include "../../doom/include/bossbrain.h" #include "../../doom/include/d_api.h" #include "../../doom/include/d_config.h" #include "../../doom/include/d_console.h" diff --git a/doomsday/plugins/doom/include/p_enemy.h b/doomsday/plugins/doom/include/p_enemy.h index 14b6afc2ff..75507ceebb 100644 --- a/doomsday/plugins/doom/include/p_enemy.h +++ b/doomsday/plugins/doom/include/p_enemy.h @@ -26,29 +26,10 @@ #include "jdoom.h" -/** - * Global state of boss brain. - */ -typedef struct braindata_s { - int easy; - int targetOn; - int numTargets; - int maxTargets; - mobj_t **targets; -} braindata_t; - -DENG_EXTERN_C braindata_t brain; - #ifdef __cplusplus extern "C" { #endif -void P_BrainInitForMap(void); -void P_BrainShutdown(void); -void P_BrainClearTargets(void); -void P_BrainWrite(Writer *writer); -void P_BrainRead(Reader *reader, int mapVersion); -void P_BrainAddTarget(mobj_t *mo); void P_NoiseAlert(mobj_t *target, mobj_t *emmiter); int P_Massacre(void); diff --git a/doomsday/plugins/doom/src/bossbrain.cpp b/doomsday/plugins/doom/src/bossbrain.cpp new file mode 100644 index 0000000000..72411c86fe --- /dev/null +++ b/doomsday/plugins/doom/src/bossbrain.cpp @@ -0,0 +1,123 @@ +/** @file bossbrain.cpp Playsim "Boss Brain" management. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2005-2013 Daniel Swanson + * @authors Copyright © 1999 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman (PrBoom 2.2.6) + * @authors Copyright © 1999-2000 Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze (PrBoom 2.2.6) + * @authors Copyright © 1993-1996 id Software, Inc. + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "jdoom.h" +#include "bossbrain.h" + +#include "p_saveg.h" + +void P_BrainInitForMap() +{ + bossBrain.easy = 0; // Always init easy to 0. + // Calling shutdown rather than clear allows us to free up memory. + P_BrainShutdown(); +} + +void P_BrainClearTargets() +{ + bossBrain.numTargets = 0; + bossBrain.targetOn = 0; +} + +void P_BrainWrite(Writer *writer) +{ + DENG_ASSERT(writer != 0); + + // Not for us? + if(!IS_SERVER) return; + + Writer_WriteByte(writer, 1); // Write a version byte. + + Writer_WriteInt16(writer, bossBrain.numTargets); + Writer_WriteInt16(writer, bossBrain.targetOn); + Writer_WriteByte(writer, bossBrain.easy!=0? 1:0); + + // Write the mobj references using the mobj archive. + for(int i = 0; i < bossBrain.numTargets; ++i) + { + Writer_WriteInt16(writer, SV_ThingArchiveId(bossBrain.targets[i])); + } +} + +void P_BrainRead(Reader *reader, int mapVersion) +{ + DENG_ASSERT(reader != 0); + + // Not for us? + if(!IS_SERVER) return; + + // No brain data before version 3. + if(mapVersion < 3) return; + + P_BrainClearTargets(); + + int ver = (mapVersion >= 8? Reader_ReadByte(reader) : 0); + int numTargets; + if(ver >= 1) + { + numTargets = Reader_ReadInt16(reader); + bossBrain.targetOn = Reader_ReadInt16(reader); + bossBrain.easy = (dd_bool)Reader_ReadByte(reader); + } + else + { + numTargets = Reader_ReadByte(reader); + bossBrain.targetOn = Reader_ReadByte(reader); + bossBrain.easy = false; + } + + for(int i = 0; i < numTargets; ++i) + { + P_BrainAddTarget(SV_GetArchiveThing((int) Reader_ReadInt16(reader), 0)); + } +} + +void P_BrainShutdown() +{ + Z_Free(bossBrain.targets); bossBrain.targets = 0; + bossBrain.numTargets = 0; + bossBrain.maxTargets = -1; + bossBrain.targetOn = 0; +} + +void P_BrainAddTarget(mobj_t *mo) +{ + DENG_ASSERT(mo != 0); + + if(bossBrain.numTargets >= bossBrain.maxTargets) + { + // Do we need to alloc more targets? + if(bossBrain.numTargets == bossBrain.maxTargets) + { + bossBrain.maxTargets *= 2; + bossBrain.targets = (mobj_t **)Z_Realloc(bossBrain.targets, bossBrain.maxTargets * sizeof(*bossBrain.targets), PU_APPSTATIC); + } + else + { + bossBrain.maxTargets = 32; + bossBrain.targets = (mobj_t **)Z_Malloc(bossBrain.maxTargets * sizeof(*bossBrain.targets), PU_APPSTATIC, NULL); + } + } + + bossBrain.targets[bossBrain.numTargets++] = mo; +} diff --git a/doomsday/plugins/doom/src/p_enemy.c b/doomsday/plugins/doom/src/p_enemy.c index 4c611f637f..5bd0e8b019 100644 --- a/doomsday/plugins/doom/src/p_enemy.c +++ b/doomsday/plugins/doom/src/p_enemy.c @@ -42,7 +42,7 @@ #define SKULLSPEED (20) #define TRACEANGLE (0xc000000) -braindata_t brain; // Global state of boss brain. +bossbrain_t bossBrain; // Global state of boss brain. // Eight directional movement speeds. #define MOVESPEED_DIAGONAL (0.71716309) @@ -1730,107 +1730,6 @@ void C_DECL A_BabyMetal(mobj_t *mo) A_Chase(mo); } -void P_BrainInitForMap(void) -{ - brain.easy = 0; // Always init easy to 0. - // Calling shutdown rather than clear allows us to free up memory. - P_BrainShutdown(); -} - -void P_BrainClearTargets(void) -{ - brain.numTargets = 0; - brain.targetOn = 0; -} - -void P_BrainWrite(Writer *writer) -{ - int i; - - DENG_ASSERT(writer != 0); - - // Not for us? - if(!IS_SERVER) return; - - Writer_WriteByte(writer, 1); // Write a version byte. - - Writer_WriteInt16(writer, brain.numTargets); - Writer_WriteInt16(writer, brain.targetOn); - Writer_WriteByte(writer, brain.easy!=0? 1:0); - - // Write the mobj references using the mobj archive. - for(i = 0; i < brain.numTargets; ++i) - { - Writer_WriteInt16(writer, SV_ThingArchiveId(brain.targets[i])); - } -} - -void P_BrainRead(Reader *reader, int mapVersion) -{ - int ver, numTargets; - int i; - - DENG_ASSERT(reader != 0); - - // Not for us? - if(!IS_SERVER) return; - - // No brain data before version 3. - if(mapVersion < 3) return; - - P_BrainClearTargets(); - - ver = (mapVersion >= 8? Reader_ReadByte(reader) : 0); - numTargets; - if(ver >= 1) - { - numTargets = Reader_ReadInt16(reader); - brain.targetOn = Reader_ReadInt16(reader); - brain.easy = (dd_bool)Reader_ReadByte(reader); - } - else - { - numTargets = Reader_ReadByte(reader); - brain.targetOn = Reader_ReadByte(reader); - brain.easy = false; - } - - for(i = 0; i < numTargets; ++i) - { - P_BrainAddTarget(SV_GetArchiveThing((int) Reader_ReadInt16(reader), 0)); - } -} - -void P_BrainShutdown(void) -{ - if(brain.targets) - Z_Free(brain.targets); - brain.targets = 0; - brain.numTargets = 0; - brain.maxTargets = -1; - brain.targetOn = 0; -} - -void P_BrainAddTarget(mobj_t* mo) -{ - if(brain.numTargets >= brain.maxTargets) - { - // Do we need to alloc more targets? - if(brain.numTargets == brain.maxTargets) - { - brain.maxTargets *= 2; - brain.targets = Z_Realloc(brain.targets, brain.maxTargets * sizeof(*brain.targets), PU_APPSTATIC); - } - else - { - brain.maxTargets = 32; - brain.targets = Z_Malloc(brain.maxTargets * sizeof(*brain.targets), PU_APPSTATIC, NULL); - } - } - - brain.targets[brain.numTargets++] = mo; -} - void C_DECL A_BrainAwake(mobj_t *mo) { S_StartSound(SFX_BOSSIT, NULL); @@ -1900,16 +1799,16 @@ void C_DECL A_BrainSpit(mobj_t* mo) mobj_t* targ; mobj_t* newmobj; - if(!brain.numTargets) + if(!bossBrain.numTargets) return; // Ignore if no targets. - brain.easy ^= 1; - if(gameRules.skill <= SM_EASY && (!brain.easy)) + bossBrain.easy ^= 1; + if(gameRules.skill <= SM_EASY && (!bossBrain.easy)) return; // Shoot a cube at current target. - targ = brain.targets[brain.targetOn++]; - brain.targetOn %= brain.numTargets; + targ = bossBrain.targets[bossBrain.targetOn++]; + bossBrain.targetOn %= bossBrain.numTargets; // Spawn brain missile. newmobj = P_SpawnMissile(MT_SPAWNSHOT, mo, targ); From ae0231c88ba90616e33e3cc56fba93b58ff6c9b8 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 9 Feb 2014 12:30:58 +0000 Subject: [PATCH 14/15] Refactor|libdoom: Translated braindata_t into a simple C++ class named BossBrain --- .../plugins/common/src/mapstatereader.cpp | 3 +- .../plugins/common/src/mapstatewriter.cpp | 3 +- doomsday/plugins/common/src/p_mapsetup.cpp | 3 +- doomsday/plugins/common/src/p_start.cpp | 2 +- doomsday/plugins/common/src/p_switch.cpp | 1 + doomsday/plugins/doom/include/bossbrain.h | 55 +++++-- doomsday/plugins/doom/include/g_game.h | 80 +++++----- doomsday/plugins/doom/include/jdoom.h | 2 +- doomsday/plugins/doom/src/bossbrain.cpp | 145 +++++++++++++----- doomsday/plugins/doom/src/p_enemy.c | 19 +-- doomsday/plugins/doom/src/p_mobj.c | 4 +- doomsday/plugins/doom64/include/g_game.h | 82 +++++----- doomsday/plugins/heretic/include/g_game.h | 78 +++++----- doomsday/plugins/hexen/include/g_game.h | 86 +++++------ 14 files changed, 321 insertions(+), 242 deletions(-) diff --git a/doomsday/plugins/common/src/mapstatereader.cpp b/doomsday/plugins/common/src/mapstatereader.cpp index d818906a98..9c167bdcab 100644 --- a/doomsday/plugins/common/src/mapstatereader.cpp +++ b/doomsday/plugins/common/src/mapstatereader.cpp @@ -483,7 +483,8 @@ DENG2_PIMPL(MapStateReader) void readBrain() { #if __JDOOM__ - P_BrainRead(reader, mapVersion); + DENG_ASSERT(bossBrain != 0); + bossBrain->read(thisPublic); #endif } diff --git a/doomsday/plugins/common/src/mapstatewriter.cpp b/doomsday/plugins/common/src/mapstatewriter.cpp index 34dca4e59e..1616c1df38 100644 --- a/doomsday/plugins/common/src/mapstatewriter.cpp +++ b/doomsday/plugins/common/src/mapstatewriter.cpp @@ -186,7 +186,8 @@ DENG2_PIMPL(MapStateWriter) void writeBrain() { #if __JDOOM__ - P_BrainWrite(writer); + DENG_ASSERT(bossBrain != 0); + bossBrain->write(thisPublic); #endif } diff --git a/doomsday/plugins/common/src/p_mapsetup.cpp b/doomsday/plugins/common/src/p_mapsetup.cpp index 989f08b074..17d7469c25 100644 --- a/doomsday/plugins/common/src/p_mapsetup.cpp +++ b/doomsday/plugins/common/src/p_mapsetup.cpp @@ -972,7 +972,8 @@ static void P_ResetWorldState() #endif #if __JDOOM__ - P_BrainInitForMap(); + delete bossBrain; + bossBrain = new BossBrain; #endif #if __JHEXEN__ diff --git a/doomsday/plugins/common/src/p_start.cpp b/doomsday/plugins/common/src/p_start.cpp index 9af8bc8762..1b2decfe5f 100644 --- a/doomsday/plugins/common/src/p_start.cpp +++ b/doomsday/plugins/common/src/p_start.cpp @@ -247,7 +247,7 @@ void P_Shutdown() P_ShutdownTerrainTypes(); P_FreeWeaponSlots(); #if __JDOOM__ - P_BrainShutdown(); + delete bossBrain; bossBrain = 0; #endif } diff --git a/doomsday/plugins/common/src/p_switch.cpp b/doomsday/plugins/common/src/p_switch.cpp index 7fccf0bdb6..79a75b3e7f 100644 --- a/doomsday/plugins/common/src/p_switch.cpp +++ b/doomsday/plugins/common/src/p_switch.cpp @@ -26,6 +26,7 @@ #include "d_net.h" #include "dmu_lib.h" +#include "dmu_archiveindex.h" #include "p_plat.h" #include "p_sound.h" #include "p_saveg.h" diff --git a/doomsday/plugins/doom/include/bossbrain.h b/doomsday/plugins/doom/include/bossbrain.h index 782a4a98f8..3eff443678 100644 --- a/doomsday/plugins/doom/include/bossbrain.h +++ b/doomsday/plugins/doom/include/bossbrain.h @@ -28,35 +28,58 @@ # error "Using jDoom headers without __JDOOM__" #endif -#include "doomsday.h" -#include "p_mobj.h" +#include "jdoom.h" +#ifdef __cplusplus +#include "mapstatereader.h" +#include "mapstatewriter.h" /** * Global state of boss brain. + * + * @ingroup libdoom */ -typedef struct bossbrain_s { - int easy; - int targetOn; - int numTargets; - int maxTargets; - mobj_t **targets; -} bossbrain_t; +class BossBrain +{ +public: + BossBrain(); + + void clearTargets(); + + int targetCount() const; + + void addTarget(struct mobj_s *mo); + + struct mobj_s *nextTarget(); -DENG_EXTERN_C bossbrain_t bossBrain; + void write(MapStateWriter *msw) const; + void read(MapStateReader *msr); + +private: + DENG2_PRIVATE(d) +}; +#endif // __cplusplus + +// C wrapper API --------------------------------------------------------------- #ifdef __cplusplus extern "C" { +#else +typedef void *BossBrain; #endif -void P_BrainInitForMap(void); -void P_BrainShutdown(void); -void P_BrainClearTargets(void); -void P_BrainWrite(Writer *writer); -void P_BrainRead(Reader *reader, int mapVersion); -void P_BrainAddTarget(mobj_t *mo); +void BossBrain_ClearTargets(BossBrain *brain); + +int BossBrain_TargetCount(BossBrain const *brain); + +void BossBrain_AddTarget(BossBrain *brain, struct mobj_s *mo); + +struct mobj_s *BossBrain_NextTarget(BossBrain *brain); #ifdef __cplusplus } // extern "C" #endif +/// The One BossBrain instance. +DENG_EXTERN_C BossBrain *bossBrain; + #endif // LIBDOOM_PLAY_BOSSBRAIN_H diff --git a/doomsday/plugins/doom/include/g_game.h b/doomsday/plugins/doom/include/g_game.h index acb8c5598f..a54e4c1bfb 100644 --- a/doomsday/plugins/doom/include/g_game.h +++ b/doomsday/plugins/doom/include/g_game.h @@ -39,46 +39,46 @@ #include "d_player.h" #include "gamerules.h" +DENG_EXTERN_C int gaSaveGameSlot; +DENG_EXTERN_C int gaLoadGameSlot; + +DENG_EXTERN_C player_t players[MAXPLAYERS]; + +DENG_EXTERN_C dd_bool gameInProgress; +DENG_EXTERN_C uint gameEpisode; +DENG_EXTERN_C uint gameMap; +DENG_EXTERN_C Uri *gameMapUri; +DENG_EXTERN_C uint gameMapEntrance; +DENG_EXTERN_C GameRuleset gameRules; + +DENG_EXTERN_C uint nextMap; // If non zero this will be the next map. +DENG_EXTERN_C dd_bool secretExit; +DENG_EXTERN_C int totalKills, totalItems, totalSecret; +DENG_EXTERN_C dd_bool paused; +DENG_EXTERN_C dd_bool precache; +DENG_EXTERN_C dd_bool customPal; +DENG_EXTERN_C wbstartstruct_t wmInfo; +DENG_EXTERN_C int bodyQueueSlot; +DENG_EXTERN_C dd_bool briefDisabled; + +DENG_EXTERN_C int gsvMapMusic; + #ifdef __cplusplus extern "C" { #endif -extern int gaSaveGameSlot; -extern int gaLoadGameSlot; - -extern player_t players[MAXPLAYERS]; - -extern dd_bool gameInProgress; -extern uint gameEpisode; -extern uint gameMap; -extern Uri *gameMapUri; -extern uint gameMapEntrance; -extern GameRuleset gameRules; - -extern uint nextMap; // If non zero this will be the next map. -extern dd_bool secretExit; -extern int totalKills, totalItems, totalSecret; -extern dd_bool paused; -extern dd_bool precache; -extern dd_bool customPal; -extern wbstartstruct_t wmInfo; -extern int bodyQueueSlot; -extern dd_bool briefDisabled; - -extern int gsvMapMusic; - -void G_Register(void); -void G_CommonPreInit(void); -void G_CommonPostInit(void); -void G_CommonShutdown(void); +void G_Register(void); +void G_CommonPreInit(void); +void G_CommonPostInit(void); +void G_CommonShutdown(void); -void R_InitRefresh(void); +void R_InitRefresh(void); -void G_PrintMapList(void); +void G_PrintMapList(void); -void G_DeferredPlayDemo(char* demo); +void G_DeferredPlayDemo(char* demo); -void G_QuitGame(void); +void G_QuitGame(void); /// @return @c true = loading is presently possible. dd_bool G_IsLoadGamePossible(void); @@ -104,7 +104,7 @@ dd_bool G_IsSaveGamePossible(void); dd_bool G_SaveGame2(int slot, const char* name); dd_bool G_SaveGame(int slot); -void G_StopDemo(void); +void G_StopDemo(void); /** * Check if there is a finale before the map. @@ -118,15 +118,15 @@ int G_BriefingEnabled(Uri const *mapUri, ddfinale_t *fin); */ int G_DebriefingEnabled(Uri const *mapUri, ddfinale_t *fin); -void G_DoReborn(int playernum); -void G_PlayerReborn(int player); +void G_DoReborn(int playernum); +void G_PlayerReborn(int player); /** * Called after intermission ends. */ -void G_IntermissionDone(void); +void G_IntermissionDone(void); -void G_Ticker(timespan_t ticLength); +void G_Ticker(timespan_t ticLength); /// @return @c true if the input event @a ev was eaten. int G_PrivilegedResponder(event_t* ev); @@ -134,11 +134,11 @@ int G_PrivilegedResponder(event_t* ev); /// @return @c true if the input event @a ev was eaten. int G_Responder(event_t* ev); -void G_ScreenShot(void); +void G_ScreenShot(void); -void G_PrepareWIData(void); +void G_PrepareWIData(void); -void G_QueueBody(mobj_t* body); +void G_QueueBody(mobj_t* body); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/plugins/doom/include/jdoom.h b/doomsday/plugins/doom/include/jdoom.h index fe19f70fd1..6d2b80669f 100644 --- a/doomsday/plugins/doom/include/jdoom.h +++ b/doomsday/plugins/doom/include/jdoom.h @@ -32,7 +32,6 @@ #define __JDOOM_CONVENIENCE_H__ #include "../../doom/include/acfnlink.h" -#include "../../doom/include/bossbrain.h" #include "../../doom/include/d_api.h" #include "../../doom/include/d_config.h" #include "../../doom/include/d_console.h" @@ -47,6 +46,7 @@ #include "../../doom/include/m_cheat.h" #include "../../doom/include/m_random.h" #include "../../doom/include/p_enemy.h" +#include "../../doom/include/bossbrain.h" #include "../../doom/include/p_inter.h" #include "../../doom/include/p_lights.h" #include "../../doom/include/p_local.h" diff --git a/doomsday/plugins/doom/src/bossbrain.cpp b/doomsday/plugins/doom/src/bossbrain.cpp index 72411c86fe..a351ad225f 100644 --- a/doomsday/plugins/doom/src/bossbrain.cpp +++ b/doomsday/plugins/doom/src/bossbrain.cpp @@ -26,42 +26,68 @@ #include "p_saveg.h" -void P_BrainInitForMap() +BossBrain *bossBrain; // The One boss brain. + +DENG2_PIMPL_NOREF(BossBrain) +{ + int easy; + int targetOn; + int numTargets; + int maxTargets; + mobj_t **targets; + + Instance() + : easy(0) // Always init easy to 0. + , targetOn(0) + , numTargets(0) + , maxTargets(-1) + , targets(0) + {} + + ~Instance() + { + Z_Free(targets); + } +}; + +BossBrain::BossBrain() : d(new Instance) +{} + +void BossBrain::clearTargets() { - bossBrain.easy = 0; // Always init easy to 0. - // Calling shutdown rather than clear allows us to free up memory. - P_BrainShutdown(); + d->numTargets = 0; + d->targetOn = 0; } -void P_BrainClearTargets() +int BossBrain::targetCount() const { - bossBrain.numTargets = 0; - bossBrain.targetOn = 0; + return d->numTargets; } -void P_BrainWrite(Writer *writer) +void BossBrain::write(MapStateWriter *msw) const { - DENG_ASSERT(writer != 0); + Writer *writer = msw->writer(); // Not for us? if(!IS_SERVER) return; Writer_WriteByte(writer, 1); // Write a version byte. - Writer_WriteInt16(writer, bossBrain.numTargets); - Writer_WriteInt16(writer, bossBrain.targetOn); - Writer_WriteByte(writer, bossBrain.easy!=0? 1:0); + Writer_WriteInt16(writer, d->numTargets); + Writer_WriteInt16(writer, d->targetOn); + Writer_WriteByte(writer, d->easy != 0? 1:0); // Write the mobj references using the mobj archive. - for(int i = 0; i < bossBrain.numTargets; ++i) + for(int i = 0; i < d->numTargets; ++i) { - Writer_WriteInt16(writer, SV_ThingArchiveId(bossBrain.targets[i])); + Writer_WriteInt16(writer, SV_ThingArchiveId(d->targets[i])); } } -void P_BrainRead(Reader *reader, int mapVersion) +void BossBrain::read(MapStateReader *msr) { - DENG_ASSERT(reader != 0); + Reader *reader = msr->reader(); + int mapVersion = msr->mapVersion(); // Not for us? if(!IS_SERVER) return; @@ -69,55 +95,90 @@ void P_BrainRead(Reader *reader, int mapVersion) // No brain data before version 3. if(mapVersion < 3) return; - P_BrainClearTargets(); + clearTargets(); int ver = (mapVersion >= 8? Reader_ReadByte(reader) : 0); - int numTargets; + int newTargetCount; if(ver >= 1) { - numTargets = Reader_ReadInt16(reader); - bossBrain.targetOn = Reader_ReadInt16(reader); - bossBrain.easy = (dd_bool)Reader_ReadByte(reader); + newTargetCount = Reader_ReadInt16(reader); + + d->targetOn = Reader_ReadInt16(reader); + d->easy = (dd_bool)Reader_ReadByte(reader); } else { - numTargets = Reader_ReadByte(reader); - bossBrain.targetOn = Reader_ReadByte(reader); - bossBrain.easy = false; + newTargetCount = Reader_ReadByte(reader); + + d->targetOn = Reader_ReadByte(reader); + d->easy = false; } - for(int i = 0; i < numTargets; ++i) + for(int i = 0; i < newTargetCount; ++i) { - P_BrainAddTarget(SV_GetArchiveThing((int) Reader_ReadInt16(reader), 0)); + addTarget(SV_GetArchiveThing((int) Reader_ReadInt16(reader), 0)); } } -void P_BrainShutdown() -{ - Z_Free(bossBrain.targets); bossBrain.targets = 0; - bossBrain.numTargets = 0; - bossBrain.maxTargets = -1; - bossBrain.targetOn = 0; -} - -void P_BrainAddTarget(mobj_t *mo) +void BossBrain::addTarget(mobj_t *mo) { DENG_ASSERT(mo != 0); - if(bossBrain.numTargets >= bossBrain.maxTargets) + if(d->numTargets >= d->maxTargets) { // Do we need to alloc more targets? - if(bossBrain.numTargets == bossBrain.maxTargets) + if(d->numTargets == d->maxTargets) { - bossBrain.maxTargets *= 2; - bossBrain.targets = (mobj_t **)Z_Realloc(bossBrain.targets, bossBrain.maxTargets * sizeof(*bossBrain.targets), PU_APPSTATIC); + d->maxTargets *= 2; + d->targets = (mobj_t **)Z_Realloc(d->targets, d->maxTargets * sizeof(*d->targets), PU_APPSTATIC); } else { - bossBrain.maxTargets = 32; - bossBrain.targets = (mobj_t **)Z_Malloc(bossBrain.maxTargets * sizeof(*bossBrain.targets), PU_APPSTATIC, NULL); + d->maxTargets = 32; + d->targets = (mobj_t **)Z_Malloc(d->maxTargets * sizeof(*d->targets), PU_APPSTATIC, NULL); } } - bossBrain.targets[bossBrain.numTargets++] = mo; + d->targets[d->numTargets++] = mo; +} + +mobj_t *BossBrain::nextTarget() +{ + if(!d->numTargets) + return 0; + + d->easy ^= 1; + if(gameRules.skill <= SM_EASY && (!d->easy)) + return 0; + + mobj_t *targ = d->targets[d->targetOn++]; + d->targetOn %= d->numTargets; + + return targ; +} + +// C wrapper API --------------------------------------------------------------- + +void BossBrain_ClearTargets(BossBrain *bb) +{ + DENG_ASSERT(bb != 0); + return bb->clearTargets(); +} + +int BossBrain_TargetCount(BossBrain const *bb) +{ + DENG_ASSERT(bb != 0); + return bb->targetCount(); +} + +void BossBrain_AddTarget(BossBrain *bb, mobj_t *mo) +{ + DENG_ASSERT(bb != 0); + return bb->addTarget(mo); +} + +mobj_t *BossBrain_NextTarget(BossBrain *bb) +{ + DENG_ASSERT(bb != 0); + return bb->nextTarget(); } diff --git a/doomsday/plugins/doom/src/p_enemy.c b/doomsday/plugins/doom/src/p_enemy.c index 5bd0e8b019..5fec89c4cd 100644 --- a/doomsday/plugins/doom/src/p_enemy.c +++ b/doomsday/plugins/doom/src/p_enemy.c @@ -42,8 +42,6 @@ #define SKULLSPEED (20) #define TRACEANGLE (0xc000000) -bossbrain_t bossBrain; // Global state of boss brain. - // Eight directional movement speeds. #define MOVESPEED_DIAGONAL (0.71716309) @@ -1796,21 +1794,12 @@ void C_DECL A_BrainDie(mobj_t* mo) void C_DECL A_BrainSpit(mobj_t* mo) { - mobj_t* targ; - mobj_t* newmobj; - - if(!bossBrain.numTargets) - return; // Ignore if no targets. - - bossBrain.easy ^= 1; - if(gameRules.skill <= SM_EASY && (!bossBrain.easy)) - return; + mobj_t *targ = BossBrain_NextTarget(bossBrain); + mobj_t *newmobj; - // Shoot a cube at current target. - targ = bossBrain.targets[bossBrain.targetOn++]; - bossBrain.targetOn %= bossBrain.numTargets; + if(!targ) return; - // Spawn brain missile. + // Shoot a cube at this target. newmobj = P_SpawnMissile(MT_SPAWNSHOT, mo, targ); if(newmobj) { diff --git a/doomsday/plugins/doom/src/p_mobj.c b/doomsday/plugins/doom/src/p_mobj.c index ab0079b81e..f5e54421e1 100644 --- a/doomsday/plugins/doom/src/p_mobj.c +++ b/doomsday/plugins/doom/src/p_mobj.c @@ -810,7 +810,9 @@ mobj_t* P_SpawnMobjXYZ(mobjtype_t type, coord_t x, coord_t y, coord_t z, angle_t } if(type == MT_BOSSTARGET) - P_BrainAddTarget(mo); + { + BossBrain_AddTarget(bossBrain, mo); + } // Copy spawn attributes to the new mobj. mo->spawnSpot.origin[VX] = x; diff --git a/doomsday/plugins/doom64/include/g_game.h b/doomsday/plugins/doom64/include/g_game.h index 40d083a731..b6f8c121a7 100644 --- a/doomsday/plugins/doom64/include/g_game.h +++ b/doomsday/plugins/doom64/include/g_game.h @@ -39,47 +39,47 @@ #include "gamerules.h" #include "wi_stuff.h" +DENG_EXTERN_C int gaSaveGameSaveSlot; +DENG_EXTERN_C int gaLoadGameSaveSlot; + +DENG_EXTERN_C player_t players[MAXPLAYERS]; +DENG_EXTERN_C uint nextMap; + +DENG_EXTERN_C dd_bool gameInProgress; +DENG_EXTERN_C uint gameEpisode; +DENG_EXTERN_C uint gameMap; +DENG_EXTERN_C Uri *gameMapUri; +DENG_EXTERN_C uint gameMapEntrance; +DENG_EXTERN_C GameRuleset gameRules; + +DENG_EXTERN_C uint nextMap; // If non zero this will be the next map. +DENG_EXTERN_C dd_bool secretExit; +DENG_EXTERN_C int totalKills, totalItems, totalSecret; +DENG_EXTERN_C wbstartstruct_t wmInfo; +DENG_EXTERN_C int bodyQueueSlot; +DENG_EXTERN_C dd_bool paused; +DENG_EXTERN_C dd_bool precache; +DENG_EXTERN_C dd_bool customPal; +DENG_EXTERN_C int gsvMapMusic; +DENG_EXTERN_C dd_bool briefDisabled; + #ifdef __cplusplus extern "C" { #endif -extern int gaSaveGameSaveSlot; -extern int gaLoadGameSaveSlot; - -extern player_t players[MAXPLAYERS]; -extern uint nextMap; - -extern dd_bool gameInProgress; -extern uint gameEpisode; -extern uint gameMap; -extern Uri *gameMapUri; -extern uint gameMapEntrance; -extern GameRuleset gameRules; - -extern uint nextMap; // If non zero this will be the next map. -extern dd_bool secretExit; -extern int totalKills, totalItems, totalSecret; -extern wbstartstruct_t wmInfo; -extern int bodyQueueSlot; -extern dd_bool paused; -extern dd_bool precache; -extern dd_bool customPal; -extern int gsvMapMusic; -extern dd_bool briefDisabled; - -void G_Register(void); -void G_CommonPreInit(void); -void G_CommonPostInit(void); -void G_CommonShutdown(void); +void G_Register(void); +void G_CommonPreInit(void); +void G_CommonPostInit(void); +void G_CommonShutdown(void); -void R_InitRefresh(void); -void G_DeathMatchSpawnPlayer(int playernum); +void R_InitRefresh(void); +void G_DeathMatchSpawnPlayer(int playernum); -void G_PrintMapList(void); +void G_PrintMapList(void); -void G_DeferredPlayDemo(char* demo); +void G_DeferredPlayDemo(char* demo); -void G_QuitGame(void); +void G_QuitGame(void); /// @return @c true = loading is presently possible. dd_bool G_IsLoadGamePossible(void); @@ -105,18 +105,18 @@ dd_bool G_IsSaveGamePossible(void); dd_bool G_SaveGame2(int slot, const char* name); dd_bool G_SaveGame(int slot); -void G_StopDemo(void); +void G_StopDemo(void); int G_BriefingEnabled(Uri const *mapUri, ddfinale_t *fin); int G_DebriefingEnabled(Uri const *mapUri, ddfinale_t *fin); // Confusing no? -void G_DoReborn(int playernum); -void G_PlayerReborn(int player); +void G_DoReborn(int playernum); +void G_PlayerReborn(int player); -void G_IntermissionDone(void); +void G_IntermissionDone(void); -void G_Ticker(timespan_t ticLength); +void G_Ticker(timespan_t ticLength); /// @return @c true if the input event @a ev was eaten. int G_PrivilegedResponder(event_t* ev); @@ -124,11 +124,11 @@ int G_PrivilegedResponder(event_t* ev); /// @return @c true if the input event @a ev was eaten. int G_Responder(event_t* ev); -void G_ScreenShot(void); +void G_ScreenShot(void); -void G_PrepareWIData(void); +void G_PrepareWIData(void); -void G_QueueBody(mobj_t* body); +void G_QueueBody(mobj_t* body); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/plugins/heretic/include/g_game.h b/doomsday/plugins/heretic/include/g_game.h index 7c267e151b..a50fab305b 100644 --- a/doomsday/plugins/heretic/include/g_game.h +++ b/doomsday/plugins/heretic/include/g_game.h @@ -39,46 +39,46 @@ #include "h_event.h" #include "h_player.h" -#ifdef __cplusplus -extern "C" { -#endif +DENG_EXTERN_C int gaSaveGameSaveSlot; +DENG_EXTERN_C int gaLoadGameSaveSlot; -extern int gaSaveGameSaveSlot; -extern int gaLoadGameSaveSlot; +DENG_EXTERN_C player_t players[MAXPLAYERS]; -extern player_t players[MAXPLAYERS]; +DENG_EXTERN_C dd_bool gameInProgress; +DENG_EXTERN_C uint gameEpisode; +DENG_EXTERN_C uint gameMap; +DENG_EXTERN_C Uri *gameMapUri; +DENG_EXTERN_C uint gameMapEntrance; +DENG_EXTERN_C GameRuleset gameRules; -extern dd_bool gameInProgress; -extern uint gameEpisode; -extern uint gameMap; -extern Uri *gameMapUri; -extern uint gameMapEntrance; -extern GameRuleset gameRules; +DENG_EXTERN_C uint nextMap; +DENG_EXTERN_C dd_bool secretExit; +DENG_EXTERN_C int totalKills, totalItems, totalSecret; +DENG_EXTERN_C dd_bool paused; +DENG_EXTERN_C dd_bool precache; +DENG_EXTERN_C wbstartstruct_t wmInfo; +DENG_EXTERN_C dd_bool customPal; +DENG_EXTERN_C dd_bool briefDisabled; -extern uint nextMap; -extern dd_bool secretExit; -extern int totalKills, totalItems, totalSecret; -extern dd_bool paused; -extern dd_bool precache; -extern wbstartstruct_t wmInfo; -extern dd_bool customPal; -extern dd_bool briefDisabled; +DENG_EXTERN_C int gsvMapMusic; -extern int gsvMapMusic; +#ifdef __cplusplus +extern "C" { +#endif -void G_Register(void); -void G_CommonPreInit(void); -void G_CommonPostInit(void); -void G_CommonShutdown(void); +void G_Register(void); +void G_CommonPreInit(void); +void G_CommonPostInit(void); +void G_CommonShutdown(void); -void R_InitRefresh(void); -void G_DeathMatchSpawnPlayer(int playernum); +void R_InitRefresh(void); +void G_DeathMatchSpawnPlayer(int playernum); -void G_PrintMapList(void); +void G_PrintMapList(void); -void G_DeferredPlayDemo(char* demo); +void G_DeferredPlayDemo(char *demo); -void G_QuitGame(void); +void G_QuitGame(void); /// @return @c true = loading is presently possible. dd_bool G_IsLoadGamePossible(void); @@ -101,28 +101,28 @@ dd_bool G_IsSaveGamePossible(void); * If an empty string a new name will be generated automatically. * @return @c true iff @a saveSlot is valid and saving is presently possible. */ -dd_bool G_SaveGame2(int slot, const char* name); +dd_bool G_SaveGame2(int slot, char const *name); dd_bool G_SaveGame(int slot); -void G_StopDemo(void); +void G_StopDemo(void); int G_BriefingEnabled(Uri const *mapUri, ddfinale_t *fin); int G_DebriefingEnabled(Uri const *mapUri, ddfinale_t *fin); -void G_DoReborn(int playernum); -void G_PlayerReborn(int player); +void G_DoReborn(int playernum); +void G_PlayerReborn(int player); -void G_IntermissionDone(void); +void G_IntermissionDone(void); -void G_Ticker(timespan_t ticLength); +void G_Ticker(timespan_t ticLength); /// @return @c true if the input event @a ev was eaten. -int G_PrivilegedResponder(event_t* ev); +int G_PrivilegedResponder(event_t *ev); /// @return @c true if the input event @a ev was eaten. -int G_Responder(event_t* ev); +int G_Responder(event_t *ev); -void G_ScreenShot(void); +void G_ScreenShot(void); #ifdef __cplusplus } // extern "C" diff --git a/doomsday/plugins/hexen/include/g_game.h b/doomsday/plugins/hexen/include/g_game.h index cd05d4a6ec..1113ee1c08 100644 --- a/doomsday/plugins/hexen/include/g_game.h +++ b/doomsday/plugins/hexen/include/g_game.h @@ -36,44 +36,44 @@ #include "p_mobj.h" #include "x_player.h" -#ifdef __cplusplus -extern "C" { -#endif +DENG_EXTERN_C int gaSaveGameSaveSlot; +DENG_EXTERN_C int gaLoadGameSaveSlot; -extern int gaSaveGameSaveSlot; -extern int gaLoadGameSaveSlot; +DENG_EXTERN_C player_t players[MAXPLAYERS]; -extern player_t players[MAXPLAYERS]; +DENG_EXTERN_C dd_bool gameInProgress; +DENG_EXTERN_C uint gameEpisode; +DENG_EXTERN_C uint gameMap; +DENG_EXTERN_C Uri *gameMapUri; +DENG_EXTERN_C uint gameMapEntrance; +DENG_EXTERN_C GameRuleset gameRules; -extern dd_bool gameInProgress; -extern uint gameEpisode; -extern uint gameMap; -extern Uri *gameMapUri; -extern uint gameMapEntrance; -extern GameRuleset gameRules; +DENG_EXTERN_C dd_bool paused; +DENG_EXTERN_C dd_bool precache; +DENG_EXTERN_C dd_bool customPal; -extern dd_bool paused; -extern dd_bool precache; -extern dd_bool customPal; +DENG_EXTERN_C uint nextMap; +DENG_EXTERN_C uint nextMapEntrance; +DENG_EXTERN_C dd_bool briefDisabled; -extern uint nextMap; -extern uint nextMapEntrance; -extern dd_bool briefDisabled; +DENG_EXTERN_C int gsvMapMusic; -extern int gsvMapMusic; +#ifdef __cplusplus +extern "C" { +#endif -void G_CommonShutdown(void); +void G_CommonShutdown(void); -void R_InitRefresh(void); -void R_GetTranslation(int plrClass, int plrColor, int* tclass, int* tmap); -void Mobj_UpdateTranslationClassAndMap(mobj_t* mo); +void R_InitRefresh(void); +void R_GetTranslation(int plrClass, int plrColor, int *tclass, int *tmap); +void Mobj_UpdateTranslationClassAndMap(mobj_t *mo); -void G_PrintMapList(void); +void G_PrintMapList(void); int G_BriefingEnabled(Uri const *mapUri, ddfinale_t *fin); int G_DebriefingEnabled(Uri const *mapUri, ddfinale_t *fin); -void G_QuitGame(void); +void G_QuitGame(void); /// @return @c true = loading is presently possible. dd_bool G_IsLoadGamePossible(void); @@ -96,34 +96,34 @@ dd_bool G_IsSaveGamePossible(void); * If an empty string a new name will be generated automatically. * @return @c true iff @a saveSlot is valid and saving is presently possible. */ -dd_bool G_SaveGame2(int slot, const char* name); +dd_bool G_SaveGame2(int slot, char const *name); dd_bool G_SaveGame(int slot); -void G_CommonPreInit(void); -void G_CommonPostInit(void); +void G_CommonPreInit(void); +void G_CommonPostInit(void); -int G_GetInteger(int id); -void* G_GetVariable(int id); +int G_GetInteger(int id); +void *G_GetVariable(int id); -void G_PlayerReborn(int player); -void G_DeathMatchSpawnPlayer(int playernum); -void G_DeferredPlayDemo(char* demo); -void G_DoPlayDemo(void); +void G_PlayerReborn(int player); +void G_DeathMatchSpawnPlayer(int playernum); +void G_DeferredPlayDemo(char *demo); +void G_DoPlayDemo(void); -void G_PlayDemo(char* name); -void G_TimeDemo(char* name); -void G_IntermissionDone(void); -void G_ScreenShot(void); -void G_DoReborn(int playernum); -void G_StopDemo(void); +void G_PlayDemo(char *name); +void G_TimeDemo(char *name); +void G_IntermissionDone(void); +void G_ScreenShot(void); +void G_DoReborn(int playernum); +void G_StopDemo(void); -void G_Ticker(timespan_t ticLength); +void G_Ticker(timespan_t ticLength); /// @return @c true if the input event @a ev was eaten. -int G_PrivilegedResponder(event_t* ev); +int G_PrivilegedResponder(event_t *ev); /// @return @c true if the input event @a ev was eaten. -int G_Responder(event_t* ev); +int G_Responder(event_t *ev); #ifdef __cplusplus } // extern "C" From 0f709435b5ff6f2c2178514d557489969c2409a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 10 Feb 2014 07:16:17 +0200 Subject: [PATCH 15/15] Fixed|Hexen: Build failure (order of includes) The Map API was not declared as being in use early enough. Also added a header file missing from common.pri. --- doomsday/plugins/common/common.pri | 1 + doomsday/plugins/hexen/include/jhexen.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doomsday/plugins/common/common.pri b/doomsday/plugins/common/common.pri index fdba754ce6..7947bcb6da 100644 --- a/doomsday/plugins/common/common.pri +++ b/doomsday/plugins/common/common.pri @@ -15,6 +15,7 @@ HEADERS += \ $$common_inc/d_net.h \ $$common_inc/d_netcl.h \ $$common_inc/d_netsv.h \ + $$common_inc/dmu_archiveindex.h \ $$common_inc/dmu_lib.h \ $$common_inc/fi_lib.h \ $$common_inc/g_common.h \ diff --git a/doomsday/plugins/hexen/include/jhexen.h b/doomsday/plugins/hexen/include/jhexen.h index 737127feda..18262fa398 100644 --- a/doomsday/plugins/hexen/include/jhexen.h +++ b/doomsday/plugins/hexen/include/jhexen.h @@ -32,6 +32,7 @@ #define __JHEXEN_CONVENIENCE_H__ #include "../../hexen/include/h2def.h" +#include "../../hexen/include/x_api.h" #include "../../hexen/include/a_action.h" #include "../../hexen/include/acfnlink.h" #include "../../hexen/include/acscript.h" @@ -59,7 +60,6 @@ #include "../../hexen/include/st_stuff.h" #include "../../hexen/include/textdefs.h" #include "../../hexen/include/version.h" -#include "../../hexen/include/x_api.h" #include "../../hexen/include/x_console.h" #include "../../hexen/include/x_config.h" #include "../../hexen/include/x_event.h"