From 18987fe43d587259e8026d6cde5a807d01a77242 Mon Sep 17 00:00:00 2001 From: ElderShell Date: Thu, 30 Apr 2026 22:28:54 -0600 Subject: [PATCH] added mariadb support, on death loose 10% xp and respawn at bind point --- .../apps/worldserver/worldserver.conf.dist | 6 +- .../database/Database/DatabaseWorkerPool.cpp | 76 ++++++++++++---- .../database/Database/MySQLConnection.cpp | 34 +++++-- src/server/game/Entities/Player/Player.cpp | 91 ++++++------------- 4 files changed, 118 insertions(+), 89 deletions(-) diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index 675f46974..c30e3fbbc 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -2089,7 +2089,7 @@ WaterBreath.Timer = 180000 # 0 - Disabled # -EnableLowLevelRegenBoost = 1 +EnableLowLevelRegenBoost = 0 # # Rate.MoveSpeed.Player @@ -2146,8 +2146,8 @@ Rate.Talent.Pet = 1 # 1 - (Rate.Focus) # 1 - (Rate.Energy) -Rate.Health = 1 -Rate.Mana = 1 +Rate.Health = 0.5 +Rate.Mana = 0.5 Rate.Rage.Income = 1 Rate.Rage.Loss = 1 Rate.RunicPower.Income = 1 diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index ee19a5a48..832fe5ba7 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -59,13 +59,38 @@ DatabaseWorkerPool::DatabaseWorkerPool() : { WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe."); - bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION; - bool isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID; +#ifdef MARIADB_BASE_VERSION - WPFatal(isSupportClientDB, "AzerothCore does not support MySQL versions below 8.0\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).", - mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID); - WPFatal(isSameClientDB, "Used MySQL library version ({} id {}) does not match the version id used to compile AzerothCore (id {}).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00046).", - mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID); + // MariaDB path (skip MySQL 8 strict checks) + LOG_INFO("sql.sql", "MariaDB detected: {} (client version: {})", + mysql_get_client_info(), + mysql_get_client_version()); + +#else + + // MySQL 8+ strict validation path + const uint32 clientVersion = mysql_get_client_version(); + const uint32 compiledVersion = MYSQL_VERSION_ID; + + bool isSupportClientDB = clientVersion >= MIN_MYSQL_CLIENT_VERSION; + bool isSameClientDB = clientVersion == compiledVersion; + + WPFatal(isSupportClientDB, + "AzerothCore does not support MySQL versions below 8.0\n\n" + "Found version: {} / {}. Server compiled with: {}.\n" + "Search ACE00043 in Common Errors.", + mysql_get_client_info(), + clientVersion, + compiledVersion); + + WPFatal(isSameClientDB, + "Used MySQL library version ({} id {}) does not match compiled version id ({}).\n" + "Search ACE00046 in Common Errors.", + mysql_get_client_info(), + clientVersion, + compiledVersion); + +#endif } template @@ -417,9 +442,10 @@ bool DatabaseIncompatibleVersion(std::string const mysqlVersion) template uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConnections) { + LOG_INFO("sql.sql", "OpenConnections called for type {}", type); + for (uint8 i = 0; i < numConnections; ++i) { - // Create the connection auto connection = [&] { switch (type) @@ -433,26 +459,42 @@ uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConne } }(); - if (uint32 error = connection->Open()) + uint32 error = connection->Open(); + if (error) { - // Failed to open a connection or invalid version, abort and cleanup _queue->Cancel(); _connections[type].clear(); return error; } - else if (DatabaseIncompatibleVersion(connection->GetServerInfo())) + + bool incompatible = DatabaseIncompatibleVersion(connection->GetServerInfo()); + +#ifdef MARIADB_BASE_VERSION + // MariaDB: do NOT treat as fatal, but also do NOT blindly trust it + if (incompatible) { - LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 8.0\n\nFound server version: {}. Server compiled with: {}.", - connection->GetServerInfo(), MYSQL_VERSION_ID); + LOG_WARN("sql.driver", + "MariaDB detected with non-standard version response: {}", + connection->GetServerInfo()); + } +#else + if (incompatible) + { + LOG_ERROR("sql.driver", + "AzerothCore does not support MySQL versions below 8.0\n\n" + "Found server version: {}. Server compiled with: {}.", + connection->GetServerInfo(), + MYSQL_VERSION_ID); + + _queue->Cancel(); + _connections[type].clear(); return 1; } - else - { - _connections[type].push_back(std::move(connection)); - } +#endif + + _connections[type].push_back(std::move(connection)); } - // Everything is fine return 0; } diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 48c9c4a62..e409dd71b 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -129,13 +129,19 @@ uint32 MySQLConnection::Open() if (m_connectionInfo.ssl != "") { - mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED; - if (m_connectionInfo.ssl == "ssl") - { - opt_use_ssl = SSL_MODE_REQUIRED; - } + #if defined(MARIADB_BASE_VERSION) + // MariaDB: no mysql_ssl_mode, skip + #else + // MySQL 8+ + mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED; + + if (m_connectionInfo.ssl == "ssl") + { + opt_use_ssl = SSL_MODE_REQUIRED; + } - mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl); + mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl); + #endif } m_Mysql = reinterpret_cast(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(), @@ -217,7 +223,13 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt) uint32 _s = getMSTime(); #if MYSQL_VERSION_ID >= 80300 - if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) + #if defined(MARIADB_BASE_VERSION) + // MariaDB: only supports positional parameters + if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) + #else + // MySQL 8+: supports named parameters + if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) + #endif #else if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) #endif @@ -269,7 +281,13 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement uint32 _s = getMSTime(); #if MYSQL_VERSION_ID >= 80300 - if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) + #if defined(MARIADB_BASE_VERSION) + // MariaDB: only supports positional parameters + if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) + #else + // MySQL 8+: supports named parameters + if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) + #endif #else if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) #endif diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0739c1d3b..869278407 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4326,25 +4326,10 @@ void Player::DeleteOldRecoveryItems(uint32 keepDays) */ void Player::BuildPlayerRepop() { - WorldPacket data(SMSG_PRE_RESURRECT, GetPackGUID().size()); - data << GetPackGUID(); - SendDirectMessage(&data); - if (getRace(true) == RACE_NIGHTELF) - { - CastSpell(this, 20584, true); - } - CastSpell(this, 8326, true); - - // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK - // there must be SMSG.STOP_MIRROR_TIMER - - // the player cannot have a corpse already on current map, only bones which are not returned by GetCorpse - WorldLocation corpseLocation = GetCorpseLocation(); - if (GetCorpse() && corpseLocation.GetMapId() == GetMapId()) - { - LOG_ERROR("entities.player", "BuildPlayerRepop: player {} ({}) already has a corpse", GetName(), GetGUID().ToString()); - return; - } + // Override -- Teleport player back to their bind point [ElderShell] + ResurrectPlayer(0.1f); + // NOTE: We teleport the player in Player::RepopAtGraveyard() + // End Override // create a corpse and place it at the player's location Corpse* corpse = CreateCorpse(); @@ -4354,22 +4339,6 @@ void Player::BuildPlayerRepop() return; } GetMap()->AddToMap(corpse); - SetHealth(1); // convert player body to ghost - SetWaterWalking(true); - - if (!IsImmobilizedState()) - SendMoveRoot(false); - - RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // BG - remove insignia related - int32 corpseReclaimDelay = CalculateCorpseReclaimDelay(); - if (corpseReclaimDelay >= 0) - { - SendCorpseReclaimDelay(corpseReclaimDelay); - } - corpse->ResetGhostTime(); // to prevent cheating - StopMirrorTimers(); // disable timers on bars - SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND); // set and clear other - sScriptMgr->OnPlayerReleasedGhost(this); } void Player::ResurrectPlayer(float restore_percent, bool applySickness) @@ -4840,39 +4809,39 @@ void Player::RepopAtGraveyard() SpawnCorpseBones(); } - GraveyardStruct const* ClosestGrave = nullptr; - - // Special handle for battleground maps - if (Battleground* bg = GetBattleground()) - ClosestGrave = bg->GetClosestGraveyard(this); - else - { - if (sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId())) - ClosestGrave = sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId())->GetClosestGraveyard(this); - else - ClosestGrave = sGraveyard->GetClosestGraveyard(this, GetTeamId()); - } - // stop countdown until repop m_deathTimer = 0; - // if no grave found, stay at the current location - // and don't show spirit healer location - if (ClosestGrave) + TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + + uint32 nextLevelXp = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); + uint32 reduction = nextLevelXp / 10; + + uint32 currentXp = GetUInt32Value(PLAYER_XP); + + int32 xpToRemove = currentXp - reduction; + + if (xpToRemove < 0) { - TeleportTo(ClosestGrave->Map, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation()); - if (isDead()) // not send if alive, because it used in TeleportTo() + uint8 currentLevel = GetLevel(); + + if (currentLevel > 1) { - WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4 * 4); // show spirit healer position on minimap - data << ClosestGrave->Map; - data << ClosestGrave->x; - data << ClosestGrave->y; - data << ClosestGrave->z; - SendDirectMessage(&data); + GiveLevel(currentLevel - 1); + nextLevelXp = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); + SetUInt32Value(PLAYER_XP, nextLevelXp + xpToRemove); + } + else + { + SetUInt32Value(PLAYER_XP, 0); } } - else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) - TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + else + { + SetUInt32Value(PLAYER_XP, currentXp - reduction); + } + + //SetUInt32Value(PLAYER_XP, currentXp > reduction ? currentXp - reduction : 0); RemovePlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS); }