added mariadb support, on death loose 10% xp and respawn at bind point

This commit is contained in:
ElderShell 2026-04-30 22:28:54 -06:00
parent ab9d0a074d
commit 18987fe43d
4 changed files with 118 additions and 89 deletions

View file

@ -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

View file

@ -59,13 +59,38 @@ DatabaseWorkerPool<T>::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 <class T>
@ -417,9 +442,10 @@ bool DatabaseIncompatibleVersion(std::string const mysqlVersion)
template <class T>
uint32 DatabaseWorkerPool<T>::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<T>::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;
}

View file

@ -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<MySQLHandle*>(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

View file

@ -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);
}