diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a19c4a1a..841bbb13 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1117,6 +1117,7 @@ typedef enum CL_DOWNLOADFILES, CL_ASKJOIN, CL_LOADFILES, + CL_SETUPFILES, CL_WAITJOINRESPONSE, #ifdef JOININGAME CL_DOWNLOADSAVEGAME, @@ -1228,6 +1229,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) @@ -2429,7 +2433,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(); @@ -2635,7 +2644,11 @@ 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 01a43fa4..8f46c045 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -486,7 +486,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/dehacked.c b/src/dehacked.c index 9bf5f43d..168d6525 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2641,109 +2641,6 @@ static void readconditionset(MYFILE *f, UINT8 setnum) Z_Free(s); } -static void readtexture(MYFILE *f, const char *name) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - char *tmp; - INT32 i, j, value; - UINT16 width = 0, height = 0; - INT16 patchcount = 0; - texture_t *texture; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - - value = searchvalue(s); - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " "); - if (word2) - strupr(word2); - else - break; - - // Width of the texture. - if (fastcmp(word, "WIDTH")) - { - DEH_WriteUndoline(word, va("%d", width), UNDO_NONE); - width = SHORT((UINT16)value); - } - // Height of the texture. - else if (fastcmp(word, "HEIGHT")) - { - DEH_WriteUndoline(word, va("%d", height), UNDO_NONE); - height = SHORT((UINT16)value); - } - // Number of patches the texture has. - else if (fastcmp(word, "NUMPATCHES")) - { - DEH_WriteUndoline(word, va("%d", patchcount), UNDO_NONE); - patchcount = SHORT((UINT16)value); - } - else - deh_warning("readtexture: unknown word '%s'", word); - } - } while (!myfeof(f)); - - // Error checking. - if (!width) - I_Error("Texture %s has no width!\n", name); - - if (!height) - I_Error("Texture %s has no height!\n", name); - - if (!patchcount) - I_Error("Texture %s has no patches!\n", name); - - // Allocate memory for the texture, and fill in information. - texture = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * SHORT(patchcount)), PU_STATIC, NULL); - M_Memcpy(texture->name, name, sizeof(texture->name)); - texture->width = width; - texture->height = height; - texture->patchcount = patchcount; - texture->holes = false; - // Fill out the texture patches, to allow them to be detected - // accurately by readpatch. - for (i = 0; i < patchcount; i++) - { - texture->patches[i].originx = 0; - texture->patches[i].originy = 0; - texture->patches[i].wad = UINT16_MAX; - texture->patches[i].lump = UINT16_MAX; - } - - // Jump to the next empty texture entry. - i = 0; - while (textures[i]) - i++; - - // Fill the global texture buffer entries. - j = 1; - while (j << 1 <= texture->width) - j <<= 1; - - textures[i] = texture; - texturewidthmask[i] = j - 1; - textureheight[i] = texture->height << FRACBITS; - - // Clean up. - Z_Free(s); -} - static void readpatch(MYFILE *f, const char *name, UINT16 wad) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3350,14 +3247,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) if (word2[strlen(word2)-1] == '\n') word2[strlen(word2)-1] = '\0'; i = atoi(word2); - if (fastcmp(word, "TEXTURE")) - { - // Read texture from spec file. - readtexture(f, word2); - DEH_WriteUndoline(word, word2, UNDO_HEADER); - // This is not a major mod. - } - else if (fastcmp(word, "PATCH")) + if (fastcmp(word, "PATCH")) { // Read patch from spec file. readpatch(f, word2, wad); diff --git a/src/p_setup.c b/src/p_setup.c index 328a3ff3..54504f4b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -143,6 +143,12 @@ 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; + /** Logs an error about a map being corrupt, then terminate. * This allows reporting highly technical errors for usefulness, without * confusing a novice map designer who simply needs to run ZenNode. @@ -3438,23 +3444,39 @@ boolean P_RunSOC(const char *socfilename) // 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; boolean mapsadded = false; - boolean replacedcurrentmap = false; + lumpinfo_t *lumpinfo; if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX) { refreshdirmenu |= REFRESHDIR_NOTLOADED; CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); - return false; + return UINT16_MAX; } else wadnum = (UINT16)(numwadfiles-1); + if (wadfiles[wadnum]->important) + partadd_important = true; + // // search for sound replacements // @@ -3488,14 +3510,6 @@ boolean P_AddWadFile(const char *wadfilename) CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); digmreplaces++; } -#if 0 - // - // search for texturechange replacements - // - else if (!memcmp(name, "TEXTURE1", 8) || !memcmp(name, "TEXTURE2", 8) - || !memcmp(name, "PNAMES", 6)) -#endif - texturechange = true; } if (!devparm && sreplaces) CONS_Printf(M_GetText("%s sounds replaced\n"), sizeu1(sreplaces)); @@ -3504,28 +3518,12 @@ boolean P_AddWadFile(const char *wadfilename) if (!devparm && digmreplaces) CONS_Printf(M_GetText("%s digital musics replaced\n"), sizeu1(digmreplaces)); - // // search for sprite replacements // R_AddSpriteDefs(wadnum); - // Reload it all anyway, just in case they - // added some textures but didn't insert a - // TEXTURE1/PNAMES/etc. list. - if (texturechange) // initialized in the sound check - R_LoadTextures(); // numtexture changes - else - R_FlushTextureCache(); // just reload it from file - - // Reload ANIMATED / ANIMDEFS - P_InitPicAnims(); - - // Flush and reload HUD graphics - ST_UnloadGraphics(); - HU_LoadGraphics(); - ST_LoadGraphics(); - ST_ReloadSkinFaceGraphics(); + // everything from MultiSetupWadFile until ST_Start was here originally // // look for skins @@ -3560,9 +3558,8 @@ boolean P_AddWadFile(const char *wadfilename) mapheaderinfo[num-1]->menuflags |= LF2_EXISTSHACK; } - //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; @@ -3571,24 +3568,85 @@ boolean P_AddWadFile(const char *wadfilename) if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); - // reload status bar (warning should have valid player!) - if (gamestate == GS_LEVEL) - ST_Start(); + 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... + partadd_stage = 0; + return wadnum; +} - // Prevent savefile cheating - if (cursaveslot >= 0) - cursaveslot = -1; +// 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; +} - if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) +// +// 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("Post-load addon setup attempted without loading any addons first")); + + if (partadd_stage == 0) { - 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); + // 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; // run next stage too } - 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 == 1) + { + // Reload all textures, unconditionally for better or worse. + R_LoadTextures(); - return true; + if (fullsetup) + ++partadd_stage; + } + + if (partadd_stage == 2) + { + // Reload ANIMATED / ANIMDEFS + P_InitPicAnims(); + + // reload status bar (warning should have valid player!) + if (gamestate == GS_LEVEL) + ST_Start(); + + // Prevent savefile cheating + if (cursaveslot >= 0) + cursaveslot = -1; + + 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; + } + + I_Assert(!fullsetup || partadd_stage < 0); + + if (partadd_stage < 0) + { + partadd_important = false; + partadd_replacescurrentmap = false; + return true; + } + else + { + ++partadd_stage; + return false; + } } #ifdef DELFILE diff --git a/src/p_setup.h b/src/p_setup.h index c4a3aab9..5ff53e13 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -64,6 +64,26 @@ boolean P_AddWadFile(const char *wadfilename); #ifdef DELFILE boolean P_DelWadFile(void); #endif + +// 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); + boolean P_RunSOC(const char *socfilename); void P_WriteThings(lumpnum_t lump); size_t P_PrecacheLevelFlats(void); diff --git a/src/r_data.c b/src/r_data.c index 43bc6ed8..5fe40e06 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -503,42 +503,31 @@ void R_LoadTextures(void) } patchlump = W_CacheLumpNumPwad((UINT16)w, texstart + j, PU_CACHE); - // Then, check the lump directly to see if it's a texture SOC, - // and if it is, load it using dehacked instead. - if (strstr((const char *)patchlump, "TEXTURE")) - { - CONS_Alert(CONS_WARNING, "%s is a Texture SOC.\n", W_CheckNameForNumPwad((UINT16)w,texstart+j)); - Z_Unlock(patchlump); - DEH_LoadDehackedLumpPwad((UINT16)w, texstart + j); - } - else - { - //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); - texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); + //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); + texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); - // Set texture properties. - M_Memcpy(texture->name, W_CheckNameForNumPwad((UINT16)w, texstart + j), sizeof(texture->name)); - texture->width = SHORT(patchlump->width); - texture->height = SHORT(patchlump->height); - texture->patchcount = 1; - texture->holes = false; + // Set texture properties. + M_Memcpy(texture->name, W_CheckNameForNumPwad((UINT16)w, texstart + j), sizeof(texture->name)); + texture->width = SHORT(patchlump->width); + texture->height = SHORT(patchlump->height); + texture->patchcount = 1; + texture->holes = false; - // Allocate information for the texture's patches. - patch = &texture->patches[0]; + // Allocate information for the texture's patches. + patch = &texture->patches[0]; - patch->originx = patch->originy = 0; - patch->wad = (UINT16)w; - patch->lump = texstart + j; + patch->originx = patch->originy = 0; + patch->wad = (UINT16)w; + patch->lump = texstart + j; - Z_Unlock(patchlump); + Z_Unlock(patchlump); - k = 1; - while (k << 1 <= texture->width) - k <<= 1; + k = 1; + while (k << 1 <= texture->width) + k <<= 1; - texturewidthmask[i] = k - 1; - textureheight[i] = texture->height << FRACBITS; - } + texturewidthmask[i] = k - 1; + textureheight[i] = texture->height << FRACBITS; i++; } }