mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-21 12:47:07 +00:00
feat(core): add standalone functions for player settings (#22703)
This commit is contained in:
@@ -18,11 +18,95 @@
|
||||
#include "Player.h"
|
||||
#include "StringConvert.h"
|
||||
#include "Tokenize.h"
|
||||
#include "CharacterDatabase.h"
|
||||
|
||||
/*********************************************************/
|
||||
/*** PLAYER SETTINGS SYSTEM ***/
|
||||
/*********************************************************/
|
||||
|
||||
namespace PlayerSettingsStore
|
||||
{
|
||||
// Common helper: parse space-separated data string into PlayerSettingVector
|
||||
PlayerSettingVector ParseSettingsData(std::string const& data)
|
||||
{
|
||||
PlayerSettingVector result;
|
||||
std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', false);
|
||||
result.reserve(tokens.size());
|
||||
for (auto const& token : tokens)
|
||||
{
|
||||
if (token.empty())
|
||||
continue;
|
||||
if (auto parsed = Acore::StringTo<uint32>(token))
|
||||
result.emplace_back(*parsed);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Common helper: serialize PlayerSettingVector to space-separated string
|
||||
std::string SerializeSettingsData(PlayerSettingVector const& settings)
|
||||
{
|
||||
if (settings.empty())
|
||||
return "";
|
||||
|
||||
std::ostringstream data;
|
||||
data << settings[0].value;
|
||||
for (size_t i = 1; i < settings.size(); ++i)
|
||||
data << ' ' << settings[i].value;
|
||||
return data.str();
|
||||
}
|
||||
|
||||
// helper: load a single source row for a player and parse to vector
|
||||
static PlayerSettingVector LoadPlayerSettings(uint32 playerLowGuid, std::string const& source)
|
||||
{
|
||||
PlayerSettingVector result;
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
|
||||
stmt->SetData(0, playerLowGuid);
|
||||
PreparedQueryResult dbRes = CharacterDatabase.Query(stmt);
|
||||
if (!dbRes)
|
||||
return result;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = dbRes->Fetch();
|
||||
std::string rowSource = fields[0].Get<std::string>();
|
||||
if (rowSource != source)
|
||||
continue;
|
||||
|
||||
std::string data = fields[1].Get<std::string>();
|
||||
return ParseSettingsData(data);
|
||||
} while (dbRes->NextRow());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UpdateSetting(uint32 playerLowGuid, std::string const& source, uint8 index, uint32 value)
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
|
||||
return;
|
||||
|
||||
PlayerSettingVector settings = LoadPlayerSettings(playerLowGuid, source);
|
||||
size_t const requiredSize = static_cast<size_t>(index) + 1;
|
||||
if (settings.size() < requiredSize)
|
||||
settings.resize(requiredSize); // zero-initialized PlayerSetting::value
|
||||
|
||||
settings[index].value = value;
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = PlayerSettingsStore::PrepareReplaceStatement(playerLowGuid, source, settings);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of PrepareReplaceStatement
|
||||
CharacterDatabasePreparedStatement* PlayerSettingsStore::PrepareReplaceStatement(uint32 playerLowGuid, std::string const& source, PlayerSettingVector const& settings)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_SETTINGS);
|
||||
stmt->SetData(0, playerLowGuid);
|
||||
stmt->SetData(1, source);
|
||||
stmt->SetData(2, SerializeSettingsData(settings));
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void Player::_LoadCharacterSettings(PreparedQueryResult result)
|
||||
{
|
||||
m_charSettingsMap.clear();
|
||||
@@ -39,21 +123,7 @@ void Player::_LoadCharacterSettings(PreparedQueryResult result)
|
||||
std::string source = fields[0].Get<std::string>();
|
||||
std::string data = fields[1].Get<std::string>();
|
||||
|
||||
std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', false);
|
||||
|
||||
PlayerSettingVector settings;
|
||||
settings.reserve(tokens.size()); // reserve capacity but don't resize
|
||||
|
||||
for (auto const& token : tokens)
|
||||
{
|
||||
if (token.empty())
|
||||
continue;
|
||||
|
||||
// Try to parse the value safely
|
||||
if (auto parsed = Acore::StringTo<uint32>(token))
|
||||
settings.emplace_back(*parsed);
|
||||
}
|
||||
|
||||
PlayerSettingVector settings = PlayerSettingsStore::ParseSettingsData(data);
|
||||
m_charSettingsMap.emplace(std::move(source), std::move(settings));
|
||||
|
||||
} while (result->NextRow());
|
||||
@@ -81,16 +151,7 @@ void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans)
|
||||
if (settings.empty())
|
||||
continue;
|
||||
|
||||
std::ostringstream data;
|
||||
data << settings[0].value;
|
||||
|
||||
for (size_t i = 1; i < settings.size(); ++i)
|
||||
data << ' ' << settings[i].value;
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_SETTINGS);
|
||||
stmt->SetData(0, GetGUID().GetCounter());
|
||||
stmt->SetData(1, source);
|
||||
stmt->SetData(2, data.str());
|
||||
CharacterDatabasePreparedStatement* stmt = PlayerSettingsStore::PrepareReplaceStatement(GetGUID().GetCounter(), source, settings);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#ifndef _PLAYER_SETTINGS_H
|
||||
#define _PLAYER_SETTINGS_H
|
||||
#include "DatabaseEnvFwd.h"
|
||||
|
||||
class Player;
|
||||
|
||||
@@ -51,4 +52,18 @@ struct PlayerSetting
|
||||
typedef std::vector<PlayerSetting> PlayerSettingVector;
|
||||
typedef std::map<std::string, PlayerSettingVector> PlayerSettingMap;
|
||||
|
||||
// Standalone API: update a player's setting directly on DB by GUID (low part) without requiring a Player instance
|
||||
namespace PlayerSettingsStore
|
||||
{
|
||||
// Update a single setting value for any player by GUID (works for online or offline players).
|
||||
// This reads the existing "source" row from character_settings, adjusts the index, and REPLACE's it back.
|
||||
void UpdateSetting(uint32 playerLowGuid, std::string const& source, uint8 index, uint32 value);
|
||||
|
||||
// Common helpers for parsing and serializing settings data
|
||||
PlayerSettingVector ParseSettingsData(std::string const& data);
|
||||
std::string SerializeSettingsData(PlayerSettingVector const& settings);
|
||||
// Prepare a REPLACE statement populated with given settings data. Caller may execute or append to a transaction.
|
||||
CharacterDatabasePreparedStatement* PrepareReplaceStatement(uint32 playerLowGuid, std::string const& source, PlayerSettingVector const& settings);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user