diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 72f3520c3..631f1b1e3 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -535,6 +535,7 @@ typedef enum CL_DOWNLOADFILES, CL_ASKJOIN, CL_LOADFILES, + CL_SETUPFILES, CL_WAITJOINRESPONSE, CL_DOWNLOADSAVEGAME, CL_CONNECTED, @@ -621,6 +622,9 @@ static inline void CL_DrawConnectionStatus(void) case CL_CONFIRMCONNECT: cltext = ""; break; + case CL_SETUPFILES: + cltext = M_GetText("Configuring addons..."); + break; case CL_ASKJOIN: case CL_WAITJOINRESPONSE: if (serverisfull) @@ -1860,7 +1864,12 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic cl_mode = CL_LOADFILES; break; case CL_LOADFILES: - if (CL_LoadServerFiles()) + if (CL_LoadServerFiles()) + cl_mode = CL_SETUPFILES; + + break; + case CL_SETUPFILES: + if (P_PartialAddGetStage() < 0 || P_MultiSetupWadFiles(false)) { *asksent = 0; //This ensure the first join ask is right away firstconnectattempttime = I_GetTime(); @@ -2073,7 +2082,13 @@ static void CL_ConnectToServer(void) #else if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL)) #endif + + { + if (P_PartialAddGetStage() >= 0) + P_MultiSetupWadFiles(true); // in case any partial adds were done + return; + } if (server) { diff --git a/src/d_netfil.c b/src/d_netfil.c index 68181685f..3e6278e0d 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -560,7 +560,7 @@ boolean CL_LoadServerFiles(void) continue; // Already loaded else if (fileneeded[i].status == FS_FOUND) { - P_AddWadFile(fileneeded[i].filename); + P_PartialAddWadFile(fileneeded[i].filename); G_SetGameModified(true, false); fileneeded[i].status = FS_OPEN; return false; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 6b857eab7..f0b8219e9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -309,22 +309,30 @@ patch_t *HU_UpdateOrBlankPatch(patch_t **user, boolean required, const char *for va_list ap; char buffer[9]; - lumpnum_t lump; + lumpnum_t lump = INT16_MAX; patch_t *patch; va_start (ap, format); vsnprintf(buffer, sizeof buffer, format, ap); va_end (ap); - if (user && p_adding_file != INT16_MAX) + if (user && partadd_earliestfile != UINT16_MAX) { - lump = W_CheckNumForNamePwad(buffer, p_adding_file, 0); + UINT16 fileref = numwadfiles; + lump = INT16_MAX; + + while ((lump == INT16_MAX) && ((--fileref) >= partadd_earliestfile)) + { + lump = W_CheckNumForNamePwad(buffer, fileref, 0); + } /* no update in this wad */ - if (lump == INT16_MAX) + if (fileref < partadd_earliestfile) return *user; - lump |= (p_adding_file << 16); + CONS_Printf("pe = %d, fr = %d\n", partadd_earliestfile, fileref); + + lump |= (fileref << 16); } else { diff --git a/src/p_setup.c b/src/p_setup.c index ba6e533e6..883abf974 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -169,6 +169,13 @@ mapthing_t *playerstarts[MAXPLAYERS]; mapthing_t *bluectfstarts[MAXPLAYERS]; mapthing_t *redctfstarts[MAXPLAYERS]; +// Global state for PartialAddWadFile/MultiSetupWadFiles +// Might be replacable with parameters, but non-trivial when the functions are called on separate tics +static SINT8 partadd_stage = -1; +static boolean partadd_replacescurrentmap = false; +static boolean partadd_important = false; +UINT16 partadd_earliestfile = UINT16_MAX; + // Maintain *ZOOM TUBE* waypoints // Renamed because SRB2Kart owns real waypoints. mobj_t *tubewaypoints[NUMTUBEWAYPOINTSEQUENCES][TUBEWAYPOINTSEQUENCESIZE]; @@ -4665,22 +4672,32 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } -UINT16 p_adding_file = INT16_MAX; - // // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps // boolean P_AddWadFile(const char *wadfilename) +{ + UINT16 wadnum; + + if ((wadnum = P_PartialAddWadFile(wadfilename)) == UINT16_MAX) + return false; + + P_MultiSetupWadFiles(true); + return true; +} + +// +// Add a WAD file and do the per-WAD setup stages. +// Call P_MultiSetupWadFiles as soon as possible after any number of these. +// +UINT16 P_PartialAddWadFile(const char *wadfilename) { size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; - - //boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes? boolean mapsadded = false; - boolean replacedcurrentmap = false; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. @@ -4699,12 +4716,21 @@ boolean P_AddWadFile(const char *wadfilename) if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX) { refreshdirmenu |= REFRESHDIR_NOTLOADED; - return false; + return UINT16_MAX; } - else - wadnum = (UINT16)(numwadfiles-1); + wadnum = (UINT16)(numwadfiles-1); + + // Init partadd. + if (wadfiles[wadnum]->important) + { + partadd_important = true; + } + if (partadd_stage != 0) + { + partadd_earliestfile = wadnum; + } + partadd_stage = 0; - p_adding_file = wadnum; switch(wadfiles[wadnum]->type) { @@ -4804,29 +4830,25 @@ boolean P_AddWadFile(const char *wadfilename) // TEXTURES/etc. list. R_LoadTexturesPwad(wadnum); // numtexture changes - // Reload ANIMDEFS - P_InitPicAnims(); - // Reload BRIGHT K_InitBrightmapsPwad(wadnum); - // Flush and reload HUD graphics - //ST_UnloadGraphics(); - HU_LoadGraphics(); - ST_LoadGraphics(); - // // look for skins // R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] R_PatchSkins(wadnum); // toast: PATCH PATCH - ST_ReloadSkinFaceGraphics(); // // edit music defs // S_LoadMusicDefs(wadnum); + // + // extra sprite/skin data + // + R_LoadSpriteInfoLumps(wadnum, numlumps); + // // search for maps // @@ -4848,46 +4870,102 @@ boolean P_AddWadFile(const char *wadfilename) { G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you } - mapheaderinfo[num - 1]->alreadyExists = true; } - //If you replaced the map you're on, end the level when done. if (num == gamemap) - replacedcurrentmap = true; + partadd_replacescurrentmap = true; CONS_Printf("%s\n", name); mapsadded = true; } } + if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); + + refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_ flags to disappear the next frame, but this one's a bit too dangerous for that... + partadd_stage = 0; + return wadnum; +} - R_LoadSpriteInfoLumps(wadnum, numlumps); +// Only exists to make sure there's no way to overwrite partadd_stage externally +// unless you really push yourself. +SINT8 P_PartialAddGetStage(void) +{ + return partadd_stage; +} + +// +// Set up a series of partially added WAD files. +// Setup functions that iterate over every loaded WAD go here. +// If fullsetup false, only do one stage per call. +// +boolean P_MultiSetupWadFiles(boolean fullsetup) +{ + if (partadd_stage < 0) + I_Error(M_GetText("P_MultiSetupWadFiles: Post-load addon setup attempted without loading any addons first")); + + if (partadd_stage == 0) + { + // Flush and reload HUD graphics + //ST_UnloadGraphics(); + HU_LoadGraphics(); + ST_LoadGraphics(); + ST_ReloadSkinFaceGraphics(); + + if (!partadd_important) + partadd_stage = -1; // everything done + else if (fullsetup) + partadd_stage++; + } + + if (partadd_stage == 1) + { + // Reload all textures, unconditionally for better or worse. + //R_LoadTextures(); + + // Prevent savefile cheating + if (cursaveslot >= 0) + cursaveslot = -1; + + // Reload ANIMATED / ANIMDEFS + P_InitPicAnims(); + + + // reload status bar (warning should have valid player!) + if (gamestate == GS_LEVEL) + ST_Start(); #ifdef HWRENDER HWR_ReloadModels(); #endif - // reload status bar (warning should have valid player!) - if (gamestate == GS_LEVEL) - ST_Start(); - - // Prevent savefile cheating - if (cursaveslot > 0) - cursaveslot = 0; - - if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) - { - CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + if (fullsetup) + partadd_stage++; } - refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_GAMEDATA to disappear the next frame, but it's a bit too dangerous for that... + if (partadd_stage == 2) + { + if (partadd_replacescurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) + { + CONS_Printf(M_GetText("Current map %d replaced, ending the level to ensure consistency.\n"), gamemap); + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + } + partadd_stage = -1; + } - p_adding_file = INT16_MAX; - LUA_HookVoid(HOOK(AddonLoaded)); - - return true; + I_Assert(!fullsetup || partadd_stage < 0); + + if (partadd_stage < 0) + { + partadd_important = false; + partadd_replacescurrentmap = false; + partadd_earliestfile = UINT16_MAX; + return true; + } + + partadd_stage++; + return false; } diff --git a/src/p_setup.h b/src/p_setup.h index 7a8a8c18f..84efa412e 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -96,8 +96,6 @@ INT32 P_CheckLevelFlat(const char *flatname); extern size_t nummapthings; extern mapthing_t *mapthings; -extern UINT16 p_adding_file; - void P_SetupLevelSky(const char *skytexname, boolean global); #ifdef SCANTHINGS void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); @@ -108,6 +106,27 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); void HWR_LoadLevel(void); #endif boolean P_AddWadFile(const char *wadfilename); + +// WARNING: The following functions should be grouped as follows: +// any amount of PartialAdds followed by MultiSetups until returned true, +// as soon as possible. +UINT16 P_PartialAddWadFile(const char *wadfilename); +// Run a single stage of multisetup, or all of them if fullsetup set. +// fullsetup true: run everything +// otherwise +// stage 0: reload UI graphics (enough for unimportant WADs) +// stage 1: reload textures +// stage 2: reload animdefs and run post-setup actions +// returns true if setup finished on this call, false otherwise (always true on fullsetup) +// throws I_Error if called without any partial adds started as a safeguard +boolean P_MultiSetupWadFiles(boolean fullsetup); +// Get the current setup stage. +// if negative, no PartialAdds done since last MultiSetup +// if 0, partial adds done but MultiSetup not called yet +// if positive, setup's partway done +SINT8 P_PartialAddGetStage(void); +extern UINT16 partadd_earliestfile; + boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); diff --git a/src/p_spec.c b/src/p_spec.c index 18467adb0..ef3e7172a 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -166,7 +166,7 @@ void P_ParseAnimationDefintion(SINT8 istexture); * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_) */ -static boolean animdeftempflats = false; // only until ANIMDEFS flats are removed +static boolean animdeftempflats = false; void P_InitPicAnims(void) { @@ -187,7 +187,7 @@ void P_InitPicAnims(void) while (animdefsLumpNum != INT16_MAX) { - animdeftempflats = ((p_adding_file == INT16_MAX) || p_adding_file == w); + animdeftempflats = ((partadd_earliestfile == UINT16_MAX) || partadd_earliestfile == w); P_ParseANIMDEFSLump(w, animdefsLumpNum); animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", (UINT16)w, animdefsLumpNum + 1); }