diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3a7c5499..213dafd1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3005,7 +3005,7 @@ static void Command_Addfile(void) // Add file on your client directly if it is trivial, or you aren't in a netgame. if (!(netgame || multiplayer) || musiconly) { - P_AddWadFile(fn, NULL); + P_AddWadFile(fn); return; } @@ -3237,7 +3237,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) ncs = findfile(filename,md5sum,true); - if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL)) + if (ncs != FS_FOUND || !P_AddWadFile(filename)) { Command_ExitGame_f(); if (ncs == FS_FOUND) diff --git a/src/d_netfil.c b/src/d_netfil.c index adbc8d77..284b9169 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -444,7 +444,7 @@ void CL_LoadServerFiles(void) continue; // Already loaded else if (fileneeded[i].status == FS_FOUND) { - P_AddWadFile(fileneeded[i].filename, NULL); + P_AddWadFile(fileneeded[i].filename); G_SetGameModified(true); fileneeded[i].status = FS_OPEN; } @@ -463,7 +463,7 @@ void CL_LoadServerFiles(void) fileneeded[i].filename); // Okay, NOW we know it's safe. Whew. - P_AddWadFile(fileneeded[i].filename, NULL); + P_AddWadFile(fileneeded[i].filename); if (fileneeded[i].important) G_SetGameModified(true); fileneeded[i].status = FS_OPEN; diff --git a/src/lua_script.c b/src/lua_script.c index 9b87f0c2..6564f258 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -170,6 +170,7 @@ static inline void LUA_LoadFile(MYFILE *f, char *name) LUA_ClearState(); lua_pushinteger(gL, f->wad); lua_setfield(gL, LUA_REGISTRYINDEX, "WAD"); + if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, 0, 0)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); lua_pop(gL,1); @@ -182,21 +183,24 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) { MYFILE f; char *name; - size_t len; f.wad = wad; f.size = W_LumpLengthPwad(wad, lump); f.data = Z_Malloc(f.size, PU_LUA, NULL); W_ReadLumpPwad(wad, lump, f.data); f.curpos = f.data; - len = strlen(wadfiles[wad]->filename); - name = malloc(len+10); - strcpy(name, wadfiles[wad]->filename); - if (!fasticmp(&name[len - 4], ".lua")) { - // If it's not a .lua file, copy the lump name in too. - name[len] = '|'; - M_Memcpy(name+len+1, wadfiles[wad]->lumpinfo[lump].name, 8); - name[len+9] = '\0'; + if (wadfiles[wad]->type == RET_LUA) + { + name = malloc(strlen(wadfiles[wad]->filename)+1); + strcpy(name, wadfiles[wad]->filename); + } + else // If it's not a .lua file, copy the lump name in too. + { + lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump]; + size_t length = strlen(wadfiles[wad]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + name = malloc(length + 1); + sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2); + name[length] = '\0'; } LUA_LoadFile(&f, name); diff --git a/src/p_saveg.c b/src/p_saveg.c index 17d28302..aa0f6af2 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -489,16 +489,34 @@ static void P_NetArchiveWorld(void) UINT8 *put; // reload the map just to see difference - const mapsector_t *ms; - const mapsidedef_t *msd; - const maplinedef_t *mld; + mapsector_t *ms; + mapsidedef_t *msd; + maplinedef_t *mld; const sector_t *ss = sectors; UINT8 diff, diff2; WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); put = save_p; - ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE); + if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 + { // HACK: Open wad file rather quickly so we can get the data from the relevant lumps + UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); + filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); +#define retrieve_mapdata(d, f)\ + d = Z_Malloc((f)->size, PU_CACHE, NULL); \ + M_Memcpy(d, wadData + (f)->filepos, (f)->size) + retrieve_mapdata(ms, fileinfo + ML_SECTORS); + retrieve_mapdata(mld, fileinfo + ML_LINEDEFS); + retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS); +#undef retrieve_mapdata + Z_Free(wadData); // we're done with this now + } + else // phew it's just a WAD + { + ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE); + mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE); + msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE); + } for (i = 0; i < numsectors; i++, ss++, ms++) { diff --git a/src/p_setup.c b/src/p_setup.c index 9f3ff423..931a5b84 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -348,16 +348,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 @@ -365,9 +362,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; @@ -377,11 +371,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; @@ -504,7 +503,12 @@ static inline void P_LoadSubsectors(lumpnum_t lumpnum) #endif ss->validcount = 0; } +} +static void P_LoadSubsectors(lumpnum_t lumpnum) +{ + UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); + P_LoadRawSubsectors(data, W_LumpLength(lumpnum)); Z_Free(data); } @@ -638,29 +642,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++) @@ -668,9 +674,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); @@ -735,8 +738,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); @@ -748,22 +749,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; @@ -781,7 +786,12 @@ static void P_LoadNodes(lumpnum_t lumpnum) no->bbox[j][k] = SHORT(mn->bbox[j][k])<slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; - else if (FixedDiv(ld->dy, ld->dx) > 0) + else if ((ld->dy > 0) == (ld->dx > 0)) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; @@ -1217,7 +1224,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum) if (ld->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)); } } } @@ -1232,14 +1239,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) @@ -1251,7 +1258,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); } @@ -1353,22 +1365,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; @@ -1386,7 +1400,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]; @@ -1528,6 +1542,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) sd->text[6] = 0; break; } + + case 4: // Speed pad parameters case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; @@ -1541,6 +1557,9 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) break; } + case 9: // Mace parameters + case 14: // Bustable block parameters + case 15: // Fan particle spawner parameters case 425: // Calls P_SetMobjState on calling mobj case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors @@ -1595,11 +1614,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]; @@ -1855,6 +1881,30 @@ static void P_CreateBlockMap(void) } } +// Split from P_LoadBlockMap for convenience +// -- Monster Iestyn 08/01/18 +static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count) +{ + size_t i; + blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL); + + // killough 3/1/98: Expand wad blockmap into larger internal one, + // by treating all offsets except -1 as unsigned and zero-extending + // them. This potentially doubles the size of blockmaps allowed, + // because Doom originally considered the offsets as always signed. + + blockmaplump[0] = SHORT(wadblockmaplump[0]); + blockmaplump[1] = SHORT(wadblockmaplump[1]); + blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff; + blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff; + + for (i = 4; i < count; i++) + { + INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98 + blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff; + } +} + // // P_LoadBlockMap // @@ -1881,38 +1931,20 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum) return false; { - size_t i; INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL); - - if (wadblockmaplump) W_ReadLump(lumpnum, wadblockmaplump); - else return false; + if (!wadblockmaplump) + return false; + W_ReadLump(lumpnum, wadblockmaplump); count /= 2; - blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, 0); - - // killough 3/1/98: Expand wad blockmap into larger internal one, - // by treating all offsets except -1 as unsigned and zero-extending - // them. This potentially doubles the size of blockmaps allowed, - // because Doom originally considered the offsets as always signed. - - blockmaplump[0] = SHORT(wadblockmaplump[0]); - blockmaplump[1] = SHORT(wadblockmaplump[1]); - blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff; - blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff; - - for (i = 4; i < count; i++) - { - INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98 - blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff; - } - + P_ReadBlockMapLump(wadblockmaplump, count); free(wadblockmaplump); - - bmaporgx = blockmaplump[0]<= 0x20000) + return false; + + CONS_Printf("Reading blockmap lump for pk3...\n"); + + // no need to malloc anything, assume the data is uncompressed for now + count /= 2; + P_ReadBlockMapLump((INT16 *)data, count); + + bmaporgx = blockmaplump[0]<infotableofs); + fileinfo += ML_THINGS; // we only need the THINGS lump + P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size); + Z_Free(wadData); // we're done with this now + } + else // phew it's just a WAD + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); P_LoadThings(); P_SpawnSecretItems(true); @@ -2688,7 +2800,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(); @@ -2698,38 +2815,93 @@ boolean P_SetupLevel(boolean skipprecip) P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); - // note: most of this ordering is important - loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); + // 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. + if (W_IsLumpWad(lastloadedmaplumpnum)) + { + // 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); + UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps; - P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); - P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); + if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded + { + I_Error("Bad WAD file for map %s!\n", maplumpname); + } - P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); + if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least + { + loadedbm = P_LoadRawBlockMap( + wadData + (fileinfo + ML_BLOCKMAP)->filepos, + (fileinfo + ML_BLOCKMAP)->size, + (fileinfo + ML_BLOCKMAP)->name); + } + 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); + if (numlumps > ML_REJECT) // enough room for a REJECT lump at least + { + P_LoadRawReject( + wadData + (fileinfo + ML_REJECT)->filepos, + (fileinfo + ML_REJECT)->size, + (fileinfo + ML_REJECT)->name); + } - 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 + P_LoadLineDefs2(); + P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; - 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; + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; + P_MapStart(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; + 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); - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = NULL; + // Important: take care of the ordering of the next functions. + if (!loadedbm) + P_CreateBlockMap(); // Graue 02-29-2004 - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; + P_LoadLineDefs2(); + P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; - P_MapStart(); - - 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; + P_MapStart(); + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + } #ifdef ESLOPE P_ResetDynamicSlopes(); @@ -2977,7 +3149,7 @@ boolean P_RunSOC(const char *socfilename) lumpnum_t lump; if (strstr(socfilename, ".soc") != NULL) - return P_AddWadFile(socfilename, NULL); + return P_AddWadFile(socfilename); lump = W_CheckNumForName(socfilename); if (lump == LUMPERROR) @@ -2993,17 +3165,17 @@ boolean P_RunSOC(const char *socfilename) // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps // -boolean P_AddWadFile(const char *wadfilename, char **firstmapname) +boolean P_AddWadFile(const char *wadfilename) { size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; UINT16 numlumps, wadnum; - INT16 firstmapreplaced = 0, num; char *name; lumpinfo_t *lumpinfo; boolean texturechange = false; + boolean mapsadded = false; boolean replacedcurrentmap = false; - if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX) + if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX) { CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); return false; @@ -3059,6 +3231,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 // @@ -3093,10 +3266,10 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) for (i = 0; i < numlumps; i++, lumpinfo++) { name = lumpinfo->name; - num = firstmapreplaced; if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers { + INT16 num; if (name[5]!='\0') continue; num = (INT16)M_MapNumber(name[3], name[4]); @@ -3106,16 +3279,10 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) replacedcurrentmap = true; CONS_Printf("%s\n", name); - } - - if (num && (num < firstmapreplaced || !firstmapreplaced)) - { - firstmapreplaced = num; - if (firstmapname) - *firstmapname = name; + mapsadded = true; } } - if (!firstmapreplaced) + if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); // reload status bar (warning should have valid player!) diff --git a/src/p_setup.h b/src/p_setup.h index 3bca1104..da25ee26 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -59,7 +59,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_LoadThingsOnly(void); boolean P_SetupLevel(boolean skipprecip); -boolean P_AddWadFile(const char *wadfilename, char **firstmapname); +boolean P_AddWadFile(const char *wadfilename); #ifdef DELFILE boolean P_DelWadFile(void); #endif diff --git a/src/r_data.c b/src/r_data.c index f2c9b146..fb7eb975 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -365,8 +365,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 @@ -404,13 +404,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 @@ -447,12 +456,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; @@ -817,7 +839,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; @@ -828,11 +850,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); @@ -864,7 +886,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; @@ -877,11 +899,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); @@ -968,12 +990,51 @@ 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. 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--) + { + switch (wadfiles[i]->type) + { + case RET_WAD: + if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) + { + if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) + continue; + else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) + continue; + } + else + if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX) + continue; + break; + case RET_PK3: + if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) + continue; + if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) + continue; + break; + default: + 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)) diff --git a/src/r_things.c b/src/r_things.c index ee2d8a9b..305d6b82 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -327,21 +327,28 @@ 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) + switch (wadfiles[wadnum]->type) + { + case RET_WAD: + 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 + end = W_CheckNumForNamePwad("S_END",wadnum,start); + if (end == INT16_MAX) + end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib. + break; + case RET_PK3: + start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0); + end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start); + break; + default: + return; + } - 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 - - 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); diff --git a/src/w_wad.c b/src/w_wad.c index 3789eab5..977b7e6f 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -26,6 +26,8 @@ #include "lzf.h" #endif +#include "zlib.h" + #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" @@ -67,14 +69,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 @@ -116,6 +110,8 @@ void W_Shutdown(void) Z_Free(wadfiles[numwadfiles]->lumpinfo); Z_Free(wadfiles[numwadfiles]->filename); Z_Free(wadfiles[numwadfiles]); + while (wadfiles[numwadfiles]->numlumps--) + Z_Free(wadfiles[numwadfiles]->lumpinfo[wadfiles[numwadfiles]->numlumps].name2); } } @@ -174,6 +170,28 @@ 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) + { + posStart++; + posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); + for (; posStart < posEnd; posStart++) + LUA_LoadLump(wadnum, posStart); + } + posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); + if (posStart != INT16_MAX) + { + posStart++; + posEnd = W_CheckNumForFolderEndPK3("SOC/", 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) { @@ -291,12 +309,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 = 0; @@ -339,12 +358,34 @@ UINT16 W_LoadWadFile(const char *filename) return INT16_MAX; } +#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); + if (handle) + fclose(handle); + 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_SOC; + numlumps = 1; lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); lumpinfo->position = 0; @@ -352,6 +393,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 @@ -360,6 +405,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_LUA; + numlumps = 1; lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); lumpinfo->position = 0; @@ -367,16 +414,206 @@ 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, "OBJCTCFG"); + 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) { @@ -437,44 +674,29 @@ 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); - if (handle) - fclose(handle); - return INT16_MAX; - } - } -#endif - // // link wad file to search files // @@ -485,6 +707,7 @@ UINT16 W_LoadWadFile(const char *filename) wadfile->lumpinfo = lumpinfo; fseek(handle, 0, SEEK_END); wadfile->filesize = (unsigned)ftell(handle); + wadfile->type = type; // already generated, just copy it over M_Memcpy(&wadfile->md5sum, &md5sum, 16); @@ -505,10 +728,30 @@ 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. + switch (wadfile->type) + { + case RET_WAD: + W_LoadDehackedLumps(numwadfiles - 1); + break; + case RET_PK3: + W_LoadDehackedLumpsPK3(numwadfiles - 1); + break; + case RET_SOC: + CONS_Printf(M_GetText("Loading SOC from %s\n"), wadfile->filename); + DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0); + break; + case RET_LUA: + LUA_LoadLump(numwadfiles - 1, 0); + break; + default: + break; + } W_InvalidateLumpnumCache(); + CONS_Printf("Ended function.\n"); return wadfile->numlumps; } @@ -566,7 +809,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) @@ -644,6 +887,51 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) 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. @@ -684,6 +972,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 // @@ -714,15 +1033,19 @@ 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; } @@ -759,6 +1082,24 @@ size_t W_LumpLength(lumpnum_t lumpnum) return W_LumpLengthPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } +// +// W_IsLumpWad +// Is the lump a WAD? (presumably in a PK3) +// +boolean W_IsLumpWad(lumpnum_t lumpnum) +{ + if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) + { + const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->name2; + + if (strlen(lumpfullName) < 4) + return false; // can't possibly be a WAD can it? + return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4); + } + + return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned +} + /** Reads bytes from the head of a lump, without doing decompression. * * \param wad Wad number to read from. @@ -785,54 +1126,35 @@ static size_t W_RawReadLumpHeader(UINT16 wad, UINT16 lump, void *dest, size_t si 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) +/* report a zlib or i/o error */ +void zerr(int ret) { -#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. @@ -843,6 +1165,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; @@ -856,17 +1180,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) @@ -1150,12 +1569,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 0e62cc9b..b84a5634 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -22,6 +22,15 @@ #pragma interface #endif +// a raw entry of the wad directory +// NOTE: This sits here and not in w_wad.c because p_setup.c makes use of it to load map WADs inside PK3s. +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; + // ============================================================== // WAD FILE STRUCTURE DEFINITIONS // ============================================================== @@ -34,14 +43,25 @@ typedef struct UINT32 infotableofs; // the 'directory' of resources } wadinfo_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 +78,19 @@ 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. +typedef enum restype +{ + RET_WAD, + RET_SOC, + RET_LUA, + RET_PK3 +} restype_t; + typedef struct wadfile_s { char *filename; + enum restype type; lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; #ifdef HWRENDER @@ -85,7 +115,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); #ifdef DELFILE void W_UnloadWadFile(UINT16 num); #endif @@ -98,6 +128,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); @@ -106,6 +142,10 @@ UINT8 W_LumpExists(const char *name); // Lua uses this. size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump); size_t W_LumpLength(lumpnum_t lumpnum); +boolean W_IsLumpWad(lumpnum_t lumpnum); // for loading maps from WADs in PK3s + +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);