From 2bb16c684fb1b165996ff6cf4c93fcf80f4842a4 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 24 Apr 2017 15:57:30 +0300 Subject: [PATCH 1/6] Fixed crash caused by 0-length lines in UDMF When line was removed during processing bogus entries remained in sidedefs array --- src/p_udmf.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 81b1d0a904..7952d2a92e 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1934,10 +1934,17 @@ public: P_AdjustLine(&lines[line]); P_FinishLoadingLineDef(&lines[line], tempalpha[0]); } - assert((unsigned)side <= level.sides.Size()); - if ((unsigned)side > level.sides.Size()) + + const int sideDelta = level.sides.Size() - side; + assert(sideDelta >= 0); + + if (sideDelta < 0) { - Printf("Map had %d invalid side references\n", (int)level.sides.Size() - side); + Printf("Map had %d invalid side references\n", abs(sideDelta)); + } + else if (sideDelta > 0) + { + level.sides.Resize(side); } } From cc786bada63bf65dc60f214da3d5c9d7ca9ee449 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 25 Apr 2017 10:57:55 +0300 Subject: [PATCH 2/6] Fixed crash when mouse is moved right after saving of game has been triggered https://forum.zdoom.org/viewtopic.php?t=56060 https://forum.zdoom.org/viewtopic.php?t=49369&start=105#p992821 https://forum.drdteam.org/viewtopic.php?t=7607 --- wadsrc/static/zscript/menu/loadsavemenu.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index 7fe3543173..279024a58a 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -500,6 +500,24 @@ class SaveMenu : LoadSaveMenu // //============================================================================= + override bool MouseEvent(int type, int x, int y) + { + if (mSaveName.Length() > 0) + { + // Do not process events when saving is in progress to avoid update of the current index, + // i.e. Selected member variable must remain unchanged + return true; + } + + return Super.MouseEvent(type, x, y); + } + + //============================================================================= + // + // + // + //============================================================================= + override bool OnUIEvent(UIEvent ev) { if (ev.Type == UIEvent.Type_KeyDown) From 9375edda11ed079bfe18b866f0072eecd589df34 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Apr 2017 12:40:08 +0200 Subject: [PATCH 3/6] - removed p_buildmap.cpp. This code had been broken for years and inactive for several months. Since there is really little point fixing it it may just be removed entirely. --- src/CMakeLists.txt | 1 - src/p_buildmap.cpp | 855 --------------------------------------------- 2 files changed, 856 deletions(-) delete mode 100644 src/p_buildmap.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e5f758377..426089610c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -886,7 +886,6 @@ set (PCH_SOURCES p_3dmidtex.cpp p_acs.cpp p_actionfunctions.cpp - p_buildmap.cpp p_ceiling.cpp p_conversation.cpp p_doors.cpp diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp deleted file mode 100644 index 6949ce9373..0000000000 --- a/src/p_buildmap.cpp +++ /dev/null @@ -1,855 +0,0 @@ - -//************************************************************************** -//** -//** TEMPLATE.C -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include "p_local.h" -#include "m_swap.h" -#include "w_wad.h" -#include "templates.h" -#include "r_sky.h" -#include "r_defs.h" -#include "p_setup.h" -#include "g_level.h" -#include "r_data/colormaps.h" -#include "gi.h" -#include "p_spec.h" - -#if 0 -// MACROS ------------------------------------------------------------------ - -//#define SHADE2LIGHT(s) (160-2*(s)) -#define SHADE2LIGHT(s) (255-2*s) - -// TYPES ------------------------------------------------------------------- - -//ceilingstat/floorstat: -// bit 0: 1 = parallaxing, 0 = not "P" -// bit 1: 1 = groudraw, 0 = not -// bit 2: 1 = swap x&y, 0 = not "F" -// bit 3: 1 = double smooshiness "E" -// bit 4: 1 = x-flip "F" -// bit 5: 1 = y-flip "F" -// bit 6: 1 = Align texture to first wall of sector "R" -// bits 7-8: "T" -// 00 = normal floors -// 01 = masked floors -// 10 = transluscent masked floors -// 11 = reverse transluscent masked floors -// bits 9-15: reserved - - //40 bytes -struct sectortype -{ - int16_t wallptr, wallnum; - int32_t ceilingZ, floorZ; - int16_t ceilingstat, floorstat; - int16_t ceilingpicnum, ceilingheinum; - int8_t ceilingshade; - uint8_t ceilingpal, ceilingxpanning, ceilingypanning; - int16_t floorpicnum, floorheinum; - int8_t floorshade; - uint8_t floorpal, floorxpanning, floorypanning; - uint8_t visibility, filler; - int16_t lotag, hitag, extra; -}; - -//cstat: -// bit 0: 1 = Blocking wall (use with clipmove, getzrange) "B" -// bit 1: 1 = bottoms of invisible walls swapped, 0 = not "2" -// bit 2: 1 = align picture on bottom (for doors), 0 = top "O" -// bit 3: 1 = x-flipped, 0 = normal "F" -// bit 4: 1 = masking wall, 0 = not "M" -// bit 5: 1 = 1-way wall, 0 = not "1" -// bit 6: 1 = Blocking wall (use with hitscan / cliptype 1) "H" -// bit 7: 1 = Transluscence, 0 = not "T" -// bit 8: 1 = y-flipped, 0 = normal "F" -// bit 9: 1 = Transluscence reversing, 0 = normal "T" -// bits 10-15: reserved - - //32 bytes -struct walltype -{ - int32_t x, y; - int16_t point2, nextwall, nextsector, cstat; - int16_t picnum, overpicnum; - int8_t shade; - uint8_t pal, xrepeat, yrepeat, xpanning, ypanning; - int16_t lotag, hitag, extra; -}; - -//cstat: -// bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B" -// bit 1: 1 = transluscence, 0 = normal "T" -// bit 2: 1 = x-flipped, 0 = normal "F" -// bit 3: 1 = y-flipped, 0 = normal "F" -// bits 5-4: 00 = FACE sprite (default) "R" -// 01 = WALL sprite (like masked walls) -// 10 = FLOOR sprite (parallel to ceilings&floors) -// bit 6: 1 = 1-sided sprite, 0 = normal "1" -// bit 7: 1 = Real centered centering, 0 = foot center "C" -// bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1) "H" -// bit 9: 1 = Transluscence reversing, 0 = normal "T" -// bits 10-14: reserved -// bit 15: 1 = Invisible sprite, 0 = not invisible - - //44 bytes -struct spritetype -{ - int32_t x, y, z; - int16_t cstat, picnum; - int8_t shade; - uint8_t pal, clipdist, filler; - uint8_t xrepeat, yrepeat; - int8_t xoffset, yoffset; - int16_t sectnum, statnum; - int16_t ang, owner, xvel, yvel, zvel; - int16_t lotag, hitag, extra; -}; - -// I used to have all the Xobjects mapped out. Not anymore. -// (Thanks for the great firmware, Seagate!) -struct Xsprite -{ - uint8_t NotReallyPadding[16]; - uint16_t Data1; - uint16_t Data2; - uint16_t Data3; - uint16_t ThisIsntPaddingEither; - uint32_t NorThis:2; - uint32_t Data4:16; - uint32_t WhatIsThisIDontEven:14; - uint8_t ThisNeedsToBe56Bytes[28]; -}; - -struct SlopeWork -{ - walltype *wal; - walltype *wal2; - long dx, dy, i, x[3], y[3], z[3]; - long heinum; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -void P_AdjustLine (line_t *line); - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static bool P_LoadBloodMap (uint8_t *data, size_t len, FMapThing **sprites, int *numsprites); -static void LoadSectors (sectortype *bsectors, int count); -static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors); -static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings); -static vertex_t *FindVertex (int32_t x, int32_t y); -static void CreateStartSpot (int32_t *pos, FMapThing *start); -static void CalcPlane (SlopeWork &slope, secplane_t &plane); -static void Decrypt (void *to, const void *from, int len, int key); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -bool P_IsBuildMap(MapData *map) -{ - uint32_t len = map->Size(ML_LABEL); - if (len < 4) - { - return false; - } - uint8_t *data = new uint8_t[len]; - - map->Seek(ML_LABEL); - map->Read(ML_LABEL, data); - - // Check for a Blood map. - if (*(uint32_t *)data == MAKE_ID('B','L','M','\x1a')) - { - delete[] data; - return true; - } - - const int numsec = LittleShort(*(uint16_t *)(data + 20)); - int numwalls; - - if (len < 26 + numsec*sizeof(sectortype) || - (numwalls = LittleShort(*(uint16_t *)(data + 22 + numsec*sizeof(sectortype))), - len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) || - LittleLong(*(uint32_t *)data) != 7 || - LittleShort(*(uint16_t *)(data + 16)) >= 2048) - { // Can't possibly be a version 7 BUILD map - delete[] data; - return false; - } - delete[] data; - return true; -} - -//========================================================================== -// -// P_LoadBuildMap -// -//========================================================================== - -bool P_LoadBuildMap (uint8_t *data, size_t len, FMapThing **sprites, int *numspr) -{ - if (len < 26) - { - return false; - } - - // Check for a Blood map. - if (*(uint32_t *)data == MAKE_ID('B','L','M','\x1a')) - { - return P_LoadBloodMap (data, len, sprites, numspr); - } - - const int numsec = LittleShort(*(uint16_t *)(data + 20)); - int numwalls; - int numsprites; - - if (len < 26 + numsec*sizeof(sectortype) || - (numwalls = LittleShort(*(uint16_t *)(data + 22 + numsec*sizeof(sectortype))), - len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) || - LittleLong(*(uint32_t *)data) != 7 || - LittleShort(*(uint16_t *)(data + 16)) >= 2048) - { // Can't possibly be a version 7 BUILD map - return false; - } - - LoadSectors ((sectortype *)(data + 22), numsec); - LoadWalls ((walltype *)(data + 24 + numsec*sizeof(sectortype)), numwalls, - (sectortype *)(data + 22)); - - numsprites = *(uint16_t *)(data + 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)); - *sprites = new FMapThing[numsprites + 1]; - CreateStartSpot ((int32_t *)(data + 4), *sprites); - *numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)), - NULL, numsprites, (sectortype *)(data + 22), *sprites + 1); - - return true; -} - -//========================================================================== -// -// P_LoadBloodMap -// -//========================================================================== - -static bool P_LoadBloodMap (uint8_t *data, size_t len, FMapThing **mapthings, int *numspr) -{ - uint8_t infoBlock[37]; - int mapver = data[5]; - uint32_t matt; - int numRevisions, numWalls, numsprites, skyLen, visibility, parallaxType; - int i; - int k; - - if (mapver != 6 && mapver != 7) - { - return false; - } - - matt = *(uint32_t *)(data + 28); - if (matt != 0 && - matt != MAKE_ID('M','a','t','t') && - matt != MAKE_ID('t','t','a','M')) - { - Decrypt (infoBlock, data + 6, 37, 0x7474614d); - } - else - { - memcpy (infoBlock, data + 6, 37); - } - skyLen = 2 << LittleShort(*(uint16_t *)(infoBlock + 16)); - visibility = LittleLong(*(uint32_t *)(infoBlock + 18)); - parallaxType = infoBlock[26]; - numRevisions = LittleLong(*(uint32_t *)(infoBlock + 27)); - int numsectors = LittleShort(*(uint16_t *)(infoBlock + 31)); - numWalls = LittleShort(*(uint16_t *)(infoBlock + 33)); - numsprites = LittleShort(*(uint16_t *)(infoBlock + 35)); - Printf("Visibility: %d\n", visibility); - - if (mapver == 7) - { - // Version 7 has some extra stuff after the info block. This - // includes a copyright, and I have no idea what the rest of - // it is. - data += 171; - } - else - { - data += 43; - } - - // Skip the sky info. - data += skyLen; - - sectortype *bsec = new sectortype[numsectors]; - walltype *bwal = new walltype[numWalls]; - spritetype *bspr = new spritetype[numsprites]; - Xsprite *xspr = new Xsprite[numsprites]; - - // Read sectors - k = numRevisions * sizeof(sectortype); - for (i = 0; i < numsectors; ++i) - { - if (mapver == 7) - { - Decrypt (&bsec[i], data, sizeof(sectortype), k); - } - else - { - memcpy (&bsec[i], data, sizeof(sectortype)); - } - data += sizeof(sectortype); - if (bsec[i].extra > 0) // skip Xsector - { - data += 60; - } - } - - // Read walls - k |= 0x7474614d; - for (i = 0; i < numWalls; ++i) - { - if (mapver == 7) - { - Decrypt (&bwal[i], data, sizeof(walltype), k); - } - else - { - memcpy (&bwal[i], data, sizeof(walltype)); - } - data += sizeof(walltype); - if (bwal[i].extra > 0) // skip Xwall - { - data += 24; - } - } - - // Read sprites - k = (numRevisions * sizeof(spritetype)) | 0x7474614d; - for (i = 0; i < numsprites; ++i) - { - if (mapver == 7) - { - Decrypt (&bspr[i], data, sizeof(spritetype), k); - } - else - { - memcpy (&bspr[i], data, sizeof(spritetype)); - } - data += sizeof(spritetype); - if (bspr[i].extra > 0) // copy Xsprite - { - assert(sizeof(Xsprite) == 56); - memcpy(&xspr[i], data, sizeof(Xsprite)); - data += sizeof(Xsprite); - } - else - { - memset(&xspr[i], 0, sizeof(Xsprite)); - } - } - - // Now convert to Doom format, since we've extracted all the standard - // BUILD info from the map we need. (Sprites are ignored.) - LoadSectors (bsec, numsectors); - LoadWalls (bwal, numWalls, bsec); - *mapthings = new FMapThing[numsprites]; - *numspr = LoadSprites (bspr, xspr, numsprites, bsec, *mapthings); - - delete[] bsec; - delete[] bwal; - delete[] bspr; - delete[] xspr; - - return true; -} - -//========================================================================== -// -// LoadSectors -// -//========================================================================== - -static void LoadSectors (sectortype *bsec, int count) -{ - sector_t *sec; - char tnam[9]; - - level.sectors.Alloc(count); - sec = &level.sectors[0]; - memset (sec, 0, sizeof(sector_t)*count); - - sec->e = new extsector_t[count]; - - for (int i = 0; i < count; ++i, ++bsec, ++sec) - { - bsec->wallptr = uint16_t(bsec->wallptr); - bsec->wallnum = uint16_t(bsec->wallnum); - bsec->ceilingstat = uint16_t(bsec->ceilingstat); - bsec->floorstat = uint16_t(bsec->floorstat); - - sec->e = &sec->e[i]; - double floorheight = -LittleLong(bsec->floorZ) / 256.; - sec->SetPlaneTexZ(sector_t::floor, floorheight); - sec->floorplane.SetAtHeight(floorheight, sector_t::floor); - mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->floorpicnum)); - sec->SetTexture(sector_t::floor, TexMan.GetTexture (tnam, FTexture::TEX_Build)); - sec->SetXScale(sector_t::floor, (bsec->floorstat & 8) ? 2. : 1.); - sec->SetYScale(sector_t::floor, (bsec->floorstat & 8) ? 2. : 1.); - sec->SetXOffset(sector_t::floor, bsec->floorxpanning + 32.); - sec->SetYOffset(sector_t::floor, bsec->floorypanning + 0.); - sec->SetPlaneLight(sector_t::floor, SHADE2LIGHT (bsec->floorshade)); - sec->ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING); - - double ceilingheight = -LittleLong(bsec->ceilingZ) / 256.; - sec->SetPlaneTexZ(sector_t::ceiling, ceilingheight); - sec->ceilingplane.SetAtHeight(ceilingheight, sector_t::ceiling); - mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->ceilingpicnum)); - sec->SetTexture(sector_t::ceiling, TexMan.GetTexture (tnam, FTexture::TEX_Build)); - if (bsec->ceilingstat & 1) - { - sky1texture = sky2texture = sec->GetTexture(sector_t::ceiling); - sec->SetTexture(sector_t::ceiling, skyflatnum); - } - sec->SetXScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? 2. : 1.); - sec->SetYScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? 2. : 1.); - sec->SetXOffset(sector_t::ceiling, bsec->ceilingxpanning + 32.); - sec->SetYOffset(sector_t::ceiling, bsec->ceilingypanning + 0.); - sec->SetPlaneLight(sector_t::ceiling, SHADE2LIGHT (bsec->ceilingshade)); - sec->ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING); - - sec->lightlevel = (sec->GetPlaneLight(sector_t::floor) + sec->GetPlaneLight(sector_t::ceiling)) / 2; - - sec->seqType = -1; - sec->SeqName = NAME_None; - sec->nextsec = -1; - sec->prevsec = -1; - sec->gravity = 1.f; - sec->friction = ORIG_FRICTION; - sec->movefactor = ORIG_FRICTION_FACTOR; - sec->ColorMap = map; - sec->ZoneNumber = 0xFFFF; - sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; - - if (bsec->floorstat & 4) - { - sec->SetAngle(sector_t::floor, DAngle(90.)); - sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor)); - } - if (bsec->floorstat & 16) - { - sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor)); - } - if (bsec->floorstat & 32) - { - sec->SetYScale(sector_t::floor, -sec->GetYScale(sector_t::floor)); - } - - if (bsec->ceilingstat & 4) - { - sec->SetAngle(sector_t::ceiling, DAngle(90.)); - sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling)); - } - if (bsec->ceilingstat & 16) - { - sec->SetXScale(sector_t::ceiling, -sec->GetXScale(sector_t::ceiling)); - } - if (bsec->ceilingstat & 32) - { - sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling)); - } - } -} - -//========================================================================== -// -// LoadWalls -// -//========================================================================== - -static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) -{ - int i, j; - - // Setting numvertexes to the same as numwalls is overly conservative, - // but the extra vertices will be removed during the BSP building pass. - numsides = numvertexes = numwalls; - int numlines = 0; - - sides = new side_t[numsides]; - memset (sides, 0, numsides*sizeof(side_t)); - - vertexes = new vertex_t[numvertexes]; - numvertexes = 0; - - // First mark each sidedef with the sector it belongs to - for (unsigned i = 0; i < level.sectors.Size(); i++) - { - if (bsec[i].wallptr >= 0) - { - for (j = 0; j < bsec[i].wallnum; ++j) - { - sides[j + bsec[i].wallptr].sector = &level.sectors[i]; - } - } - } - - // Now copy wall properties to their matching sidedefs - for (i = 0; i < numwalls; ++i) - { - char tnam[9]; - FTextureID overpic, pic; - - mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].picnum)); - pic = TexMan.GetTexture (tnam, FTexture::TEX_Build); - mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].overpicnum)); - overpic = TexMan.GetTexture (tnam, FTexture::TEX_Build); - - walls[i].x = LittleLong(walls[i].x); - walls[i].y = LittleLong(walls[i].y); - walls[i].point2 = LittleShort(walls[i].point2); - walls[i].cstat = LittleShort(walls[i].cstat); - walls[i].nextwall = LittleShort(walls[i].nextwall); - walls[i].nextsector = LittleShort(walls[i].nextsector); - - sides[i].SetTextureXOffset((double)walls[i].xpanning); - sides[i].SetTextureYOffset((double)walls[i].ypanning); - - sides[i].SetTexture(side_t::top, pic); - sides[i].SetTexture(side_t::bottom, pic); - if (walls[i].nextsector < 0 || (walls[i].cstat & 32)) - { - sides[i].SetTexture(side_t::mid, pic); - } - else if (walls[i].cstat & 16) - { - sides[i].SetTexture(side_t::mid, overpic); - } - else - { - sides[i].SetTexture(side_t::mid, FNullTextureID()); - } - - sides[i].TexelLength = walls[i].xrepeat * 8; - sides[i].SetTextureYScale(walls[i].yrepeat / 8.); - sides[i].SetTextureXScale(1.); - sides[i].SetLight(SHADE2LIGHT(walls[i].shade)); - sides[i].Flags = WALLF_ABSLIGHTING; - sides[i].RightSide = walls[i].point2; - sides[walls[i].point2].LeftSide = i; - - if (walls[i].nextwall >= 0 && walls[i].nextwall <= i) - { - sides[i].linedef = sides[walls[i].nextwall].linedef; - } - else - { - sides[i].linedef = (line_t*)(intptr_t)(numlines++); - } - } - - // Set line properties that Doom doesn't store per-sidedef - level.lines.Alloc(numlines); - memset (&level.lines[0], 0, numlines*sizeof(line_t)); - - for (i = 0, j = -1; i < numwalls; ++i) - { - if (walls[i].nextwall >= 0 && walls[i].nextwall <= i) - { - continue; - } - - j = int(intptr_t(sides[i].linedef)); - auto &lines = level.lines; - lines[j].sidedef[0] = (side_t*)(intptr_t)i; - lines[j].sidedef[1] = (side_t*)(intptr_t)walls[i].nextwall; - lines[j].v1 = FindVertex (walls[i].x, walls[i].y); - lines[j].v2 = FindVertex (walls[walls[i].point2].x, walls[walls[i].point2].y); - lines[j].frontsector = sides[i].sector; - lines[j].flags |= ML_WRAP_MIDTEX; - if (walls[i].nextsector >= 0) - { - lines[j].backsector = &level.sectors[walls[i].nextsector]; - lines[j].flags |= ML_TWOSIDED; - } - else - { - lines[j].backsector = NULL; - } - P_AdjustLine (&lines[j]); - if (walls[i].cstat & 128) - { - if (walls[i].cstat & 512) - { - lines[j].alpha = 1/3.; - } - else - { - lines[j].alpha = 2/3.; - } - } - if (walls[i].cstat & 1) - { - lines[j].flags |= ML_BLOCKING; - } - if (walls[i].nextwall < 0) - { - if (walls[i].cstat & 4) - { - lines[j].flags |= ML_DONTPEGBOTTOM; - } - } - else - { - if (walls[i].cstat & 4) - { - lines[j].flags |= ML_DONTPEGTOP; - } - else - { - lines[j].flags |= ML_DONTPEGBOTTOM; - } - } - if (walls[i].cstat & 64) - { - lines[j].flags |= ML_BLOCKEVERYTHING; - } - } - - // Finish setting sector properties that depend on walls - for (auto &sec : level.sectors) - { - SlopeWork slope; - - slope.wal = &walls[bsec->wallptr]; - slope.wal2 = &walls[slope.wal->point2]; - slope.dx = slope.wal2->x - slope.wal->x; - slope.dy = slope.wal2->y - slope.wal->y; - slope.i = long (g_sqrt ((double)(slope.dx*slope.dx+slope.dy*slope.dy))) << 5; - if (slope.i == 0) - { - continue; - } - if ((bsec->floorstat & 2) && (bsec->floorheinum != 0)) - { // floor is sloped - slope.heinum = -LittleShort(bsec->floorheinum); - slope.z[0] = slope.z[1] = slope.z[2] = -bsec->floorZ; - CalcPlane (slope, sec.floorplane); - } - if ((bsec->ceilingstat & 2) && (bsec->ceilingheinum != 0)) - { // ceiling is sloped - slope.heinum = -LittleShort(bsec->ceilingheinum); - slope.z[0] = slope.z[1] = slope.z[2] = -bsec->ceilingZ; - CalcPlane (slope, sec.ceilingplane); - } - int linenum = sides[bsec->wallptr].linedef->Index(); - int sidenum = int(intptr_t(level.lines[linenum].sidedef[1] - sides)); - if (bsec->floorstat & 64) - { // floor is aligned to first wall - P_AlignFlat (linenum, sidenum == bsec->wallptr, 0); - } - if (bsec->ceilingstat & 64) - { // ceiling is aligned to first wall - P_AlignFlat (linenum, sidenum == bsec->wallptr, 0); - } - } - for (i = 0; i < numlines; i++) - { - intptr_t front = intptr_t(level.lines[i].sidedef[0]-sides); - intptr_t back = intptr_t(level.lines[i].sidedef[1]-sides); - lines[i].sidedef[0] = front >= 0 ? &sides[front] : NULL; - lines[i].sidedef[1] = back >= 0 ? &sides[back] : NULL; - } - for (i = 0; i < numsides; i++) - { - assert(sides[i].sector != NULL); - sides[i].linedef = &lines[intptr_t(sides[i].linedef)]; - } -} - -//========================================================================== -// -// LoadSprites -// -//========================================================================== - -static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, - sectortype *bsectors, FMapThing *mapthings) -{ - int count = 0; - - memset(mapthings, 0, sizeof(*mapthings)*numsprites); - - for (int i = 0; i < numsprites; ++i) - { - mapthings[count].thingid = 0; - mapthings[count].pos.X = sprites[i].x / 16.; - mapthings[count].pos.Y = -sprites[i].y / 16.; - mapthings[count].pos.Z = (bsectors[sprites[i].sectnum].floorZ - sprites[i].z) / 256.; - mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11; - mapthings[count].ClassFilter = 0xffff; - mapthings[count].SkillFilter = 0xffff; - mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH; - mapthings[count].special = 0; - mapthings[count].Gravity = 1.; - mapthings[count].RenderStyle = STYLE_Count; - mapthings[count].Alpha = -1; - mapthings[count].health = -1; - mapthings[count].FloatbobPhase = -1; - - if (xsprites != NULL && sprites[i].lotag == 710) - { // Blood ambient sound - mapthings[count].args[0] = xsprites[i].Data3; - // I am totally guessing about the volume level. 50 seems to be a pretty - // typical value for Blood's standard maps, so I assume it's 100-based. - mapthings[count].args[1] = xsprites[i].Data4; - mapthings[count].args[2] = xsprites[i].Data1; - mapthings[count].args[3] = xsprites[i].Data2; - mapthings[count].EdNum = 14065; - } - else if (xsprites != NULL && sprites[i].lotag == 1) - { // Blood player start - if (xsprites[i].Data1 < 4) - mapthings[count].EdNum= 1 + xsprites[i].Data1; - else - mapthings[count].EdNum = 4001 + xsprites[i].Data1 - 4; - } - else if (xsprites != NULL && sprites[i].lotag == 2) - { // Bloodbath start - mapthings[count].EdNum = 11; - } - else - { - if (sprites[i].cstat & 32768) continue; - if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue; - - mapthings[count].EdNum = 9988; - mapthings[count].args[0] = sprites[i].picnum; - mapthings[count].args[2] = sprites[i].xrepeat; - mapthings[count].args[3] = sprites[i].yrepeat; - mapthings[count].args[4] = sprites[i].cstat; - } - mapthings[count].info = DoomEdMap.CheckKey(mapthings[count].EdNum); - count++; - } - return count; -} - -//========================================================================== -// -// FindVertex -// -//========================================================================== - -vertex_t *FindVertex (int32_t xx, int32_t yy) -{ - int i; - - double x = xx / 64.; - double y = -yy / 64.; - - for (i = 0; i < numvertexes; ++i) - { - if (vertexes[i].fX() == x && vertexes[i].fY() == y) - { - return &vertexes[i]; - } - } - vertexes[i].set(x, y); - numvertexes++; - return &vertexes[i]; -} - -//========================================================================== -// -// CreateStartSpot -// -//========================================================================== - -static void CreateStartSpot (int32_t *pos, FMapThing *start) -{ - short angle = LittleShort(*(uint16_t *)(&pos[3])); - FMapThing mt = { 0, }; - - mt.pos.X = LittleLong(pos[0]) / 16.; - mt.pos.Y = -LittleLong(pos[1]) / 16.; - mt.angle = short(Scale((2048-angle)&2047, 360, 2048)); - mt.info = DoomEdMap.CheckKey(1); - mt.EdNum = 1; - mt.flags = 7|MTF_SINGLE|224; - - *start = mt; -} - -//========================================================================== -// -// CalcPlane -// -//========================================================================== - -static void CalcPlane (SlopeWork &slope, secplane_t &plane) -{ - DVector3 pt[3]; - long j; - - slope.x[0] = slope.wal->x; slope.y[0] = slope.wal->y; - slope.x[1] = slope.wal2->x; slope.y[1] = slope.wal2->y; - if (slope.dx == 0) - { - slope.x[2] = slope.x[0] + 64; - slope.y[2] = slope.y[0]; - } - else - { - slope.x[2] = slope.x[0]; - slope.y[2] = slope.y[0] + 64; - } - j = DMulScale3 (slope.dx, slope.y[2]-slope.wal->y, -slope.dy, slope.x[2]-slope.wal->x); - slope.z[2] += Scale (slope.heinum, j, slope.i); - - pt[0] = DVector3(slope.dx, -slope.dy, 0); - pt[1] = DVector3(slope.x[2] - slope.x[0], slope.y[0] - slope.y[2], (slope.z[2] - slope.z[0]) / 16); - pt[2] = (pt[0] ^ pt[1]).Unit(); - - if ((pt[2][2] < 0 && plane.fC() > 0) || (pt[2][2] > 0 && plane.fC() < 0)) - { - pt[2] = -pt[2]; - } - - double dist = -pt[2][0] * slope.x[0] * 16 + pt[2][1] * slope.y[0] * 16 - pt[2][2] * slope.z[0]; - plane.set(pt[2][0], pt[2][1], pt[2][2], dist); -} - -//========================================================================== -// -// Decrypt -// -// Note that this is different from the general RFF encryption. -// -//========================================================================== - -static void Decrypt (void *to_, const void *from_, int len, int key) -{ - uint8_t *to = (uint8_t *)to_; - const uint8_t *from = (const uint8_t *)from_; - - for (int i = 0; i < len; ++i, ++key) - { - to[i] = from[i] ^ key; - } -} - -#endif From 090502b2439fe8e1d5416a5c0d577433df02825b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Apr 2017 19:55:05 +0200 Subject: [PATCH 4/6] - moved the 'no player start' check to the end of G_DoLoadLevel because inside G_FinishTravel it would leave some data in undefined places that later can cause a crash. --- src/g_level.h | 2 +- src/p_udmf.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_level.h b/src/g_level.h index 6b4d1d8f24..d332a0093f 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -468,7 +468,7 @@ enum void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1); void G_StartTravel (); -void G_FinishTravel (); +int G_FinishTravel (); void G_DoLoadLevel (int position, bool autosave); diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 7952d2a92e..3b8c06132f 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -2073,6 +2073,7 @@ public: else if (sc.Compare("sector")) { sector_t sec; + memset(&sec, 0, sizeof(sector_t)); ParseSector(&sec, ParsedSectors.Size()); ParsedSectors.Push(sec); } From f866e0f02ff5f0506e5ad0c357b7cfe833fcaf5b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Apr 2017 21:05:36 +0200 Subject: [PATCH 5/6] - saved the wrong version. --- src/g_level.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index ad83a2a05b..4139362c35 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -86,6 +86,7 @@ #include "serializer.h" #include "vm.h" #include "events.h" +#include "dobjgc.h" #include "gi.h" @@ -1019,7 +1020,7 @@ void G_DoLoadLevel (int position, bool autosave) level.starttime = gametic; G_UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level. - G_FinishTravel (); + int pnumerr = G_FinishTravel (); // For each player, if they are viewing through a player, make sure it is themselves. for (int ii = 0; ii < MAXPLAYERS; ++ii) { @@ -1061,6 +1062,10 @@ void G_DoLoadLevel (int position, bool autosave) { DAutosaver GCCNOWARN *dummy = Create(); } + if (pnumerr > 0) + { + I_Error("no start for player %d found.", pnumerr); + } } @@ -1224,13 +1229,14 @@ void G_StartTravel () // //========================================================================== -void G_FinishTravel () +int G_FinishTravel () { TThinkerIterator it (STAT_TRAVELLING); APlayerPawn *pawn, *pawndup, *oldpawn, *next; AInventory *inv; FPlayerStart *start; int pnum; + int failnum = 0; // APlayerPawn* pawns[MAXPLAYERS]; @@ -1257,8 +1263,7 @@ void G_FinishTravel () else { // Could not find a start for this player at all. This really should never happen but if it does, let's better abort. - DThinker::DestroyThinkersInList(STAT_TRAVELLING); - I_Error ("No player %d start to travel to!\n", pnum + 1); + if (failnum == 0) failnum = pnum + 1; } } oldpawn = pawndup; @@ -1286,7 +1291,7 @@ void G_FinishTravel () pawn->Floorclip = pawndup->Floorclip; pawn->waterlevel = pawndup->waterlevel; } - else + else if (failnum == 0) // In the failure case this may run into some undefined data. { P_FindFloorCeiling(pawn); } @@ -1336,6 +1341,7 @@ void G_FinishTravel () // Since this list is excluded from regular thinker cleaning, anything that may survive through here // will endlessly multiply and severely break the following savegames or just simply crash on broken pointers. DThinker::DestroyThinkersInList(STAT_TRAVELLING); + return failnum; } //========================================================================== From 99579efd0dd7b7b2da8258344cf86161991345e9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 Apr 2017 21:30:11 +0200 Subject: [PATCH 6/6] - fixed a few issues with libmpg123 not correctly reporting the sound's length and issues with repeatedly rewinding the song. --- src/sound/i_soundinternal.h | 2 +- src/sound/mpg123_decoder.cpp | 43 ++++++++++++++------- src/sound/mpg123_decoder.h | 2 +- src/sound/musicformats/music_libsndfile.cpp | 35 ++++++++++++++--- src/sound/oalsound.cpp | 4 +- src/sound/sndfile_decoder.cpp | 2 +- src/sound/sndfile_decoder.h | 4 +- 7 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index aa91d73ae6..47d2b923e3 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -132,7 +132,7 @@ struct SoundDecoder virtual size_t read(char *buffer, size_t bytes) = 0; virtual TArray readAll(); - virtual bool seek(size_t ms_offset, bool ms) = 0; + virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) = 0; virtual size_t getSampleOffset() = 0; virtual size_t getSampleLength() { return 0; } diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index 6ea6a1370c..dccaa66004 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -190,23 +190,38 @@ size_t MPG123Decoder::read(char *buffer, size_t bytes) return amt; } -bool MPG123Decoder::seek(size_t ms_offset, bool ms) +bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart) { - int enc, channels; - long srate; + int enc, channels; + long srate; - if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) - { - size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; - if(mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) - { - Done = false; - return true; - } - } - return false; + if (!mayrestart || ms_offset > 0) + { + if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) + { + size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; + if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) + { + Done = false; + return true; + } + } + return false; + } + else + { + // Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly. + // offset is intentionally ignored here. + if (MPG123) + { + mpg123_close(MPG123); + mpg123_delete(MPG123); + MPG123 = 0; + } + Reader->Seek(0, SEEK_SET); + return open(Reader); + } } - size_t MPG123Decoder::getSampleOffset() { return mpg123_tell(MPG123); diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index fa20f0b3ce..02af11a165 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -21,7 +21,7 @@ struct MPG123Decoder : public SoundDecoder virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual size_t read(char *buffer, size_t bytes); - virtual bool seek(size_t ms_offset, bool ms); + virtual bool seek(size_t ms_offset, bool ms, bool mayrestart); virtual size_t getSampleOffset(); virtual size_t getSampleLength(); diff --git a/src/sound/musicformats/music_libsndfile.cpp b/src/sound/musicformats/music_libsndfile.cpp index fc159314f0..e8a6132789 100644 --- a/src/sound/musicformats/music_libsndfile.cpp +++ b/src/sound/musicformats/music_libsndfile.cpp @@ -326,16 +326,39 @@ bool SndFileSong::Read(SoundStream *stream, void *vbuff, int ilen, void *userdat } else { + // This looks a bit more complicated than necessary because libmpg123 will not read the full requested length for the last block in the file. if (currentpos + framestoread > song->Loop_End) { size_t endblock = (song->Loop_End - currentpos) * song->Channels * 2; - err = (song->Decoder->read(buff, endblock) != endblock); - buff = buff + endblock; - len -= endblock; - song->Decoder->seek(song->Loop_Start, false); + size_t endlen = song->Decoder->read(buff, endblock); + if (endlen != 0) + { + buff = buff + endblock; + len -= endblock; + song->Decoder->seek(song->Loop_Start, false, true); + } + else + { + song->CritSec.Leave(); + return false; + } + } + while (len > 0) + { + size_t readlen = song->Decoder->read(buff, len); + if (readlen == 0) + { + song->CritSec.Leave(); + return false; + } + buff += readlen; + len -= readlen; + if (len > 0) + { + song->Decoder->seek(song->Loop_Start, false, true); + } } - err |= song->Decoder->read(buff, len) != len; } song->CritSec.Leave(); - return !err; + return true; } diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 946fba2b57..d9b53b0d58 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -215,7 +215,7 @@ class OpenALSoundStream : public SoundStream size_t got = self->Decoder->read((char*)ptr, length); if(got < (unsigned int)length) { - if(!self->Looping || !self->Decoder->seek(0, false)) + if(!self->Looping || !self->Decoder->seek(0, false, true)) return false; got += self->Decoder->read((char*)ptr+got, length-got); } @@ -364,7 +364,7 @@ public: virtual bool SetPosition(unsigned int ms_pos) { std::unique_lock lock(Renderer->StreamLock); - if(!Decoder->seek(ms_pos, true)) + if(!Decoder->seek(ms_pos, true, false)) return false; if(!Playing.load()) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index fe808c983b..b403b46ed9 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -190,7 +190,7 @@ TArray SndFileDecoder::readAll() return output; } -bool SndFileDecoder::seek(size_t ms_offset, bool ms) +bool SndFileDecoder::seek(size_t ms_offset, bool ms, bool /*mayrestart*/) { size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * SndInfo.samplerate) : ms_offset; if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0) diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h index e5473dcb22..53fa6e6a9e 100644 --- a/src/sound/sndfile_decoder.h +++ b/src/sound/sndfile_decoder.h @@ -17,8 +17,8 @@ struct SndFileDecoder : public SoundDecoder virtual size_t read(char *buffer, size_t bytes); virtual TArray readAll(); - virtual bool seek(size_t ms_offset, bool ms); - virtual size_t getSampleOffset(); + virtual bool seek(size_t ms_offset, bool ms, bool mayrestart); + virtual size_t getSampleOffset(); virtual size_t getSampleLength(); SndFileDecoder() : SndFile(0) { }