From 3634a1435de144d2a0ad1ec125072a4d45096054 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 16 Nov 2023 20:12:14 -0500 Subject: [PATCH 1/6] NETallowJoining: Add session bans for more cases --- lib/netplay/netplay.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/netplay/netplay.cpp b/lib/netplay/netplay.cpp index b7a4e541c30..39ec54e2bde 100644 --- a/lib/netplay/netplay.cpp +++ b/lib/netplay/netplay.cpp @@ -4117,6 +4117,7 @@ static void NETallowJoining() NETflush(); NETpop(NETnetTmpQueue(i)); + NETaddSessionBanBadIP(tmp_connectState[i].ip); NETcloseTempSocket(i); sync_counter.cantjoin++; } @@ -4158,6 +4159,7 @@ static void NETallowJoining() NETflush(); NETpop(NETnetTmpQueue(i)); + NETaddSessionBanBadIP(tmp_connectState[i].ip); NETcloseTempSocket(i); sync_counter.cantjoin++; continue; From 8e00372e3e535325189115717f595050295de620 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:05:46 -0500 Subject: [PATCH 2/6] netplay.cpp: Additional cleanup --- lib/netplay/netplay.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/netplay/netplay.cpp b/lib/netplay/netplay.cpp index 39ec54e2bde..145274ebd39 100644 --- a/lib/netplay/netplay.cpp +++ b/lib/netplay/netplay.cpp @@ -4833,6 +4833,7 @@ bool NETjoinGame(const char *host, uint32_t port, const char *playername, const if (bsocket == nullptr) { + NETclose(); return false; // Connection dropped while sending NET_JOIN. } socketFlush(bsocket, NetPlay.hostPlayer); // Make sure the message was completely sent. @@ -4848,11 +4849,13 @@ bool NETjoinGame(const char *host, uint32_t port, const char *playername, const if ((unsigned)wzGetTicks() > i + 5000) { // timeout + NETclose(); return false; } if (bsocket == nullptr) { + NETclose(); return false; // Connection dropped. } @@ -4878,6 +4881,7 @@ bool NETjoinGame(const char *host, uint32_t port, const char *playername, const if (NetPlay.hostPlayer >= MAX_CONNECTED_PLAYERS) { debug(LOG_ERROR, "Bad host player number (%" PRIu32 ") received from host!", NetPlay.hostPlayer); + NETclose(); return false; } @@ -4895,6 +4899,7 @@ bool NETjoinGame(const char *host, uint32_t port, const char *playername, const if (index >= MAX_CONNECTED_PLAYERS) { debug(LOG_ERROR, "Bad player number (%u) received from host!", index); + NETclose(); return false; } From 4ac58c1f34c4ab4ba0a37d51c63c093465a8ba8a Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:19:40 -0500 Subject: [PATCH 3/6] Fix: Mod hashing issue (zero-initialize Sha256) --- lib/framework/crc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/framework/crc.h b/lib/framework/crc.h index 45c2c96d921..192a6456dc2 100644 --- a/lib/framework/crc.h +++ b/lib/framework/crc.h @@ -43,7 +43,7 @@ struct Sha256 std::string toString() const; void fromString(std::string const &s); - uint8_t bytes[Bytes]; + uint8_t bytes[Bytes] = {0}; }; Sha256 sha256Sum(void const *data, size_t dataLen); template <> From c5b2c0c9e576ac52ce26ed0d1bd72fe0cd958b66 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:57:23 -0500 Subject: [PATCH 4/6] mission.cpp: Add const --- src/mission.cpp | 26 +++++++++++++------------- src/mission.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mission.cpp b/src/mission.cpp index 4acb04c6a0a..5e491658c5c 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -146,12 +146,12 @@ static UBYTE bPlayCountDown; //FUNCTIONS************** static void addLandingLights(UDWORD x, UDWORD y); -static bool startMissionOffClear(char *pGame); -static bool startMissionOffKeep(char *pGame); -static bool startMissionCampaignStart(char *pGame); -static bool startMissionCampaignChange(char *pGame); -static bool startMissionCampaignExpand(char *pGame); -static bool startMissionCampaignExpandLimbo(char *pGame); +static bool startMissionOffClear(const char *pGame); +static bool startMissionOffKeep(const char *pGame); +static bool startMissionCampaignStart(const char *pGame); +static bool startMissionCampaignChange(const char *pGame); +static bool startMissionCampaignExpand(const char *pGame); +static bool startMissionCampaignExpandLimbo(const char *pGame); static bool startMissionBetween(); static void endMissionCamChange(); static void endMissionOffClear(); @@ -376,7 +376,7 @@ void setMissionCountDown() } -bool startMission(LEVEL_TYPE missionType, char *pGame) +bool startMission(LEVEL_TYPE missionType, const char *pGame) { bool loaded = true; @@ -1103,7 +1103,7 @@ void saveCampaignData() //start an off world mission - clearing the object lists -bool startMissionOffClear(char *pGame) +bool startMissionOffClear(const char *pGame) { debug(LOG_SAVE, "called for %s", pGame); @@ -1124,7 +1124,7 @@ bool startMissionOffClear(char *pGame) } //start an off world mission - keeping the object lists -bool startMissionOffKeep(char *pGame) +bool startMissionOffKeep(const char *pGame) { debug(LOG_SAVE, "called for %s", pGame); saveMissionData(); @@ -1143,7 +1143,7 @@ bool startMissionOffKeep(char *pGame) return true; } -bool startMissionCampaignStart(char *pGame) +bool startMissionCampaignStart(const char *pGame) { debug(LOG_SAVE, "called for %s", pGame); @@ -1164,7 +1164,7 @@ bool startMissionCampaignStart(char *pGame) return true; } -bool startMissionCampaignChange(char *pGame) +bool startMissionCampaignChange(const char *pGame) { // Clear out all intelligence screen messages freeMessages(); @@ -1191,7 +1191,7 @@ bool startMissionCampaignChange(char *pGame) return true; } -bool startMissionCampaignExpand(char *pGame) +bool startMissionCampaignExpand(const char *pGame) { //load in the new game details if (!loadGame(pGame, KEEPOBJECTS, !FREEMEM, false)) @@ -1203,7 +1203,7 @@ bool startMissionCampaignExpand(char *pGame) return true; } -bool startMissionCampaignExpandLimbo(char *pGame) +bool startMissionCampaignExpandLimbo(const char *pGame) { saveMissionLimboData(); diff --git a/src/mission.h b/src/mission.h index b3889b25abc..e211dd0fc58 100644 --- a/src/mission.h +++ b/src/mission.h @@ -53,7 +53,7 @@ void releaseMission(); /** On the PC - sets the countdown played flag. */ void setMissionCountDown(); -bool startMission(LEVEL_TYPE missionType, char *pGame); +bool startMission(LEVEL_TYPE missionType, const char *pGame); void endMission(); /** Initialise the mission stuff for a save game. */ From 973fb88c51cf4f5baee50067519d2f9b50f2c058 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:58:44 -0500 Subject: [PATCH 5/6] Use new/delete for LEVEL_DATASET --- src/game.cpp | 2 +- src/levels.cpp | 188 +++++++++++++++++++++++----------------------- src/levels.h | 26 ++++--- src/map.h | 2 +- src/multiint.cpp | 41 +++++----- src/multimenu.cpp | 4 +- src/multiopt.cpp | 2 +- src/multiplay.cpp | 2 +- 8 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 2766647ace7..ff4b0a2fb4f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -7168,7 +7168,7 @@ bool loadTerrainTypeMap(const char *pFilePath) } // Maps built into the game with custom tile types need to be excluded for overrides. -bool shouldLoadTerrainTypeOverrides(const char* name) +bool shouldLoadTerrainTypeOverrides(const std::string& name) { std::vector excludedMaps = {"Monocot"}; diff --git a/src/levels.cpp b/src/levels.cpp index 4fbec9d30f4..cf00b43c9cf 100644 --- a/src/levels.cpp +++ b/src/levels.cpp @@ -77,7 +77,7 @@ static LEVEL_DATASET *psBaseData = nullptr; static LEVEL_DATASET *psCurrLevel = nullptr; // dummy level data for single WRF loads -static LEVEL_DATASET sSingleWRF = { LEVEL_TYPE::LDS_COMPLETE, 0, 0, nullptr, mod_clean, {nullptr}, nullptr, nullptr, nullptr, {{0}}, nullptr}; +static LEVEL_DATASET sSingleWRF = LEVEL_DATASET(); // return values from the lexer char *pLevToken; @@ -98,6 +98,31 @@ enum LEVELPARSER_STATE LP_GAME, // game token received }; +void LEVEL_DATASET::reset() +{ + type = static_cast(0); + players = 0; + game = 0; + pName.clear(); + dataDir = mod_clean; + for (auto &apDataFile : apDataFiles) + { + apDataFile.clear(); + } + psBaseData = nullptr; + psChange = nullptr; + if (realFileName) + { + free(realFileName); + } + realFileName = nullptr; + realFileHash.setZero(); + if (customMountPoint) + { + free(customMountPoint); + } + customMountPoint = nullptr; +} // initialise the level system bool levInitialise() @@ -116,18 +141,8 @@ SDWORD getLevelLoadType() static inline void freeLevel(LEVEL_DATASET* toDelete) { - for (auto &apDataFile : toDelete->apDataFiles) - { - if (apDataFile != nullptr) - { - free(apDataFile); - } - } - - free(toDelete->pName); - free(toDelete->realFileName); - free(toDelete->customMountPoint); - free(toDelete); + toDelete->reset(); + delete toDelete; } // shutdown the level system @@ -160,7 +175,7 @@ LEVEL_DATASET *levFindDataSet(char const *name, Sha256 const *hash) for (auto psNewLevel : psLevels) { - if (psNewLevel->pName && strcmp(psNewLevel->pName, name) == 0) + if (!psNewLevel->pName.empty() && strcmp(psNewLevel->pName.c_str(), name) == 0) { if (hash == nullptr || levGetFileHash(psNewLevel) == *hash) { @@ -282,14 +297,13 @@ LEVEL_DATASET* levFindBaseTileset(MAP_TILESET tileset) bool levParse_JSON(const std::string& mountPoint, const std::string& filename, searchPathMode pathMode, char const *realFileName) { // start a new level data set - LEVEL_DATASET *psDataSet = (LEVEL_DATASET *)malloc(sizeof(LEVEL_DATASET)); + LEVEL_DATASET *psDataSet = new LEVEL_DATASET(); if (!psDataSet) { debug(LOG_FATAL, "Out of memory"); abort(); return false; } - memset(psDataSet, 0, sizeof(LEVEL_DATASET)); psDataSet->players = 1; psDataSet->game = -1; @@ -302,7 +316,7 @@ bool levParse_JSON(const std::string& mountPoint, const std::string& filename, s if (!levelDetails.has_value()) { debug(LOG_ERROR, "Level File JSON load error: Failed to load JSON: %s", filename.c_str()); - free(psDataSet); + delete psDataSet; return false; } @@ -315,7 +329,7 @@ bool levParse_JSON(const std::string& mountPoint, const std::string& filename, s if (levelDetails.value().name.empty()) { debug(LOG_ERROR, "Level File JSON load error: Map has empty name??: %s", filename.c_str()); - free(psDataSet); + delete psDataSet; return false; } switch (levelDetails.value().type) @@ -324,7 +338,7 @@ bool levParse_JSON(const std::string& mountPoint, const std::string& filename, s case WzMap::MapType::SAVEGAME: // FUTURE TODO: Support other map types debug(LOG_ERROR, "Level File JSON load error: Unsupported map type: %d", (int)levelDetails.value().type); - free(psDataSet); + delete psDataSet; return false; case WzMap::MapType::SKIRMISH: customMountPoint = std::string("multiplay/maps/") + levelDetails.value().name; @@ -338,22 +352,22 @@ bool levParse_JSON(const std::string& mountPoint, const std::string& filename, s case WzMap::MapType::SAVEGAME: // FUTURE TODO: Support other map types debug(LOG_ERROR, "Level File JSON load error: Unsupported map type: %d", (int)levelDetails.value().type); - free(psDataSet); + delete psDataSet; return false; case WzMap::MapType::SKIRMISH: psDataSet->type = LEVEL_TYPE::SKIRMISH; break; } psDataSet->players = static_cast(levelDetails.value().players); - psDataSet->pName = strdup(levelDetails.value().name.c_str()); + psDataSet->pName = levelDetails.value().name; auto gamFilePath = mapIO.pathJoin(mapIO.pathDirName(customMountPoint), levelDetails.value().gamFilePath()); - psDataSet->apDataFiles[0] = strdup(gamFilePath.c_str()); + psDataSet->apDataFiles[0] = gamFilePath; psDataSet->game = 0; psDataSet->psBaseData = levFindBaseTileset(levelDetails.value().tileset); if (psDataSet->psBaseData == nullptr) { debug(LOG_ERROR, "Level File JSON load error: Failed to find base tileset for: %d", (int)levelDetails.value().tileset); - free(psDataSet); + delete psDataSet; return false; } if (!customMountPoint.empty()) @@ -408,14 +422,13 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign } // start a new level data set - psDataSet = (LEVEL_DATASET *)malloc(sizeof(LEVEL_DATASET)); + psDataSet = new LEVEL_DATASET(); if (!psDataSet) { debug(LOG_FATAL, "Out of memory"); abort(); return false; } - memset(psDataSet, 0, sizeof(LEVEL_DATASET)); psDataSet->players = 1; psDataSet->game = -1; psDataSet->dataDir = pathMode; @@ -464,7 +477,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } state = LP_LEVEL; @@ -478,7 +491,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -490,7 +503,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -504,7 +517,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign if (levVal < LEVEL_TYPE::LDS_MULTI_TYPE_START) { lev_error("invalid type number"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } @@ -513,7 +526,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } state = LP_LEVELDONE; @@ -526,7 +539,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -547,7 +560,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign ) { lev_error("Missing dataset command"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } state = LP_DATA; @@ -555,7 +568,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -568,7 +581,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -583,26 +596,20 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign if (psFoundData == nullptr) { lev_error("Cannot find full data set for camchange"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } if (psFoundData->type != LEVEL_TYPE::LDS_CAMSTART) { lev_error("Invalid data set name for cam change"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } psFoundData->psChange = psDataSet; } // store the level name - psDataSet->pName = strdup(pLevToken); - if (psDataSet->pName == nullptr) - { - debug(LOG_FATAL, "Out of memory!"); - abort(); - return false; - } + psDataSet->pName = pLevToken; state = LP_LEVELDONE; } @@ -614,7 +621,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign if (psDataSet->psBaseData == nullptr) { lev_error("Unknown dataset"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } state = LP_WAITDATA; @@ -622,7 +629,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -632,7 +639,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign if (currData >= LEVEL_MAXFILES) { lev_error("Too many data files"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } @@ -648,7 +655,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign } // store the data name - psDataSet->apDataFiles[currData] = strdup(pLevToken); + psDataSet->apDataFiles[currData] = pLevToken; resToLower(pLevToken); @@ -658,7 +665,7 @@ bool levParse(const char *buffer, size_t size, searchPathMode pathMode, bool ign else { lev_error("Syntax Error"); - if (psDataSet) { free(psDataSet); } + if (psDataSet) { delete psDataSet; } return false; } break; @@ -758,7 +765,7 @@ bool levReleaseAll() { for (int i = LEVEL_MAXFILES - 1; i >= 0; i--) { - if (psCurrLevel->psBaseData->apDataFiles[i]) + if (!psCurrLevel->psBaseData->apDataFiles[i].empty()) { resReleaseBlockData(i); } @@ -787,13 +794,8 @@ static bool levLoadSingleWRF(const char *name) } // create the dummy level data - if (sSingleWRF.pName) - { - free(sSingleWRF.pName); - } - - memset(&sSingleWRF, 0, sizeof(LEVEL_DATASET)); - sSingleWRF.pName = strdup(name); + sSingleWRF.reset(); + sSingleWRF.pName = (name) ? std::string(name) : std::string(); // load up the WRF if (!stageOneInitialise()) @@ -848,7 +850,7 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP debug(LOG_INFO, "Dataset %s not found - trying to load as WRF", name); return levLoadSingleWRF(name); } - debug(LOG_WZ, "** Data set found is %s type %d", psNewLevel->pName, (int)psNewLevel->type); + debug(LOG_WZ, "** Data set found is %s type %d", psNewLevel->pName.c_str(), (int)psNewLevel->type); /* Keep a copy of the present level name */ sstrcpy(currentLevelName, name); @@ -872,7 +874,7 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP // ensure the correct dataset is loaded if (psNewLevel->type == LEVEL_TYPE::LDS_CAMPAIGN) { - debug(LOG_ERROR, "Cannot load a campaign dataset (%s)", psNewLevel->pName); + debug(LOG_ERROR, "Cannot load a campaign dataset (%s)", psNewLevel->pName.c_str()); return false; } else @@ -903,7 +905,7 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP { if (psNewLevel->psBaseData != nullptr) { - debug(LOG_WZ, "Setting base dataset to load: %s", psNewLevel->psBaseData->pName); + debug(LOG_WZ, "Setting base dataset to load: %s", psNewLevel->psBaseData->pName.c_str()); } psBaseData = psNewLevel->psBaseData; } @@ -955,16 +957,16 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP // load up a base dataset if necessary if (psBaseData != nullptr) { - debug(LOG_WZ, "Loading base dataset %s", psBaseData->pName); + debug(LOG_WZ, "Loading base dataset %s", psBaseData->pName.c_str()); for (int i = 0; i < LEVEL_MAXFILES; i++) { - if (psBaseData->apDataFiles[i]) + if (!psBaseData->apDataFiles[i].empty()) { // load the data - debug(LOG_WZ, "Loading [directory: %s] %s ...", WZ_PHYSFS_getRealDir_String(psBaseData->apDataFiles[i]).c_str(), psBaseData->apDataFiles[i]); - if (!resLoad(psBaseData->apDataFiles[i], i)) + debug(LOG_WZ, "Loading [directory: %s] %s ...", WZ_PHYSFS_getRealDir_String(psBaseData->apDataFiles[i].c_str()).c_str(), psBaseData->apDataFiles[i].c_str()); + if (!resLoad(psBaseData->apDataFiles[i].c_str(), i)) { - debug(LOG_ERROR, "Failed resLoad(%s)!", psBaseData->apDataFiles[i]); + debug(LOG_ERROR, "Failed resLoad(%s)!", psBaseData->apDataFiles[i].c_str()); return false; } } @@ -1083,7 +1085,7 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP // load the new data - debug(LOG_NEVER, "Loading mission dataset: %s", psNewLevel->pName); + debug(LOG_NEVER, "Loading mission dataset: %s", psNewLevel->pName.c_str()); for (int i = 0; i < LEVEL_MAXFILES; i++) { if (psNewLevel->game == i) @@ -1126,96 +1128,96 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP if (pSaveName == nullptr || saveType == GTYPE_SAVE_START) { // load the game - debug(LOG_WZ, "Loading scenario file %s", psNewLevel->apDataFiles[i]); + debug(LOG_WZ, "Loading scenario file %s", psNewLevel->apDataFiles[i].c_str()); switch (psNewLevel->type) { case LEVEL_TYPE::LDS_COMPLETE: case LEVEL_TYPE::LDS_CAMSTART: debug(LOG_WZ, "LDS_COMPLETE / LDS_CAMSTART"); - if (!startMission(LEVEL_TYPE::LDS_CAMSTART, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_CAMSTART, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_CAMSTART), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_CAMSTART), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_BETWEEN: debug(LOG_WZ, "LDS_BETWEEN"); - if (!startMission(LEVEL_TYPE::LDS_BETWEEN, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_BETWEEN, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_BETWEEN), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_BETWEEN), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_MKEEP: debug(LOG_WZ, "LDS_MKEEP"); - if (!startMission(LEVEL_TYPE::LDS_MKEEP, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_MKEEP, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MKEEP), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MKEEP), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_CAMCHANGE: debug(LOG_WZ, "LDS_CAMCHANGE"); - if (!startMission(LEVEL_TYPE::LDS_CAMCHANGE, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_CAMCHANGE, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_CAMCHANGE), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_CAMCHANGE), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_EXPAND: debug(LOG_WZ, "LDS_EXPAND"); - if (!startMission(LEVEL_TYPE::LDS_EXPAND, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_EXPAND, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_EXPAND), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_EXPAND), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_EXPAND_LIMBO: debug(LOG_WZ, "LDS_LIMBO"); - if (!startMission(LEVEL_TYPE::LDS_EXPAND_LIMBO, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_EXPAND_LIMBO, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_EXPAND_LIMBO), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_EXPAND_LIMBO), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_MCLEAR: debug(LOG_WZ, "LDS_MCLEAR"); - if (!startMission(LEVEL_TYPE::LDS_MCLEAR, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_MCLEAR, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MCLEAR), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MCLEAR), psNewLevel->apDataFiles[i].c_str()); return false; } break; case LEVEL_TYPE::LDS_MKEEP_LIMBO: debug(LOG_WZ, "LDS_MKEEP_LIMBO"); - if (!startMission(LEVEL_TYPE::LDS_MKEEP_LIMBO, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_MKEEP_LIMBO, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MKEEP_LIMBO), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s)!", static_cast(LEVEL_TYPE::LDS_MKEEP_LIMBO), psNewLevel->apDataFiles[i].c_str()); return false; } break; default: ASSERT(psNewLevel->type >= LEVEL_TYPE::LDS_MULTI_TYPE_START, "Unexpected mission type"); debug(LOG_WZ, "default (MULTIPLAYER)"); - if (!startMission(LEVEL_TYPE::LDS_CAMSTART, psNewLevel->apDataFiles[i])) + if (!startMission(LEVEL_TYPE::LDS_CAMSTART, psNewLevel->apDataFiles[i].c_str())) { - debug(LOG_ERROR, "Failed startMission(%d, %s) (default)!", static_cast(LEVEL_TYPE::LDS_CAMSTART), psNewLevel->apDataFiles[i]); + debug(LOG_ERROR, "Failed startMission(%d, %s) (default)!", static_cast(LEVEL_TYPE::LDS_CAMSTART), psNewLevel->apDataFiles[i].c_str()); return false; } break; } } } - else if (psNewLevel->apDataFiles[i]) + else if (!psNewLevel->apDataFiles[i].empty()) { // load the data - debug(LOG_WZ, "Loading %s", psNewLevel->apDataFiles[i]); - if (!resLoad(psNewLevel->apDataFiles[i], i + CURRENT_DATAID)) + debug(LOG_WZ, "Loading %s", psNewLevel->apDataFiles[i].c_str()); + if (!resLoad(psNewLevel->apDataFiles[i].c_str(), i + CURRENT_DATAID)) { - debug(LOG_ERROR, "Failed resLoad(%s, %d) (default)!", psNewLevel->apDataFiles[i], i + CURRENT_DATAID); + debug(LOG_ERROR, "Failed resLoad(%s, %d) (default)!", psNewLevel->apDataFiles[i].c_str(), i + CURRENT_DATAID); return false; } } @@ -1270,7 +1272,7 @@ bool levLoadData(char const *name, Sha256 const *hash, char *pSaveName, GAME_TYP // Copy this info to be used by the crash handler for the dump file char buf[256]; - ssprintf(buf, "Current Level/map is %s", psCurrLevel->pName); + ssprintf(buf, "Current Level/map is %s", psCurrLevel->pName.c_str()); addDumpInfo(buf); if (autogame_enabled() && getHostLaunch() != HostLaunch::LoadReplay) @@ -1338,17 +1340,17 @@ LEVEL_LIST enumerateMultiMaps(int camToUse, int numPlayers) { if ((lev->type == LEVEL_TYPE::SKIRMISH || lev->type == LEVEL_TYPE::MULTI_SKIRMISH2 || lev->type == LEVEL_TYPE::MULTI_SKIRMISH3 || lev->type == LEVEL_TYPE::MULTI_SKIRMISH4) && (numPlayers == 0 || numPlayers == lev->players) - && lev->pName) + && !lev->pName.empty()) { bool already_added = false; for (auto map : list) { - if (!map->pName) + if (map->pName.empty()) { continue; } - std::string levelBaseName = mapNameWithoutTechlevel(lev->pName); - std::string mapBaseName = mapNameWithoutTechlevel(map->pName); + std::string levelBaseName = mapNameWithoutTechlevel(lev->pName.c_str()); + std::string mapBaseName = mapNameWithoutTechlevel(map->pName.c_str()); if (strcmp(levelBaseName.c_str(), mapBaseName.c_str()) == 0) { already_added = true; diff --git a/src/levels.h b/src/levels.h index d06e8c61e13..08314aa9018 100644 --- a/src/levels.h +++ b/src/levels.h @@ -30,6 +30,7 @@ #include #include +#include /// maximum number of data files #define LEVEL_MAXFILES 9 @@ -60,19 +61,22 @@ enum class LEVEL_TYPE : uint8_t struct LEVEL_DATASET { - LEVEL_TYPE type; // type of map - SWORD players; // number of players for the map - SWORD game; // index of WRF/WDG that loads the scenario file - char *pName; // title for the level - searchPathMode dataDir; // title for the level - char *apDataFiles[LEVEL_MAXFILES]; // the WRF/GAM files for the level + LEVEL_TYPE type = LEVEL_TYPE::LDS_COMPLETE; // type of map + SWORD players = 0; // number of players for the map + SWORD game = 0; // index of WRF/WDG that loads the scenario file + std::string pName; // title for the level + searchPathMode dataDir = mod_clean; // title for the level + std::array apDataFiles; // the WRF/GAM files for the level // in load order - LEVEL_DATASET *psBaseData; // LEVEL_DATASET that must be loaded for this level to load - LEVEL_DATASET *psChange; // LEVEL_DATASET used when changing to this level from another + LEVEL_DATASET *psBaseData = nullptr; // LEVEL_DATASET that must be loaded for this level to load + LEVEL_DATASET *psChange = nullptr; // LEVEL_DATASET used when changing to this level from another - char *realFileName; ///< Filename of the file containing the level, or NULL if the level is built in. - Sha256 realFileHash; ///< Use levGetFileHash() to read this value. SHA-256 hash of the file containing the level, or 0x00×32 if the level is built in or not yet calculated. - char *customMountPoint; ///< A custom mount point (to be used for "flattened" map packages, or NULL for the default. + char *realFileName = nullptr; ///< Filename of the file containing the level, or NULL if the level is built in. + Sha256 realFileHash; ///< Use levGetFileHash() to read this value. SHA-256 hash of the file containing the level, or 0x00×32 if the level is built in or not yet calculated. + char *customMountPoint = nullptr; ///< A custom mount point (to be used for "flattened" map packages, or NULL for the default. + +public: + void reset(); }; typedef std::vector LEVEL_LIST; diff --git a/src/map.h b/src/map.h index ac142f19e02..4a2c71ba76f 100644 --- a/src/map.h +++ b/src/map.h @@ -575,7 +575,7 @@ WZ_DECL_ALWAYS_INLINE static inline bool hasSensorOnTile(MAPTILE *psTile, unsign void mapInit(); void mapUpdate(); -bool shouldLoadTerrainTypeOverrides(const char* name); +bool shouldLoadTerrainTypeOverrides(const std::string& name); bool loadTerrainTypeMapOverride(MAP_TILESET tileSet); //For saves to determine if loading the terrain type override should occur diff --git a/src/multiint.cpp b/src/multiint.cpp index 11712e3bfc3..de7e0cad812 100644 --- a/src/multiint.cpp +++ b/src/multiint.cpp @@ -460,7 +460,7 @@ void loadMultiScripts() LEVEL_DATASET *psLevel = levFindDataSet(game.map, &game.hash); ASSERT_OR_RETURN(, psLevel, "No level found for %s", game.map); ASSERT_OR_RETURN(, psLevel->game >= 0 && psLevel->game < LEVEL_MAXFILES, "Invalid psLevel->game: %" PRIi16 " - may be a corrupt level load (%s; hash: %s)", psLevel->game, game.map, game.hash.toString().c_str()); - sstrcpy(aFileName, psLevel->apDataFiles[psLevel->game]); + sstrcpy(aFileName, psLevel->apDataFiles[psLevel->game].c_str()); aFileName[strlen(aFileName) - 4] = '\0'; sstrcpy(aPathName, aFileName); sstrcat(aFileName, ".json"); @@ -574,11 +574,11 @@ static MAP_TILESET guessMapTilesetType(LEVEL_DATASET *psLevel) { unsigned t = 0, c = 0; - if (psLevel->psBaseData && psLevel->psBaseData->pName) + if (psLevel->psBaseData && !psLevel->psBaseData->pName.empty()) { - if (sscanf(psLevel->psBaseData->pName, "MULTI_CAM_%u", &c) != 1) + if (sscanf(psLevel->psBaseData->pName.c_str(), "MULTI_CAM_%u", &c) != 1) { - sscanf(psLevel->psBaseData->pName, "MULTI_T%u_C%u", &t, &c); + sscanf(psLevel->psBaseData->pName.c_str(), "MULTI_T%u_C%u", &t, &c); } } @@ -717,23 +717,22 @@ void loadMapPreview(bool hideInterface) { builtInMap = true; useTerrainOverrides = shouldLoadTerrainTypeOverrides(psLevel->pName); - debug(LOG_WZ, "Loading map preview: \"%s\" builtin t%d override %d", psLevel->pName, psLevel->dataDir, (int)useTerrainOverrides); + debug(LOG_WZ, "Loading map preview: \"%s\" builtin t%d override %d", psLevel->pName.c_str(), psLevel->dataDir, (int)useTerrainOverrides); } else { builtInMap = false; useTerrainOverrides = false; - debug(LOG_WZ, "Loading map preview: \"%s\" in (%s)\"%s\" %s t%d", psLevel->pName, WZ_PHYSFS_getRealDir_String(psLevel->realFileName).c_str(), psLevel->realFileName, psLevel->realFileHash.toString().c_str(), psLevel->dataDir); + debug(LOG_WZ, "Loading map preview: \"%s\" in (%s)\"%s\" %s t%d", psLevel->pName.c_str(), WZ_PHYSFS_getRealDir_String(psLevel->realFileName).c_str(), psLevel->realFileName, psLevel->realFileHash.toString().c_str(), psLevel->dataDir); } rebuildSearchPath(psLevel->dataDir, false, psLevel->realFileName, psLevel->customMountPoint); - const char* pGamPath = psLevel->apDataFiles[psLevel->game]; - if (!pGamPath) + if (psLevel->apDataFiles[psLevel->game].empty()) { - debug(LOG_ERROR, "No path for level \"%s\"? (%s)", psLevel->pName, (psLevel->realFileName) ? psLevel->realFileName : "null"); + debug(LOG_ERROR, "No path for level \"%s\"? (%s)", psLevel->pName.c_str(), (psLevel->realFileName) ? psLevel->realFileName : "null"); loadEmptyMapPreview(); return; } - aFileName = pGamPath; + aFileName = psLevel->apDataFiles[psLevel->game]; // Remove the file extension (ex. ".gam") auto lastPeriodPos = aFileName.rfind('.'); if (std::string::npos != lastPeriodPos) @@ -785,7 +784,7 @@ void loadMapPreview(bool hideInterface) if (!mapPreviewResult) { // Failed to generate map preview - debug(LOG_ERROR, "Failed to generate map preview for: %s", psLevel->pName); + debug(LOG_ERROR, "Failed to generate map preview for: %s", psLevel->pName.c_str()); loadEmptyMapPreview(); return; } @@ -5726,11 +5725,11 @@ static unsigned int repositionHumanSlots() static void updateMapWidgets(LEVEL_DATASET *mapData) { ASSERT_OR_RETURN(, mapData != nullptr, "Invalid mapData?"); - sstrcpy(game.map, mapData->pName); + sstrcpy(game.map, mapData->pName.c_str()); game.hash = levGetFileHash(mapData); game.maxPlayers = mapData->players; game.isMapMod = CheckForMod(mapData->realFileName); - game.isRandom = CheckForRandom(mapData->realFileName, mapData->pName); + game.isRandom = CheckForRandom(mapData->realFileName, mapData->pName.c_str()); if (game.isMapMod) { widgReveal(psWScreen, MULTIOP_MAP_MOD); @@ -6046,7 +6045,7 @@ static void loadMapChallengeAndPlayerSettings(bool forceLoadPlayers = false) ASSERT_OR_RETURN(, psLevel, "No level found for %s", game.map); ASSERT_OR_RETURN(, psLevel->game >= 0 && psLevel->game < LEVEL_MAXFILES, "Invalid psLevel->game: %" PRIi16 " - may be a corrupt level load (%s; hash: %s)", psLevel->game, game.map, game.hash.toString().c_str()); - sstrcpy(aFileName, psLevel->apDataFiles[psLevel->game]); + sstrcpy(aFileName, psLevel->apDataFiles[psLevel->game].c_str()); aFileName[std::max(strlen(aFileName), 4) - 4] = '\0'; sstrcat(aFileName, ".json"); @@ -6141,7 +6140,7 @@ static void randomizeOptions() updateMapWidgets(mapData); loadMapPreview(false); loadMapChallengeAndPlayerSettings(); - debug(LOG_INFO, "Switching map: %s (builtin: %d)", (mapData->pName) ? mapData->pName : "n/a", (int)builtInMap); + debug(LOG_INFO, "Switching map: %s (builtin: %d)", (!mapData->pName.empty()) ? mapData->pName.c_str() : "n/a", (int)builtInMap); } // Reset and randomize player positions, also to guard @@ -7505,11 +7504,11 @@ TITLECODE WzMultiplayerOptionsTitleUI::run() bool oldGameIsMapMod = game.isMapMod; bool oldGameIsRandom = game.isRandom; - sstrcpy(game.map, mapData->pName); + sstrcpy(game.map, mapData->pName.c_str()); game.hash = levGetFileHash(mapData); game.maxPlayers = mapData->players; game.isMapMod = CheckForMod(mapData->realFileName); - game.isRandom = CheckForRandom(mapData->realFileName, mapData->apDataFiles[0]); + game.isRandom = CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str()); loadMapPreview(false); /* Change game info to match the previous selection if hover preview was displayed */ @@ -7542,14 +7541,14 @@ TITLECODE WzMultiplayerOptionsTitleUI::run() uint8_t oldMaxPlayers = game.maxPlayers; - sstrcpy(game.map, mapData->pName); + sstrcpy(game.map, mapData->pName.c_str()); game.hash = levGetFileHash(mapData); game.maxPlayers = mapData->players; game.isMapMod = CheckForMod(mapData->realFileName); - game.isRandom = CheckForRandom(mapData->realFileName, mapData->apDataFiles[0]); + game.isRandom = CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str()); loadMapPreview(true); loadMapChallengeAndPlayerSettings(); - debug(LOG_INFO, "Switching map: %s (builtin: %d)", (mapData->pName) ? mapData->pName : "n/a", (int)builtInMap); + debug(LOG_INFO, "Switching map: %s (builtin: %d)", (!mapData->pName.empty()) ? mapData->pName.c_str() : "n/a", (int)builtInMap); WzString name = formatGameName(game.map); widgSetString(psWScreen, MULTIOP_MAP + 1, name.toUtf8().c_str()); //What a horrible, horrible way to do this! FIX ME! (See addBlueForm) @@ -9157,7 +9156,7 @@ bool WZGameReplayOptionsHandler::restoreOptions(const nlohmann::json& object, Em { game.isMapMod = true; } - game.isRandom = mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0]); + game.isRandom = mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str()); // Set various other initialization things (see NET_FIREUP) ingame.TimeEveryoneIsInGame = nullopt; // reset time diff --git a/src/multimenu.cpp b/src/multimenu.cpp index 32560c41549..949dc073fd4 100644 --- a/src/multimenu.cpp +++ b/src/multimenu.cpp @@ -282,7 +282,7 @@ void displayRequestOption(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset) { iV_DrawImage(FrontImages, IMAGE_WEE_GUY, x + 6 * count + 6, y + 16); } - if (CheckForRandom(mapData->realFileName, mapData->apDataFiles[0])) + if (CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str())) { iV_DrawImage(FrontImages, IMAGE_WEE_DIE, x + 80 + 6, y + 15); } @@ -485,7 +485,7 @@ void addMultiRequest(const char *searchDir, const char *fileExtension, UDWORD mo for (auto mapData : levels) { - std::string withoutTechlevel = mapNameWithoutTechlevel(mapData->pName); + std::string withoutTechlevel = mapNameWithoutTechlevel(mapData->pName.c_str()); // add number of players to string. auto button = std::make_shared(); requestList->attach(button); diff --git a/src/multiopt.cpp b/src/multiopt.cpp index 312d3a01ff5..ef1fcd8ef7a 100644 --- a/src/multiopt.cpp +++ b/src/multiopt.cpp @@ -481,7 +481,7 @@ bool recvOptions(NETQUEUE queue) addConsoleMessage(str, DEFAULT_JUSTIFY, NOTIFY_MESSAGE); game.isMapMod = true; } - game.isRandom = mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0]); + game.isRandom = mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str()); if (mapData) { diff --git a/src/multiplay.cpp b/src/multiplay.cpp index a39f2ac4083..54d277acd6b 100644 --- a/src/multiplay.cpp +++ b/src/multiplay.cpp @@ -2127,7 +2127,7 @@ bool recvMapFileData(NETQUEUE queue) game.isMapMod = true; widgReveal(psWScreen, MULTIOP_MAP_MOD); } - if (mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0])) + if (mapData && CheckForRandom(mapData->realFileName, mapData->apDataFiles[0].c_str())) { game.isRandom = true; widgReveal(psWScreen, MULTIOP_MAP_RANDOM); From 8a6a3ea3e73317cd7b40d7034c5460eae30d6c58 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:27:50 -0500 Subject: [PATCH 6/6] Avoid first-run log spam --- src/terrain.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/terrain.cpp b/src/terrain.cpp index e0285b9a900..aa041434e26 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -813,7 +813,10 @@ bool setTerrainMappingTexturesMaxSize(int texSize) bool isPowerOfTwo = !(texSize == 0) && !(texSize & (texSize - 1)); if (!isPowerOfTwo || texSize < MIN_TERRAIN_TEXTURE_SIZE || texSize > 1024) { - debug(LOG_ERROR, "Attempted to set bad terrain mapping texture max size %d! Ignored.", texSize); + if (texSize != 0) + { + debug(LOG_ERROR, "Attempted to set bad terrain mapping texture max size %d! Ignored.", texSize); + } return false; } maxTerrainMappingTextureSize = texSize;