From 0a0908a37d06eea0be8792666d40d3006e69af09 Mon Sep 17 00:00:00 2001 From: SirFerMoX Date: Tue, 24 Mar 2026 14:53:30 +0100 Subject: [PATCH] Fix C++20 incompatibilities preventing compilation on MSVC (VS2017) The project currently fails to compile on Windows using Visual Studio 2017 (MSVC v141) due to multiple C++20 features being used in a codebase configured for C++17. Below is a detailed list of all the changes required to make the project compile successfully on Windows. --- dep/g3dlite/source/debugAssert.cpp | 2 +- .../Debugging/WheatyExceptionReport.cpp | 2 +- src/common/Debugging/WheatyExceptionReport.h | 2 +- src/common/Utilities/Types.h | 5 ++- .../database/Database/FieldValueConverters.h | 4 +- .../database/Database/MySQLConnection.cpp | 6 +-- .../Database/MySQLPreparedStatement.cpp | 19 +++++----- .../database/Database/QueryCallback.cpp | 37 +++++++++++++++---- src/server/database/Database/QueryResult.cpp | 25 ++++++++++--- src/server/game/Entities/Player/Player.cpp | 2 +- src/server/game/Handlers/PetHandler.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 4 +- .../Draenor/Highmaul/boss_the_butcher.cpp | 5 ++- .../Northrend/Nexus/Oculus/boss_urom.cpp | 4 +- 14 files changed, 79 insertions(+), 40 deletions(-) diff --git a/dep/g3dlite/source/debugAssert.cpp b/dep/g3dlite/source/debugAssert.cpp index cfccf9a0cc5..ee771d4ff21 100644 --- a/dep/g3dlite/source/debugAssert.cpp +++ b/dep/g3dlite/source/debugAssert.cpp @@ -103,7 +103,7 @@ static void createErrorMessage( if (NULL != formatMsg) { realLastErr = formatMsg; } else { - realLastErr = _T("Last error code does not exist."); + realLastErr = (LPTSTR)_T("Last error code does not exist."); } if (lastErr != 0) { diff --git a/src/common/Debugging/WheatyExceptionReport.cpp b/src/common/Debugging/WheatyExceptionReport.cpp index 6e98bf23c5f..bd6a98f87f8 100644 --- a/src/common/Debugging/WheatyExceptionReport.cpp +++ b/src/common/Debugging/WheatyExceptionReport.cpp @@ -602,7 +602,7 @@ PEXCEPTION_POINTERS pExceptionInfo) // Given an exception code, returns a pointer to a static string with a // description of the exception //====================================================================== -LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) +LPCTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) { #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x); diff --git a/src/common/Debugging/WheatyExceptionReport.h b/src/common/Debugging/WheatyExceptionReport.h index 7d7ae3feb4e..4d11441e344 100644 --- a/src/common/Debugging/WheatyExceptionReport.h +++ b/src/common/Debugging/WheatyExceptionReport.h @@ -165,7 +165,7 @@ class WheatyExceptionReport static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount); // Helper functions - static LPTSTR GetExceptionString(DWORD dwCode); + static LPCTSTR GetExceptionString(DWORD dwCode); static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset); diff --git a/src/common/Utilities/Types.h b/src/common/Utilities/Types.h index 922be079de0..b0c4c3638c0 100644 --- a/src/common/Utilities/Types.h +++ b/src/common/Utilities/Types.h @@ -34,8 +34,11 @@ namespace Trinity using type = find_type_end; }; + template + struct type_identity { using type = T; }; + template typename Check, typename T1, typename... Ts> - struct find_type_if : std::conditional_t::value, std::type_identity, find_type_if> + struct find_type_if : std::conditional_t::value, type_identity, find_type_if> { }; diff --git a/src/server/database/Database/FieldValueConverters.h b/src/server/database/Database/FieldValueConverters.h index fc6dec8682d..43b680d61ba 100644 --- a/src/server/database/Database/FieldValueConverters.h +++ b/src/server/database/Database/FieldValueConverters.h @@ -92,7 +92,7 @@ class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter }; template<> -class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter +class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter { public: uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } @@ -109,7 +109,7 @@ class PrimitiveResultValueConverter : public char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* /*meta*/) const override { return data; } }; -using StringResultValueConverter = PrimitiveResultValueConverter; +using StringResultValueConverter = PrimitiveResultValueConverter; class NotImplementedResultValueConverter : public BaseDatabaseResultValueConverter { diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 4bb32e0880b..7acd06bb996 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -452,9 +452,9 @@ void MySQLConnection::StartWorkerThread(Trinity::Asio::IoContext* context) { boost::asio::executor_work_guard executorWorkGuard = boost::asio::make_work_guard(context->get_executor()); // construct guard before thread starts running - m_workerThread = std::make_unique(WorkerThread{ - .ThreadHandle = std::thread([context] { context->run(); }), - .WorkGuard = std::move(executorWorkGuard) + m_workerThread = std::make_unique(WorkerThread{ + std::thread([context] { context->run(); }), + std::move(executorWorkGuard) }); } diff --git a/src/server/database/Database/MySQLPreparedStatement.cpp b/src/server/database/Database/MySQLPreparedStatement.cpp index 5c8da20caee..c880f908d1c 100644 --- a/src/server/database/Database/MySQLPreparedStatement.cpp +++ b/src/server/database/Database/MySQLPreparedStatement.cpp @@ -160,17 +160,16 @@ void MySQLPreparedStatement::SetParameter(uint8 index, SystemTimePoint value) delete param->length; param->length = new unsigned long(len); - std::chrono::year_month_day ymd(time_point_cast(value)); - std::chrono::hh_mm_ss hms(duration_cast(value - std::chrono::sys_days(ymd))); - + time_t tt = std::chrono::system_clock::to_time_t(value); + tm* t = gmtime(&tt); MYSQL_TIME* time = reinterpret_cast(static_cast(param->buffer)); - time->year = static_cast(ymd.year()); - time->month = static_cast(ymd.month()); - time->day = static_cast(ymd.day()); - time->hour = hms.hours().count(); - time->minute = hms.minutes().count(); - time->second = hms.seconds().count(); - time->second_part = hms.subseconds().count(); + time->year = t->tm_year + 1900; + time->month = t->tm_mon + 1; + time->day = t->tm_mday; + time->hour = t->tm_hour; + time->minute = t->tm_min; + time->second = t->tm_sec; + time->second_part = 0; } void MySQLPreparedStatement::SetParameter(uint8 index, std::string const& value) diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index 528605da708..6539767311b 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -93,15 +93,36 @@ bool QueryCallback::InvokeIfReady() return false; }; - return std::visit([&](std::future&& future) + struct Visitor { - if (future.valid() && future.wait_for(0s) == std::future_status::ready) + QueryCallback& self; + std::function& checkStateAndReturnCompletion; + + bool operator()(std::future&& future) { - std::future f(std::move(future)); - std::function cb(std::get>(std::move(_callbacks.front()))); - cb(*this, f.get()); - return checkStateAndReturnCompletion(); + if (future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + std::future f(std::move(future)); + std::function cb(std::get>(std::move(self._callbacks.front()))); + cb(self, f.get()); + return checkStateAndReturnCompletion(); + } + return false; } - return false; - }, std::move(_query)); + + bool operator()(std::future&& future) + { + if (future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + std::future f(std::move(future)); + std::function cb(std::get>(std::move(self._callbacks.front()))); + cb(self, f.get()); + return checkStateAndReturnCompletion(); + } + return false; + } + }; + std::function checkFn = checkStateAndReturnCompletion; + Visitor v{*this, checkFn}; + return std::visit(v, std::move(_query)); } diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index a22f48c9a9b..c18ff14f21f 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -318,13 +318,26 @@ class DateResultValueConverter : public BaseDatabaseResultValueConverter switch (source.time_type) { case MYSQL_TIMESTAMP_DATE: - return sys_days(year(source.year) / month(source.month) / day(source.day)); + { + std::tm t = {}; + t.tm_year = source.year - 1900; + t.tm_mon = source.month - 1; + t.tm_mday = source.day; + time_t tt = mktime(&t); + return std::chrono::system_clock::from_time_t(tt); + } case MYSQL_TIMESTAMP_DATETIME: - return sys_days(year(source.year) / month(source.month) / day(source.day)) - + hours(source.hour) - + minutes(source.minute) - + seconds(source.second) - + microseconds(source.second_part); + { + std::tm t = {}; + t.tm_year = source.year - 1900; + t.tm_mon = source.month - 1; + t.tm_mday = source.day; + t.tm_hour = source.hour; + t.tm_min = source.minute; + t.tm_sec = source.second; + time_t tt = mktime(&t); + return std::chrono::system_clock::from_time_t(tt) + std::chrono::microseconds(source.second_part); + } default: break; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f7d4876dc00..45afe4d82ef 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -28729,7 +28729,7 @@ void Player::SendGarrisonInfo() const { garrisonInfo.Plots.push_back(&plot->PacketInfo); if (plot->BuildingInfo.PacketInfo) - garrisonInfo.Buildings.push_back(std::to_address(plot->BuildingInfo.PacketInfo)); + garrisonInfo.Buildings.push_back(plot->BuildingInfo.PacketInfo.has_value() ? &(*plot->BuildingInfo.PacketInfo) : nullptr); } } diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index f04e29a8cee..82316b65ce2 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -520,7 +520,7 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) ObjectGuid petguid = packet.RenameData.PetGUID; std::string name = packet.RenameData.NewName; - DeclinedName const* declinedname = std::to_address(packet.RenameData.DeclinedNames); + DeclinedName const* declinedname = packet.RenameData.DeclinedNames.has_value() ? &(*packet.RenameData.DeclinedNames) : nullptr; Pet* pet = ObjectAccessor::GetPet(*_player, petguid); // check it! diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ccc3c7b747c..53fc83775f1 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4470,10 +4470,10 @@ void Spell::EffectCharge(SpellEffIndex effIndex) { //unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster)); - m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, false, unitTarget, std::to_address(spellEffectExtraData)); + m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, false, unitTarget, spellEffectExtraData ? &(*spellEffectExtraData) : nullptr); } else - m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, unitTarget, std::to_address(spellEffectExtraData)); + m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, unitTarget, spellEffectExtraData ? &(*spellEffectExtraData) : nullptr); } if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) diff --git a/src/server/scripts/Draenor/Highmaul/boss_the_butcher.cpp b/src/server/scripts/Draenor/Highmaul/boss_the_butcher.cpp index 0161d1f32e3..5117b2a6cc6 100644 --- a/src/server/scripts/Draenor/Highmaul/boss_the_butcher.cpp +++ b/src/server/scripts/Draenor/Highmaul/boss_the_butcher.cpp @@ -16,7 +16,8 @@ * with this program. If not, see . */ -# include "highmaul.h" +#include "highmaul.h" +#include Position const g_MaggotSpawnPos[eHighmaulDatas::MaxMaggotToKill] = { @@ -400,7 +401,7 @@ class boss_the_butcher : public CreatureScript if (action == eAction::MaggotKilled) { std::vector l_Indexes = { 0, 1, 2, 3, 4, 5 }; - std::random_shuffle(l_Indexes.begin(), l_Indexes.end()); + std::shuffle(l_Indexes.begin(), l_Indexes.end(), std::mt19937{std::random_device{}()}); for (uint8 l_I : l_Indexes) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp index 76ce7ade438..223b4c17717 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp @@ -27,6 +27,8 @@ EndScriptData */ #include "oculus.h" #include "ScriptedCreature.h" #include "SpellInfo.h" +#include "ScriptMgr.h" +#include enum Spells { @@ -102,7 +104,7 @@ class boss_urom : public CreatureScript for (uint8 i = 0; i < 3; ++i) group[i] = i; - std::random_shuffle(group, group + 3); + std::shuffle(group, group + 3, std::mt19937{std::random_device{}()}); } void Initialize()