diff --git a/src/d_main.c b/src/d_main.c index e321693ee..21f6055a2 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -817,7 +817,7 @@ static void IdentifyVersion(void) if (srb2wad1 == NULL && srb2wad2 == NULL) I_Error("No more free memory to look in %s", srb2waddir); if (srb2wad1 != NULL) - sprintf(srb2wad1, pandf, srb2waddir, "srb2.srb"); + sprintf(srb2wad1, pandf, srb2waddir, "srb2.pk3"); if (srb2wad2 != NULL) sprintf(srb2wad2, pandf, srb2waddir, "srb2.wad"); @@ -847,9 +847,6 @@ static void IdentifyVersion(void) // Add the players D_AddFile(va(pandf,srb2waddir, "player.dta")); - // Add the weapons - D_AddFile(va(pandf,srb2waddir,"rings.dta")); - #ifdef USE_PATCH_DTA // Add our crappy patches to fix our bugs D_AddFile(va(pandf,srb2waddir,"patch.dta")); @@ -1137,16 +1134,15 @@ void D_SRB2Main(void) //W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad //W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta //W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta - //W_VerifyFileMD5(3, ASSET_HASH_RINGS_DTA); // rings.dta #ifdef USE_PATCH_DTA - W_VerifyFileMD5(4, ASSET_HASH_PATCH_DTA); // patch.dta + W_VerifyFileMD5(3, ASSET_HASH_PATCH_DTA); // patch.dta #endif // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif //ifndef DEVELOP - mainwads = 4; // there are 4 wads not to unload + mainwads = 3; // there are 3 wads not to unload #ifdef USE_PATCH_DTA ++mainwads; // patch.dta adds one more #endif @@ -1373,7 +1369,9 @@ void D_SRB2Main(void) else if (!dedicated && M_MapLocked(pstartmap)) I_Error("You need to unlock this level before you can warp to it!\n"); else + { D_MapChange(pstartmap, gametype, ultimatemode, true, 0, false, false); + } } } else if (M_CheckParm("-skipintro")) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c7d384b0d..b9c53a1b7 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1604,16 +1604,12 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese { static char buf[2+MAX_WADPATH+1+4]; static char *buf_p = buf; - // The supplied data are assumed to be good. I_Assert(delay >= 0 && delay <= 2); - if (mapnum != -1) CV_SetValue(&cv_nextmap, mapnum); - CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene); - if ((netgame || multiplayer) && !((gametype == newgametype) && (newgametype == GT_COOP))) FLS = false; @@ -1621,9 +1617,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese { UINT8 flags = 0; const char *mapname = G_BuildMapName(mapnum); - I_Assert(W_CheckNumForName(mapname) != LUMPERROR); - buf_p = buf; if (pultmode) flags |= 1; @@ -3243,6 +3237,8 @@ static void Command_ListWADS_f(void) CONS_Printf("\x82 IWAD\x80: %s\n", tempname); else if (i <= mainwads) CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname); + else if (!wadfiles[i]->important) + CONS_Printf("\x86 %.2d: %s\n", i, tempname); else CONS_Printf(" %.2d: %s\n", i, tempname); } diff --git a/src/d_netfil.c b/src/d_netfil.c index bf94e0ca7..72ac0dd32 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -753,11 +753,10 @@ void Got_Filetxpak(void) char *filename = file->filename; static INT32 filetime = 0; - if (!(strcmp(filename, "srb2.srb") + if (!(strcmp(filename, "srb2.pk3") && strcmp(filename, "srb2.wad") && strcmp(filename, "zones.dta") && strcmp(filename, "player.dta") - && strcmp(filename, "rings.dta") && strcmp(filename, "patch.dta") && strcmp(filename, "music.dta") )) diff --git a/src/dehacked.c b/src/dehacked.c index 8f6dbaa1a..0e2b8b4f4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3346,9 +3346,15 @@ static void DEH_LoadDehackedFile(MYFILE *f) if (gamestate == GS_TITLESCREEN) { if (introchanged) + { + menuactive = false; COM_BufAddText("playintro"); + } else if (titlechanged) + { + menuactive = false; COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed + } } dbg_line = -1; diff --git a/src/filesrch.c b/src/filesrch.c index b4a995154..2b5493642 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -441,7 +441,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want char exttable[NUM_EXT_TABLE][5] = { ".txt", ".cfg", // exec - ".wad", ".soc", ".lua"}; // addfile + ".wad", ".pk3", ".soc", ".lua"}; // addfile char filenamebuf[MAX_WADFILES][MAX_WADPATH]; diff --git a/src/filesrch.h b/src/filesrch.h index c2201b453..e88242698 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -54,6 +54,7 @@ typedef enum EXT_CFG, EXT_LOADSTART, EXT_WAD = EXT_LOADSTART, + EXT_PK3, EXT_SOC, EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt NUM_EXT, diff --git a/src/m_menu.c b/src/m_menu.c index aa199f289..34f623718 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4740,6 +4740,7 @@ static void M_Addons(INT32 choice) addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); + addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC); @@ -5155,6 +5156,7 @@ static void M_HandleAddons(INT32 choice) // else intentional fallthrough case EXT_SOC: case EXT_WAD: + case EXT_PK3: COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); addonsresponselimit = 5; break; diff --git a/src/p_setup.c b/src/p_setup.c index 83c9348c9..26234bccb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -354,16 +354,13 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) * \param lump VERTEXES lump number. * \sa ML_VERTEXES */ -static inline void P_LoadVertexes(lumpnum_t lumpnum) + +static inline void P_LoadRawVertexes(UINT8 *data, size_t i) { - UINT8 *data; - size_t i; mapvertex_t *ml; vertex_t *li; - // Determine number of lumps: - // total lump length / vertex record length. - numvertexes = W_LumpLength(lumpnum) / sizeof (mapvertex_t); + numvertexes = i / sizeof (mapvertex_t); if (numvertexes <= 0) I_Error("Level has no vertices"); // instead of crashing @@ -371,9 +368,6 @@ static inline void P_LoadVertexes(lumpnum_t lumpnum) // Allocate zone memory for buffer. vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - // Load data into cache. - data = W_CacheLumpNum(lumpnum, PU_STATIC); - ml = (mapvertex_t *)data; li = vertexes; @@ -383,11 +377,16 @@ static inline void P_LoadVertexes(lumpnum_t lumpnum) li->x = SHORT(ml->x)<y = SHORT(ml->y)<numlights = 0; li->rlights = NULL; } +} +static void P_LoadSegs(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawSegs(data, W_LumpLength(lumpnum)); Z_Free(data); } + /** Loads the SSECTORS resource from a level. * * \param lump Lump number of the SSECTORS resource. * \sa ::ML_SSECTORS */ -static inline void P_LoadSubsectors(lumpnum_t lumpnum) +static inline void P_LoadRawSubsectors(void *data, size_t i) { - void *data; - size_t i; mapsubsector_t *ms; subsector_t *ss; - numsubsectors = W_LumpLength(lumpnum) / sizeof (mapsubsector_t); + numsubsectors = i / sizeof (mapsubsector_t); if (numsubsectors <= 0) I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); ss = subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL); - data = W_CacheLumpNum(lumpnum,PU_STATIC); ms = (mapsubsector_t *)data; @@ -510,13 +509,14 @@ static inline void P_LoadSubsectors(lumpnum_t lumpnum) #endif ss->validcount = 0; } - - Z_Free(data); } -// -// P_LoadSectors -// +static void P_LoadSubsectors(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawSubsectors(data, W_LumpLength(lumpnum)); + Z_Free(data); +} // // levelflats @@ -543,24 +543,21 @@ size_t P_PrecacheLevelFlats(void) return flatmemory; } -// help function for P_LoadSectors, find a flat in the active wad files, +// Auxiliary function. Find a flat in the active wad files, // allocate an id for it, and set the levelflat (to speedup search) -// INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) { size_t i; - // - // first scan through the already found flats - // + // Scan through the already found flats, break if it matches. for (i = 0; i < numlevelflats; i++, levelflat++) - if (strnicmp(levelflat->name,flatname,8)==0) + if (strnicmp(levelflat->name, flatname, 8) == 0) break; - // that flat was already found in the level, return the id + // If there is no match, make room for a new flat. if (i == numlevelflats) { - // store the name + // Store the name. strlcpy(levelflat->name, flatname, sizeof (levelflat->name)); strupr(levelflat->name); @@ -644,29 +641,31 @@ INT32 P_CheckLevelFlat(const char *flatname) return (INT32)i; } -static void P_LoadSectors(lumpnum_t lumpnum) +// Sets up the ingame sectors structures. +// Lumpnum is the lumpnum of a SECTORS lump. +static void P_LoadRawSectors(UINT8 *data, size_t i) { - UINT8 *data; - size_t i; mapsector_t *ms; sector_t *ss; levelflat_t *foundflats; - numsectors = W_LumpLength(lumpnum) / sizeof (mapsector_t); + // We count how many sectors we got. + numsectors = i / sizeof (mapsector_t); if (numsectors <= 0) I_Error("Level has no sectors"); + + // Allocate as much memory as we need into the global sectors table. sectors = Z_Calloc(numsectors*sizeof (*sectors), PU_LEVEL, NULL); - data = W_CacheLumpNum(lumpnum,PU_STATIC); - - //Fab : FIXME: allocate for whatever number of flats - // 512 different flats per level should be plenty + // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. + //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats)); if (foundflats == NULL) I_Error("Ran out of memory while loading sectors\n"); numlevelflats = 0; + // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. ms = (mapsector_t *)data; ss = sectors; for (i = 0; i < numsectors; i++, ss++, ms++) @@ -674,9 +673,6 @@ static void P_LoadSectors(lumpnum_t lumpnum) ss->floorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = P_AddLevelFlat(ms->floorpic, foundflats); ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats); @@ -741,8 +737,6 @@ static void P_LoadSectors(lumpnum_t lumpnum) #endif // ----- end special tricks ----- } - Z_Free(data); - // set the sky flat num skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats); @@ -754,22 +748,26 @@ static void P_LoadSectors(lumpnum_t lumpnum) P_SetupLevelFlatAnims(); } +static void P_LoadSectors(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawSectors(data, W_LumpLength(lumpnum)); + Z_Free(data); +} + // // P_LoadNodes // -static void P_LoadNodes(lumpnum_t lumpnum) +static void P_LoadRawNodes(UINT8 *data, size_t i) { - UINT8 *data; - size_t i; UINT8 j, k; mapnode_t *mn; node_t *no; - numnodes = W_LumpLength(lumpnum) / sizeof (mapnode_t); + numnodes = i / sizeof (mapnode_t); if (numnodes <= 0) I_Error("Level has no nodes"); nodes = Z_Calloc(numnodes * sizeof (*nodes), PU_LEVEL, NULL); - data = W_CacheLumpNum(lumpnum, PU_STATIC); mn = (mapnode_t *)data; no = nodes; @@ -787,7 +785,12 @@ static void P_LoadNodes(lumpnum_t lumpnum) no->bbox[j][k] = SHORT(mn->bbox[j][k])<sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides) { ld->sidenum[j] = 0xffff; - CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1)); } } } @@ -1251,14 +1251,14 @@ static void P_LoadLineDefs(lumpnum_t lumpnum) { ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); } if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED)) { ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); } if (ld->sidenum[0] != 0xffff && ld->special) @@ -1270,7 +1270,12 @@ static void P_LoadLineDefs(lumpnum_t lumpnum) ld->polyobj = NULL; #endif } +} +static void P_LoadLineDefs(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawLineDefs(data, W_LumpLength(lumpnum)); Z_Free(data); } @@ -1372,22 +1377,24 @@ static void P_LoadLineDefs2(void) } } -// -// P_LoadSideDefs -// -static inline void P_LoadSideDefs(lumpnum_t lumpnum) + + +static inline void P_LoadRawSideDefs(size_t i) { - numsides = W_LumpLength(lumpnum) / sizeof (mapsidedef_t); + numsides = i / sizeof (mapsidedef_t); if (numsides <= 0) I_Error("Level has no sidedefs"); sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); } -// Delay loading texture names until after loaded linedefs. - -static void P_LoadSideDefs2(lumpnum_t lumpnum) +static inline void P_LoadSideDefs(lumpnum_t lumpnum) +{ + P_LoadRawSideDefs(W_LumpLength(lumpnum)); +} + + +static void P_LoadRawSideDefs2(void *data) { - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); UINT16 i; INT32 num; @@ -1405,7 +1412,7 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) if (sector_num >= numsectors) { - CONS_Debug(DBG_SETUP, "P_LoadSideDefs2: sidedef %u has out-of-range sector num %u\n", i, sector_num); + CONS_Debug(DBG_SETUP, "P_LoadRawSideDefs2: sidedef %u has out-of-range sector num %u\n", i, sector_num); sector_num = 0; } sd->sector = sec = §ors[sector_num]; @@ -1619,11 +1626,18 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) break; } } - - Z_Free(data); R_ClearTextureNumCache(true); } +// Delay loading texture names until after loaded linedefs. +static void P_LoadSideDefs2(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawSideDefs2(data); + Z_Free(data); +} + + static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1) { fixed_t bbox[4]; @@ -2297,6 +2311,7 @@ void P_LoadThingsOnly(void) centerid = i; // save id just in case } + for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function.acp1 != (actionf_p1)P_MobjThinker) @@ -2313,10 +2328,10 @@ void P_LoadThingsOnly(void) P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); P_LoadThings(); + // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0]; skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; - P_SpawnSecretItems(true); } @@ -2566,6 +2581,7 @@ boolean P_SetupLevel(boolean skipprecip) // use gamemap to get map number. // 99% of the things already did, so. // Map header should always be in place at this point + char *lumpfullName; INT32 i, loadprecip = 1, ranspecialwipe = 0; INT32 loademblems = 1; INT32 fromnetsave = 0; @@ -2728,7 +2744,12 @@ boolean P_SetupLevel(boolean skipprecip) } // internal game map - lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); + maplumpname = G_BuildMapName(gamemap); + //lastloadedmaplumpnum = LUMPERROR; + lastloadedmaplumpnum = W_CheckNumForName(maplumpname); + + if (lastloadedmaplumpnum == INT16_MAX) + I_Error("Map %s not found.\n", maplumpname); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); CON_SetupBackColormap(); @@ -2738,42 +2759,87 @@ boolean P_SetupLevel(boolean skipprecip) P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); - // note: most of this ordering is important - loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); - P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); - P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); + // HACK ALERT: Cache the WAD, get the map data into the tables, free memory. + // As it is implemented right now, we're assuming an uncompressed WAD. + // (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.) + // We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error. + lumpfullName = (wadfiles[WADFILENUM(lastloadedmaplumpnum)]->lumpinfo + LUMPNUM(lastloadedmaplumpnum))->name2; + if (!strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4)) + { + // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. + UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); + //filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs; + filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); + P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size); + P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size); + P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size); + P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size); + P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos); + P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size); + P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size); + P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size); - P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS); - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 - P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS); + // Important: take care of the ordering of the next functions. + if (!loadedbm) + P_CreateBlockMap(); // Graue 02-29-2004 + R_MakeColormaps(); + P_LoadLineDefs2(); + P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; - R_MakeColormaps(); - P_LoadLineDefs2(); - P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS); - P_LoadNodes(lastloadedmaplumpnum + ML_NODES); - P_LoadSegs(lastloadedmaplumpnum + ML_SEGS); - P_LoadReject(lastloadedmaplumpnum + ML_REJECT); - P_GroupLines(); + // reset the player starts + for (i = 0; i < MAXPLAYERS; i++) + playerstarts[i] = NULL; - numdmstarts = numredctfstarts = numbluectfstarts = 0; + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = NULL; + for (i = 0; i < 16; i++) + skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; + P_MapStart(); - for (i = 0; i < 16; i++) - skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; + P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size); + Z_Free(wadData); + } + else + { + // Important: take care of the ordering of the next functions. + loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); + P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); + P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); + P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); + P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS); + P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS); + P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS); + P_LoadNodes(lastloadedmaplumpnum + ML_NODES); + P_LoadSegs(lastloadedmaplumpnum + ML_SEGS); + P_LoadReject(lastloadedmaplumpnum + ML_REJECT); - P_MapStart(); + // Important: take care of the ordering of the next functions. + if (!loadedbm) + P_CreateBlockMap(); // Graue 02-29-2004 + R_MakeColormaps(); + P_LoadLineDefs2(); + P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + // reset the player starts + for (i = 0; i < MAXPLAYERS; i++) + playerstarts[i] = NULL; + + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; + + for (i = 0; i < 16; i++) + skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; + + P_MapStart(); + + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + } // init gravity, tag lists, // anything that P_ResetDynamicSlopes/P_LoadThings needs to know @@ -2784,7 +2850,6 @@ boolean P_SetupLevel(boolean skipprecip) #endif P_LoadThings(); - // skybox mobj defaults skyboxmo[0] = skyboxviewpnts[0]; skyboxmo[1] = skyboxcenterpnts[0]; @@ -3078,6 +3143,50 @@ boolean P_RunSOC(const char *socfilename) return true; } +// Auxiliary function for PK3 loading - looks for sound replacements. +// NOTE: it does not really add any new sound entry or anything. +void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num) +{ + size_t j; + lumpinfo_t *lumpinfo = wadfiles[wadnum]->lumpinfo + first; + for (; num > 0; num--, lumpinfo++) + { + // Let's check whether it's replacing an existing sound or it's a brand new one. + for (j = 1; j < NUMSFX; j++) + { + if (S_sfx[j].name && !strnicmp(S_sfx[j].name, lumpinfo->name + 2, 6)) + { + // the sound will be reloaded when needed, + // since sfx->data will be NULL + CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", lumpinfo->name); + + I_FreeSfx(&S_sfx[j]); + } + } + } +} + +// Auxiliary function for PK3 loading - looks for music and music replacements. +// NOTE: does nothing but print debug messages. The code is handled somewhere else. +void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num) +{ + lumpinfo_t *lumpinfo = wadfiles[wadnum]->lumpinfo + first; + char *name; + for (; num > 0; num--, lumpinfo++) + { + name = lumpinfo->name; + if (name[0] == 'O' && name[1] == '_') + { + CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); + } + else if (name[0] == 'D' && name[1] == '_') + { + CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); + } + } + return; +} + // // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps @@ -3091,47 +3200,118 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) lumpinfo_t *lumpinfo; boolean replacedcurrentmap = false; - if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX) + // Vars to help us with the position start and amount of each resource type. + // Useful for PK3s since they use folders. + // WADs use markers for some resources, but others such as sounds are checked lump-by-lump anyway. +// UINT16 luaPos, luaNum = 0; +// UINT16 socPos, socNum = 0; + UINT16 sfxPos, sfxNum = 0; + UINT16 musPos = 0, musNum = 0; +// UINT16 sprPos, sprNum = 0; + UINT16 texPos, texNum = 0; +// UINT16 patPos, patNum = 0; +// UINT16 flaPos, flaNum = 0; +// UINT16 mapPos, mapNum = 0; + + // Init file. + if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX) { refreshdirmenu |= REFRESHDIR_NOTLOADED; CONS_Printf(M_GetText("Errors occured while loading %s; not added.\n"), wadfilename); return false; } - else wadnum = (UINT16)(numwadfiles-1); + else + wadnum = (UINT16)(numwadfiles-1); - // - // search for sound replacements - // - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < numlumps; i++, lumpinfo++) + switch(wadfiles[wadnum]->type) { - name = lumpinfo->name; - if (name[0] == 'D') + case RET_PK3: { - if (name[1] == 'S') for (j = 1; j < NUMSFX; j++) + // Auxiliary function - input a folder name and gives us the resource markers positions. + void FindFolder(const char *folName, UINT16 *start, UINT16 *end) { - if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6)) + if (!stricmp(lumpinfo->name2, folName)) { - // the sound will be reloaded when needed, - // since sfx->data will be NULL - CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name); + lumpinfo++; + *start = ++i; + for (; i < numlumps; i++, lumpinfo++) + if (strnicmp(lumpinfo->name2, folName, strlen(folName))) + break; + lumpinfo--; + *end = i-- - *start; + return; + } + return; + } - I_FreeSfx(&S_sfx[j]); + // Look for the lumps that act as resource delimitation markers. + lumpinfo = wadfiles[wadnum]->lumpinfo; + for (i = 0; i < numlumps; i++, lumpinfo++) + { +// FindFolder("Lua/", &luaPos, &luaNum); +// FindFolder("SOCs/", &socPos, &socNum); + FindFolder("Sounds/", &sfxPos, &sfxNum); + FindFolder("Music/", &musPos, &musNum); +// FindFolder("Sprites/", &sprPos, &sprNum); + FindFolder("Textures/", &texPos, &texNum); +// FindFolder("Patches/", &patPos, &patNum); +// FindFolder("Flats/", &flaPos, &flaNum); +// FindFolder("Maps/", &mapPos, &mapNum); + } - sreplaces++; + // Update the detected resources. + // Note: ALWAYS load Lua scripts first, SOCs right after, and the remaining resources afterwards. +#ifdef HAVE_BLUA +// if (luaNum) // Lua scripts. +// P_LoadLuaScrRange(wadnum, luaPos, luaNum); +#endif +// if (socNum) // SOCs. +// P_LoadDehackRange(wadnum, socPos, socNum); + if (sfxNum) // Sounds. TODO: Function currently only updates already existing sounds, the rest is handled somewhere else. + P_LoadSoundsRange(wadnum, sfxPos, sfxNum); + if (musNum) // Music. TODO: Useless function right now. + P_LoadMusicsRange(wadnum, musPos, musNum); +// if (sprNum) // Sprites. +// R_LoadSpritsRange(wadnum, sprPos, sprNum); +// if (texNum) // Textures. TODO: R_LoadTextures() does the folder positioning once again. New function maybe? +// R_LoadTextures(); +// if (mapNum) // Maps. TODO: Actually implement the map WAD loading code, lulz. +// P_LoadWadMapRange(wadnum, mapPos, mapNum); + } + break; + default: + lumpinfo = wadfiles[wadnum]->lumpinfo; + for (i = 0; i < numlumps; i++, lumpinfo++) + { + name = lumpinfo->name; + if (name[0] == 'D') + { + if (name[1] == 'S') for (j = 1; j < NUMSFX; j++) + { + if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6)) + { + // the sound will be reloaded when needed, + // since sfx->data will be NULL + CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name); + + I_FreeSfx(&S_sfx[j]); + + sreplaces++; + } + } + else if (name[1] == '_') + { + CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); + mreplaces++; } } - else if (name[1] == '_') + else if (name[0] == 'O' && name[1] == '_') { CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); - mreplaces++; + digmreplaces++; } } - else if (name[0] == 'O' && name[1] == '_') - { - CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name); - digmreplaces++; - } + break; } if (!devparm && sreplaces) CONS_Printf(M_GetText("%s sounds replaced\n"), sizeu1(sreplaces)); @@ -3140,9 +3320,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) if (!devparm && digmreplaces) CONS_Printf(M_GetText("%s digital musics replaced\n"), sizeu1(digmreplaces)); - // - // search for sprite replacements - // + // Search for sprite replacements. R_AddSpriteDefs(wadnum); // Reload it all anyway, just in case they diff --git a/src/p_setup.h b/src/p_setup.h index 3443ffdb7..de763bed0 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -61,6 +61,8 @@ void P_LoadThingsOnly(void); boolean P_SetupLevel(boolean skipprecip); boolean P_AddWadFile(const char *wadfilename, char **firstmapname); boolean P_RunSOC(const char *socfilename); +void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); +void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_WriteThings(lumpnum_t lump); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); diff --git a/src/p_spec.c b/src/p_spec.c index 03643a708..803c1ab86 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -145,22 +145,23 @@ void P_InitPicAnims(void) size_t i; I_Assert(animdefs == NULL); - + maxanims = 0; - if (W_CheckNumForName("ANIMDEFS") != LUMPERROR) + for (w = numwadfiles-1; w >= 0; w--) { - for (w = numwadfiles-1; w >= 0; w--) - { - UINT16 animdefsLumpNum; + UINT16 animdefsLumpNum; - // Find ANIMDEFS lump in the WAD - animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0); - if (animdefsLumpNum != INT16_MAX) - P_ParseANIMDEFSLump(w, animdefsLumpNum); + // Find ANIMDEFS lump in the WAD + animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0); + + while (animdefsLumpNum != INT16_MAX) + { + P_ParseANIMDEFSLump(w, animdefsLumpNum); + animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", (UINT16)w, animdefsLumpNum + 1); } } - + // Define the last one animdefs[maxanims].istexture = -1; strncpy(animdefs[maxanims].endname, "", 9); diff --git a/src/r_data.c b/src/r_data.c index c578012d1..1a6162dc2 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -528,8 +528,8 @@ void R_FlushTextureCache(void) } // Need these prototypes for later; defining them here instead of r_data.h so they're "private" -int R_CountTexturesInTEXTURESLump(UINT16 wadNum); -void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *index); +int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum); +void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index); // // R_LoadTextures @@ -567,13 +567,22 @@ void R_LoadTextures(void) // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. for (w = 0, numtextures = 0; w < numwadfiles; w++) { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - - if (texturesLumpPos != INT16_MAX) + if (wadfiles[w]->type == RET_PK3) { - numtextures += R_CountTexturesInTEXTURESLump((UINT16)w); + texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; + texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); + } + + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + while (texturesLumpPos != INT16_MAX) + { + numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); } // Add all the textures between TX_START and TX_END @@ -588,7 +597,6 @@ void R_LoadTextures(void) I_Error("No textures detected in any WADs!\n"); } } - // Allocate memory and initialize to 0 for all the textures we are initialising. // There are actually 5 buffers allocated in one for convenience. textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); @@ -610,12 +618,25 @@ void R_LoadTextures(void) for (i = 0, w = 0; w < numwadfiles; w++) { // Get the lump numbers for the markers in the WAD, if they exist. - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - - if (texturesLumpPos != INT16_MAX) - R_ParseTEXTURESLump(w,&i); + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + while (texturesLumpPos != INT16_MAX) + { + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); + } + } + else + { + texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; + texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + if (texturesLumpPos != INT16_MAX) + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + } if (texstart == INT16_MAX || texend == INT16_MAX) continue; @@ -1013,7 +1034,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) } // Parses the TEXTURES lump... but just to count the number of textures. -int R_CountTexturesInTEXTURESLump(UINT16 wadNum) +int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum) { char *texturesLump; size_t texturesLumpLength; @@ -1024,11 +1045,11 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum) // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll // need to make a space of memory where I can ensure that it will terminate // correctly. Start by loading the relevant data from the WAD. - texturesLump = (char *)W_CacheLumpNumPwad(wadNum,W_CheckNumForNamePwad("TEXTURES", wadNum, 0),PU_STATIC); + texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); // If that didn't exist, we have nothing to do here. if (texturesLump == NULL) return 0; // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. - texturesLumpLength = W_LumpLengthPwad(wadNum,W_CheckNumForNamePwad("TEXTURES",wadNum,0)); + texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); // Now move the contents of the lump into this new location. memmove(texturesText,texturesLump,texturesLumpLength); @@ -1060,7 +1081,7 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum) } // Parses the TEXTURES lump... for real, this time. -void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *texindex) +void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex) { char *texturesLump; size_t texturesLumpLength; @@ -1073,11 +1094,11 @@ void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *texindex) // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll // need to make a space of memory where I can ensure that it will terminate // correctly. Start by loading the relevant data from the WAD. - texturesLump = (char *)W_CacheLumpNumPwad(wadNum,W_CheckNumForNamePwad("TEXTURES", wadNum, 0),PU_STATIC); + texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); // If that didn't exist, we have nothing to do here. if (texturesLump == NULL) return; // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. - texturesLumpLength = W_LumpLengthPwad(wadNum,W_CheckNumForNamePwad("TEXTURES",wadNum,0)); + texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); // Now move the contents of the lump into this new location. memmove(texturesText,texturesLump,texturesLumpLength); @@ -1164,12 +1185,60 @@ static void R_InitExtraColormaps(void) CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps)); } -// 12/14/14 -- only take flats in F_START/F_END +// Search for flat name through all lumpnum_t R_GetFlatNumForName(const char *name) { - lumpnum_t lump = W_CheckNumForNameInBlock(name, "F_START", "F_END"); - if (lump == LUMPERROR) - lump = W_CheckNumForNameInBlock(name, "FF_START", "FF_END"); // deutex, some other old things + INT32 i; + lumpnum_t lump; + lumpnum_t start; + lumpnum_t end; + + // Scan wad files backwards so patched flats take preference. + for (i = numwadfiles - 1; i >= 0; i--) + { + + if (wadfiles[i]->type == RET_PK3) + { + start = W_CheckNumForFolderStartPK3("Flats/", i, 0); + if (start == INT16_MAX) + continue; + end = W_CheckNumForFolderEndPK3("Flats/", i, start); + if (end == INT16_MAX) + continue; + } + else // WAD type? use markers. + { + // Find the ranges to work with. + start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0); + if (start == INT16_MAX) + { + start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0); + if (start == INT16_MAX) + continue; + else + { + end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start); + if (end == INT16_MAX) + continue; + } + } + else + { + end = W_CheckNumForNamePwad("F_END", (UINT16)i, start); + if (end == INT16_MAX) + continue; + } + } + // Now find lump with specified name in that range. + lump = W_CheckNumForNamePwad(name, (UINT16)i, start); + if (lump < end) + { + lump += (i<<16); // found it, in our constraints + break; + } + lump = LUMPERROR; + } + if (lump == LUMPERROR) { if (strcmp(name, SKYFLATNAME)) @@ -1218,7 +1287,6 @@ void R_ReInitColormaps(UINT16 num) { char colormap[9] = "COLORMAP"; lumpnum_t lump; - if (num > 0 && num <= 10000) snprintf(colormap, 8, "CLM%04u", num-1); diff --git a/src/r_things.c b/src/r_things.c index 9ab7b5d1e..d201786a5 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -379,31 +379,40 @@ void R_AddSpriteDefs(UINT16 wadnum) UINT16 start, end; char wadname[MAX_WADPATH]; - // find the sprites section in this pwad - // we need at least the S_END - // (not really, but for speedup) - - start = W_CheckNumForNamePwad("S_START", wadnum, 0); - if (start == INT16_MAX) - start = W_CheckNumForNamePwad("SS_START", wadnum, 0); //deutex compatib. - if (start == INT16_MAX) - start = 0; //let say S_START is lump 0 + // Find the sprites section in this resource file. + if (wadfiles[wadnum]->type == RET_PK3) + start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0); else - start++; // just after S_START + { + start = W_CheckNumForNamePwad("S_START", wadnum, 0); + if (start == INT16_MAX) + start = W_CheckNumForNamePwad("SS_START", wadnum, 0); //deutex compatib. + if (start == INT16_MAX) + start = 0; //let say S_START is lump 0 + else + start++; // just after S_START + } // ignore skin wads (we don't want skin sprites interfering with vanilla sprites) - if (start == 0 && W_CheckNumForNamePwad("S_SKIN", wadnum, 0) != INT16_MAX) + if (start == 0 && W_CheckNumForNamePwad("S_SKIN", wadnum, 0) != UINT16_MAX) return; - end = W_CheckNumForNamePwad("S_END",wadnum,start); - if (end == INT16_MAX) - end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib. + if (wadfiles[wadnum]->type == RET_PK3) + end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start); + else + { + end = W_CheckNumForNamePwad("S_END",wadnum,start); + if (end == INT16_MAX) + end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib. + } + if (end == INT16_MAX) { CONS_Debug(DBG_SETUP, "no sprites in pwad %d\n", wadnum); return; } + // // scan through lumps, for each sprite, find all the sprite frames // diff --git a/src/r_things.h b/src/r_things.h index e1a171c1f..9a9761d5b 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -231,7 +231,7 @@ char *GetPlayerFacePic(INT32 skinnum); // Future: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!@ ]] FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) { -#if 1 // 2.1 compat +#if 0 // 2.1 compat return 'A' + frame; #else if (frame < 26) return 'A' + frame; @@ -245,7 +245,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn) { -#if 1 // 2.1 compat +#if 0 // 2.1 compat return cn - 'A'; #else if (cn >= 'A' && cn <= 'Z') return cn - 'A'; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 3e46a9b6a..0412344e6 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -142,7 +142,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); /** \brief WAD file to look for */ -#define WADKEYWORD1 "srb2.srb" +#define WADKEYWORD1 "srb2.pk3" #define WADKEYWORD2 "srb2.wad" /** \brief holds wad path */ diff --git a/src/w_wad.c b/src/w_wad.c index 2aa0a6316..c8701f98f 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -22,6 +22,22 @@ #include "lzf.h" #endif +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +//#ifdef HAVE_ZLIB +#include "zlib.h" +//#endif // HAVE_ZLIB + #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" @@ -65,14 +81,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #pragma pack(1) #endif -// a raw entry of the wad directory -typedef struct -{ - UINT32 filepos; // file offset of the resource - UINT32 size; // size of the resource - char name[8]; // name of the resource -} ATTRPACK filelump_t; - #if defined(_MSC_VER) #pragma pack() #endif @@ -113,6 +121,8 @@ void W_Shutdown(void) fclose(wadfiles[numwadfiles]->handle); Z_Free(wadfiles[numwadfiles]->lumpinfo); Z_Free(wadfiles[numwadfiles]->filename); + while (wadfiles[numwadfiles]->numlumps--) + Z_Free(wadfiles[numwadfiles]->lumpinfo[wadfiles[numwadfiles]->numlumps].name2); Z_Free(wadfiles[numwadfiles]); } } @@ -172,6 +182,26 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) return handle; } +// Look for all DEHACKED and Lua scripts inside a PK3 archive. +static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum) +{ + UINT16 posStart, posEnd; + posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); + if (posStart != INT16_MAX) + { + posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); + for (; posStart < posEnd; posStart++) + LUA_LoadLump(wadnum, posStart); + } + posStart = W_CheckNumForFolderStartPK3("SOCs/", wadnum, 0); + if (posStart != INT16_MAX) + { + posEnd = W_CheckNumForFolderEndPK3("SOCs/", wadnum, posStart); + for(; posStart < posEnd; posStart++) + DEH_LoadDehackedLumpPwad(wadnum, posStart); + } +} + // search for all DEHACKED lump in all wads and load it static inline void W_LoadDehackedLumps(UINT16 wadnum) { @@ -284,12 +314,13 @@ static void W_InvalidateLumpnumCache(void) // // Can now load dehacked files (.soc) // -UINT16 W_LoadWadFile(const char *filename) +UINT16 W_InitFile(const char *filename) { FILE *handle; lumpinfo_t *lumpinfo; wadfile_t *wadfile; - UINT32 numlumps; + enum restype type; + UINT16 numlumps; size_t i; INT32 compressed = 0; size_t packetsize; @@ -335,12 +366,32 @@ UINT16 W_LoadWadFile(const char *filename) packetsizetally = packetsize; } +#ifndef NOMD5 + // + // w-waiiiit! + // Let's not add a wad file if the MD5 matches + // an MD5 of an already added WAD file! + // + W_MakeFileMD5(filename, md5sum); + + for (i = 0; i < numwadfiles; i++) + { + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); + return INT16_MAX; + } + } +#endif + // detect dehacked file with the "soc" extension if (!stricmp(&filename[strlen(filename) - 4], ".soc")) { // This code emulates a wadfile with one lump name "OBJCTCFG" // at position 0 and size of the whole file. // This allows soc files to be like all wads, copied by network and loaded at the console. + type = RET_WAD; + numlumps = 1; lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); lumpinfo->position = 0; @@ -348,6 +399,10 @@ UINT16 W_LoadWadFile(const char *filename) lumpinfo->size = ftell(handle); fseek(handle, 0, SEEK_SET); strcpy(lumpinfo->name, "OBJCTCFG"); + // Allocate the lump's full name. + lumpinfo->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strcpy(lumpinfo->name2, "OBJCTCFG"); + lumpinfo->name2[8] = '\0'; } #ifdef HAVE_BLUA // detect lua script with the "lua" extension @@ -356,6 +411,8 @@ UINT16 W_LoadWadFile(const char *filename) // This code emulates a wadfile with one lump name "LUA_INIT" // at position 0 and size of the whole file. // This allows soc files to be like all wads, copied by network and loaded at the console. + type = RET_WAD; + numlumps = 1; lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); lumpinfo->position = 0; @@ -363,15 +420,205 @@ UINT16 W_LoadWadFile(const char *filename) lumpinfo->size = ftell(handle); fseek(handle, 0, SEEK_SET); strcpy(lumpinfo->name, "LUA_INIT"); + // Allocate the lump's full name. + lumpinfo->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strcpy(lumpinfo->name2, "LUA_INIT"); + lumpinfo->name2[8] = '\0'; } #endif + else if (!stricmp(&filename[strlen(filename) - 4], ".pk3")) + { + char curHeader[4]; + unsigned long size; + char seekPat[] = {0x50, 0x4b, 0x01, 0x02, 0x00}; + char endPat[] = {0x50, 0x4b, 0x05, 0x06, 0x00}; + char *s; + int c; + UINT32 position; + boolean matched = false; + lumpinfo_t *lump_p; + + type = RET_PK3; + + // Obtain the file's size. + fseek(handle, 0, SEEK_END); + size = ftell(handle); + CONS_Debug(DBG_SETUP, "PK3 size is: %ld\n", size); + + // We must look for the central directory through the file. (Thanks to JTE for this algorithm.) + // All of the central directory entry headers have a signature of 0x50 0x4b 0x01 0x02. + // The first entry found means the beginning of the central directory. + fseek(handle, -min(size, (22 + 65536)), SEEK_CUR); + s = endPat; + while((c = fgetc(handle)) != EOF) + { + if (*s != c && s > endPat) // No match? + s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array. + if (*s == c) + { + s++; + if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature. + { + matched = true; + CONS_Debug(DBG_SETUP, "Found PK3 central directory at position %ld.\n", ftell(handle)); + break; + } + } + } + + // Error if we couldn't find the central directory at all. It likely means this is not a ZIP/PK3 file. + if (matched == false) + { + CONS_Alert(CONS_ERROR, "No central directory inside PK3! File may be corrupted or incomplete.\n"); + return INT16_MAX; + } + + fseek(handle, 4, SEEK_CUR); + fread(&numlumps, 1, 2, handle); + fseek(handle, 6, SEEK_CUR); + fread(&position, 1, 4, handle); + lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); + fseek(handle, position, SEEK_SET); + + // Since we found the central directory, now we can map our lumpinfo table. + // We will look for file headers inside it, until we reach the central directory end signature. + // We exactly know what data to expect this time, so now we don't need to do a byte-by-byte search. + CONS_Debug(DBG_SETUP, "Now finding central directory file headers...\n"); + for (i = 0; i < numlumps; i++, lump_p++) + { + fread(curHeader, 1, 4, handle); + + // We found a central directory entry signature? + if (!strncmp(curHeader, seekPat, 3)) + { + // Let's fill in the fields that we actually need. + // (Declaring all those vars might not be the optimal way to do this, sorry.) + char *eName; + int namePos; + int nameEnd; + unsigned short int eNameLen = 8; + unsigned short int eXFieldLen = 0; + unsigned short int lNameLen = 0; + unsigned short int lXFieldLen = 0; + unsigned short int eCommentLen = 0; + unsigned short int eCompression = 0; + unsigned int eSize = 0; + unsigned int eCompSize = 0; + unsigned int eLocalHeaderOffset = 0; + unsigned long int rememberPos = 0; + + // We get the compression type indicator value. + fseek(handle, 6, SEEK_CUR); + fread(&eCompression, 1, 2, handle); + // Get the size + fseek(handle, 8, SEEK_CUR); + fread(&eCompSize, 1, 4, handle); + fread(&eSize, 1, 4, handle); + // We get the variable length fields. + fread(&eNameLen, 1, 2, handle); + fread(&eXFieldLen, 1, 2, handle); + fread(&eCommentLen, 1, 2, handle); + fseek(handle, 8, SEEK_CUR); + fread(&eLocalHeaderOffset, 1, 4, handle); // Get the offset. + + eName = malloc(sizeof(char)*(eNameLen + 1)); + fgets(eName, eNameLen + 1, handle); + + // Don't load lump if folder. +// if (*(eName + eNameLen - 1) == '/') +// continue; + + // We must calculate the position for the actual data. + // Why not eLocalHeaderOffset + 30 + eNameLen + eXFieldLen? That's because the extra field and name lengths MAY be different in the local headers. + rememberPos = ftell(handle); + fseek(handle, eLocalHeaderOffset + 26, SEEK_SET); + fread(&lNameLen, 1, 2, handle); + fread(&lXFieldLen, 1, 2, handle); + lump_p->position = ftell(handle) + lNameLen + lXFieldLen; + + fseek(handle, rememberPos, SEEK_SET); // Let's go back to the central dir. + lump_p->disksize = eCompSize; + lump_p->size = eSize; + + // We will trim the file's full name so that only the filename is left. + namePos = eNameLen - 1; + while(namePos--) + if(eName[namePos] == '/') + break; + namePos++; + // We will remove the file extension too. + nameEnd = 0; + while(nameEnd++ < 8) + if(eName[namePos + nameEnd] == '.') + break; + memset(lump_p->name, '\0', 9); + strncpy(lump_p->name, eName + namePos, nameEnd); + + lump_p->name2 = Z_Malloc((eNameLen+1)*sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->name2, eName, eNameLen); + lump_p->name2[eNameLen] = '\0'; + + // We set the compression type from what we're supporting so far. + switch(eCompression) + { + case 0: + lump_p->compression = CM_NOCOMPRESSION; + break; + case 8: + lump_p->compression = CM_DEFLATE; + break; + case 14: + lump_p->compression = CM_LZF; + break; + default: + CONS_Alert(CONS_WARNING, "Lump has an unsupported compression type!\n"); + lump_p->compression = CM_UNSUPPORTED; + break; + } + CONS_Debug(DBG_SETUP, "File %s, data begins at: %ld\n", eName, lump_p->position); + fseek(handle, eXFieldLen + eCommentLen, SEEK_CUR); // We skip to where we expect the next central directory entry or end marker to be. + free(eName); + } + // We found the central directory end signature? + else if (!strncmp(curHeader, endPat, 4)) + { + CONS_Debug(DBG_SETUP, "Central directory end signature found at: %ld\n", ftell(handle)); + + /*// We will create a "virtual" marker lump at the very end of lumpinfo for convenience. + // This marker will be used by the different lump-seeking (eg. textures, sprites, etc.) in PK3-specific cases in an auxiliary way. + lumpinfo = (lumpinfo_t*) Z_Realloc(lumpinfo, (numlumps + 1)*sizeof(*lumpinfo), PU_STATIC, NULL); + strcpy(lumpinfo[numlumps].name, "PK3_ENDM\0"); + lumpinfo[numlumps].name2 = Z_Malloc(14 * sizeof(char), PU_STATIC, NULL); + strcpy(lumpinfo[numlumps].name2, "PK3_ENDMARKER\0"); + lumpinfo[numlumps].position = 0; + lumpinfo[numlumps].size = 0; + lumpinfo[numlumps].disksize = 0; + lumpinfo[numlumps].compression = CM_NOCOMPRESSION; + numlumps++;*/ + break; + } + // ... None of them? We're only expecting either a central directory signature entry or the central directory end signature. + // The file may be broken or incomplete... + else + { + CONS_Alert(CONS_WARNING, "Expected central directory header signature, got something else!"); + return INT16_MAX; + } + } + // If we've reached this far, then it means our dynamically stored lumpinfo has to be ready. + // Now we finally build our... incorrectly called wadfile. + // TODO: Maybe we should give them more generalized names, like resourcefile or resfile or something. + // Mostly for clarity and better understanding when reading the code. + } + // assume wad file else { - // assume wad file wadinfo_t header; lumpinfo_t *lump_p; filelump_t *fileinfo; void *fileinfov; + + type = RET_WAD; // read the header if (fread(&header, 1, sizeof header, handle) < sizeof header) @@ -427,47 +674,37 @@ UINT16 W_LoadWadFile(const char *filename) if (realsize != 0) { lump_p->size = realsize; - lump_p->compressed = 1; + lump_p->compression = CM_LZF; } else { lump_p->size -= 4; - lump_p->compressed = 0; + lump_p->compression = CM_NOCOMPRESSION; } lump_p->position += 4; lump_p->disksize -= 4; } - else lump_p->compressed = 0; + else + { + lump_p->compression = CM_NOCOMPRESSION; + } memset(lump_p->name, 0x00, 9); strncpy(lump_p->name, fileinfo->name, 8); + // Allocate the lump's full name. + lump_p->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->name2, fileinfo->name, 8); + lump_p->name2[8] = '\0'; } free(fileinfov); } -#ifndef NOMD5 - // - // w-waiiiit! - // Let's not add a wad file if the MD5 matches - // an MD5 of an already added WAD file! - // - W_MakeFileMD5(filename, md5sum); - - for (i = 0; i < numwadfiles; i++) - { - if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) - { - CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); - return INT16_MAX; - } - } -#endif - // // link wad file to search files // wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); wadfile->filename = Z_StrDup(filename); + wadfile->type = type; wadfile->handle = handle; wadfile->numlumps = (UINT16)numlumps; wadfile->lumpinfo = lumpinfo; @@ -494,7 +731,13 @@ UINT16 W_LoadWadFile(const char *filename) CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); wadfiles[numwadfiles] = wadfile; numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded - W_LoadDehackedLumps(numwadfiles-1); + + // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. + if (wadfile->type == RET_WAD) + W_LoadDehackedLumps(numwadfiles - 1); + else if (wadfile->type == RET_PK3) + W_LoadDehackedLumpsPK3(numwadfiles - 1); + W_InvalidateLumpnumCache(); @@ -523,7 +766,7 @@ INT32 W_InitMultipleFiles(char **filenames) for (; *filenames; filenames++) { //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); - rc &= (W_LoadWadFile(*filenames) != INT16_MAX) ? 1 : 0; + rc &= (W_InitFile(*filenames) != INT16_MAX) ? 1 : 0; } if (!numwadfiles) @@ -591,16 +834,59 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) - { if (memcmp(lump_p->name,uname,8) == 0) return i; - } } // not found. return INT16_MAX; } +// Look for the first lump from a folder. +UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump) +{ + INT32 i; + lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) + { + if (strnicmp(name, lump_p->name2, strlen(name)) == 0) + break; + } + return i; +} + +// In a PK3 type of resource file, it looks for the next lumpinfo entry that doesn't share the specified pathfile. +// Useful for finding folder ends. +// Returns the position of the lumpinfo entry. +UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump) +{ + INT32 i; + lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) + { + if (strnicmp(name, lump_p->name2, strlen(name))) + break; + } + return i; +} + +// In a PK3 type of resource file, it looks for an entry with the specified full name. +// Returns lump position in PK3's lumpinfo, or INT16_MAX if not found. +UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump) +{ + INT32 i; + lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) + { + if (!strnicmp(name, lump_p->name2, strlen(name))) + { + return i; + } + } + // Not found at all? + return INT16_MAX; +} + // // W_CheckNumForName // Returns LUMPERROR if name not found. @@ -641,6 +927,37 @@ lumpnum_t W_CheckNumForName(const char *name) } } +// Look for valid map data through all added files in descendant order. +// Get a map marker for WADs, and a standalone WAD file lump inside PK3s. +// TODO: Make it search through cache first, maybe...? +lumpnum_t W_CheckNumForMap(const char *name) +{ + UINT16 lumpNum, end; + UINT32 i; + for (i = numwadfiles - 1; i < numwadfiles; i--) + { + if (wadfiles[i]->type == RET_WAD) + { + for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++) + if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) + return (i<<16) + lumpNum; + } + else if (wadfiles[i]->type == RET_PK3) + { + lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0); + if (lumpNum != INT16_MAX) + end = W_CheckNumForFolderEndPK3("maps/", i, lumpNum); + else + continue; + // Now look for the specified map. + for (++lumpNum; lumpNum < end; lumpNum++) + if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) + return (i<<16) + lumpNum; + } + } + return LUMPERROR; +} + // // W_GetNumForName // @@ -671,15 +988,20 @@ lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, con // scan wad files backwards so patch lump files take precedence for (i = numwadfiles - 1; i >= 0; i--) { - bsid = W_CheckNumForNamePwad(blockstart,(UINT16)i,0); - if (bsid == INT16_MAX) - continue; // block doesn't exist, keep going - beid = W_CheckNumForNamePwad(blockend,(UINT16)i,0); - // if block end doesn't exist, just search through everything + if (wadfiles[i]->type == RET_WAD) + { + bsid = W_CheckNumForNamePwad(blockstart, (UINT16)i, 0); + if (bsid == INT16_MAX) + continue; // Start block doesn't exist? + beid = W_CheckNumForNamePwad(blockend, (UINT16)i, 0); + if (beid == INT16_MAX) + continue; // End block doesn't exist? + + check = W_CheckNumForNamePwad(name, (UINT16)i, bsid); + if (check < beid) + return (i<<16)+check; // found it, in our constraints + } - check = W_CheckNumForNamePwad(name,(UINT16)i,bsid); - if (check < beid) - return (i<<16)+check; // found it, in our constraints } return LUMPERROR; } @@ -716,80 +1038,35 @@ size_t W_LumpLength(lumpnum_t lumpnum) return W_LumpLengthPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } -/** Reads bytes from the head of a lump, without doing decompression. - * - * \param wad Wad number to read from. - * \param lump Lump number to read from, within wad. - * \param dest Buffer in memory to serve as destination. - * \param size Number of bytes to read. - * \param offest Number of bytes to offset. - * \return Number of bytes read (should equal size). - * \sa W_ReadLumpHeader - */ -static size_t W_RawReadLumpHeader(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset) +/* report a zlib or i/o error */ +void zerr(int ret) { - size_t bytesread; - lumpinfo_t *l; - FILE *handle; - - l = wadfiles[wad]->lumpinfo + lump; - - handle = wadfiles[wad]->handle; - - fseek(handle, (long)(l->position + offset), SEEK_SET); - bytesread = fread(dest, 1, size, handle); - - return bytesread; -} - -// Read a compressed lump; return it in newly Z_Malloc'd memory. -// wad is number of wad file, lump is number of lump in wad. -static void *W_ReadCompressedLump(UINT16 wad, UINT16 lump) -{ -#ifdef ZWAD - char *compressed, *data; - const lumpinfo_t *l = &wadfiles[wad]->lumpinfo[lump]; - size_t retval; - - compressed = Z_Malloc(l->disksize, PU_STATIC, NULL); - data = Z_Malloc(l->size, PU_STATIC, NULL); - if (W_RawReadLumpHeader(wad, lump, compressed, l->disksize, 0) - < l->disksize) - { - I_Error("wad %d, lump %d: cannot read compressed data", - wad, lump); - } - - retval = lzf_decompress(compressed, l->disksize, data, l->size); -#ifndef AVOID_ERRNO - if (retval == 0 && errno == E2BIG) - { - I_Error("wad %d, lump %d: compressed data too big " - "(bigger than %s)", wad, lump, sizeu1(l->size)); - } - else if (retval == 0 && errno == EINVAL) - I_Error("wad %d, lump %d: invalid compressed data", wad, lump); - else -#endif - if (retval != l->size) - { - I_Error("wad %d, lump %d: decompressed to wrong number of " - "bytes (expected %s, got %s)", wad, lump, - sizeu1(l->size), sizeu2(retval)); - } - Z_Free(compressed); - return data; -#else - (void)wad; - (void)lump; - //I_Error("ZWAD files not supported on this platform."); - return NULL; -#endif + CONS_Printf("zpipe: "); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + CONS_Printf("error reading stdin\n"); + if (ferror(stdout)) + CONS_Printf("error writing stdout\n"); + break; + case Z_STREAM_ERROR: + CONS_Printf("invalid compression level\n"); + break; + case Z_DATA_ERROR: + CONS_Printf("invalid or incomplete deflate data\n"); + break; + case Z_MEM_ERROR: + CONS_Printf("out of memory\n"); + break; + case Z_VERSION_ERROR: + CONS_Printf("zlib version mismatch!\n"); + } } /** Reads bytes from the head of a lump. * Note: If the lump is compressed, the whole thing has to be read anyway. * + * \param wad Wad number to read from. * \param lump Lump number to read from. * \param dest Buffer in memory to serve as destination. * \param size Number of bytes to read. @@ -800,6 +1077,8 @@ static void *W_ReadCompressedLump(UINT16 wad, UINT16 lump) size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset) { size_t lumpsize; + lumpinfo_t *l; + FILE *handle; if (!TestValidLump(wad,lump)) return 0; @@ -813,17 +1092,112 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si if (!size || size+offset > lumpsize) size = lumpsize - offset; - if (wadfiles[wad]->lumpinfo[lump].compressed) + // Let's get the raw lump data. + // We setup the desired file handle to read the lump data. + l = wadfiles[wad]->lumpinfo + lump; + handle = wadfiles[wad]->handle; + fseek(handle, (long)(l->position + offset), SEEK_SET); + + // But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account. + switch(wadfiles[wad]->lumpinfo[lump].compression) { - UINT8 *data; - data = W_ReadCompressedLump(wad, lump); - if (!data) return 0; - M_Memcpy(dest, data+offset, size); - Z_Free(data); - return size; + case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read. + return fread(dest, 1, size, handle); + case CM_LZF: // Is it LZF compressed? Used by ZWADs. + { +#ifdef ZWAD + char *rawData; // The lump's raw data. + char *decData; // Lump's decompressed real data. + size_t retval; // Helper var, lzf_decompress returns 0 when an error occurs. + + rawData = Z_Malloc(l->disksize, PU_STATIC, NULL); + decData = Z_Malloc(l->size, PU_STATIC, NULL); + + if (fread(rawData, 1, l->disksize, handle) < l->disksize) + I_Error("wad %d, lump %d: cannot read compressed data", wad, lump); + retval = lzf_decompress(rawData, l->disksize, decData, l->size); +#ifndef AVOID_ERRNO + if (retval == 0 && errno == E2BIG) // errno is a global var set by the lzf functions when something goes wrong. + { + I_Error("wad %d, lump %d: compressed data too big (bigger than %s)", wad, lump, sizeu1(l->size)); + } + else if (retval == 0 && errno == EINVAL) + I_Error("wad %d, lump %d: invalid compressed data", wad, lump); + else +#endif + if (retval != l->size) + { + I_Error("wad %d, lump %d: decompressed to wrong number of bytes (expected %s, got %s)", wad, lump, sizeu1(l->size), sizeu2(retval)); + } +#else + (void)wad; + (void)lump; + //I_Error("ZWAD files not supported on this platform."); + return NULL; +#endif + if (!decData) // Did we get no data at all? + return 0; + M_Memcpy(dest, decData + offset, size); + Z_Free(rawData); + Z_Free(decData); + return size; + } + case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support. + { + z_const Bytef *rawData; // The lump's raw data. + Bytef *decData; // Lump's decompressed real data. + + int zErr; // Helper var. + z_stream strm; + unsigned long rawSize = l->disksize; + unsigned long decSize = l->size; + + rawData = Z_Malloc(rawSize, PU_STATIC, NULL); + decData = Z_Malloc(decSize, PU_STATIC, NULL); + + if (fread(rawData, 1, rawSize, handle) < rawSize) + I_Error("wad %d, lump %d: cannot read compressed data", wad, lump); + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + strm.total_in = strm.avail_in = rawSize; + strm.total_out = strm.avail_out = decSize; + + strm.next_in = rawData; + strm.next_out = decData; + + zErr = inflateInit2(&strm, -15); + if (zErr == Z_OK) + { + zErr = inflate(&strm, Z_FINISH); + if (zErr == Z_STREAM_END) + { + M_Memcpy(dest, decData, size); + } + else + { + size = 0; + zerr(zErr); + (void)inflateEnd(&strm); + } + } + else + { + CONS_Printf("whopet\n"); + size = 0; + zerr(zErr); + } + + Z_Free(rawData); + Z_Free(decData); + + return size; + } + default: + I_Error("wad %d, lump %d: unsupported compression type!", wad, lump); } - else - return W_RawReadLumpHeader(wad, lump, dest, size, offset); } size_t W_ReadLumpHeader(lumpnum_t lumpnum, void *dest, size_t size, size_t offset) @@ -1107,12 +1481,12 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, if ((handle = W_OpenWadFile(&filename, false)) == NULL) return -1; - // detect dehacked file with the "soc" extension - if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0 + // detect wad file by the absence of the other supported extensions + if (stricmp(&filename[strlen(filename) - 4], ".soc") #ifdef HAVE_BLUA - && stricmp(&filename[strlen(filename) - 4], ".lua") != 0 + && stricmp(&filename[strlen(filename) - 4], ".lua") #endif - ) + && stricmp(&filename[strlen(filename) - 4], ".pk3")) { // assume wad file wadinfo_t header; diff --git a/src/w_wad.h b/src/w_wad.h index d3ce20e20..14bf4d85f 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -34,14 +34,33 @@ typedef struct UINT32 infotableofs; // the 'directory' of resources } wadinfo_t; +// a raw entry of the wad directory +typedef struct +{ + UINT32 filepos; // file offset of the resource + UINT32 size; // size of the resource + char name[8]; // name of the resource +} ATTRPACK filelump_t; + +// Available compression methods for lumps. +typedef enum +{ + CM_NOCOMPRESSION, + CM_DEFLATE, + CM_LZF, + CM_UNSUPPORTED +} compmethod; + // a memory entry of the wad directory typedef struct { unsigned long position; // filelump_t filepos unsigned long disksize; // filelump_t size char name[9]; // filelump_t name[] + char *name2; // Used by PK3s. Dynamically allocated name. size_t size; // real (uncompressed) size INT32 compressed; // i + compmethod compression; // lump compression method } lumpinfo_t; // ========================================================================= @@ -58,9 +77,13 @@ typedef struct #include "m_aatree.h" #endif +// Resource type of the WAD. Yeah, I know this sounds dumb, but I'll leave it like this until I clean up the code further. +enum restype {RET_WAD, RET_PK3}; + typedef struct wadfile_s { char *filename; + enum restype type; lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; #ifdef HWRENDER @@ -86,7 +109,7 @@ void W_Shutdown(void); // Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened FILE *W_OpenWadFile(const char **filename, boolean useerrors); // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error -UINT16 W_LoadWadFile(const char *filename); +UINT16 W_InitFile(const char *filename); // W_InitMultipleFiles returns 1 if all is okay, 0 otherwise, // so that it stops with a message if a file was not found, but not if all is okay. @@ -96,6 +119,12 @@ const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNum(lumpnum_t lumpnum); UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad + +UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump); +UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump); +UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump); + +lumpnum_t W_CheckNumForMap(const char *name); lumpnum_t W_CheckNumForName(const char *name); lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend); @@ -104,6 +133,8 @@ UINT8 W_LumpExists(const char *name); // Lua uses this. size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump); size_t W_LumpLength(lumpnum_t lumpnum); +void zerr(int ret); // zlib error checking + size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset); size_t W_ReadLumpHeader(lumpnum_t lump, void *dest, size_t size, size_t offest); // read all or a part of a lump void W_ReadLumpPwad(UINT16 wad, UINT16 lump, void *dest);