/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#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 tokens = Acore::Tokenize(data, ' ', false);
result.reserve(tokens.size());
for (auto const& token : tokens)
{
if (token.empty())
continue;
if (auto parsed = Acore::StringTo(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(ObjectGuid::LowType 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();
if (rowSource != source)
continue;
std::string data = fields[1].Get();
return ParseSettingsData(data);
} while (dbRes->NextRow());
return result;
}
void UpdateSetting(ObjectGuid::LowType playerLowGuid, std::string const& source, uint32 index, uint32 value)
{
if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
return;
PlayerSettingVector settings = LoadPlayerSettings(playerLowGuid, source);
size_t const requiredSize = static_cast(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(ObjectGuid::LowType 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();
if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
return;
if (!result)
return;
do
{
Field* fields = result->Fetch();
std::string source = fields[0].Get();
std::string data = fields[1].Get();
PlayerSettingVector settings = PlayerSettingsStore::ParseSettingsData(data);
m_charSettingsMap.emplace(std::move(source), std::move(settings));
} while (result->NextRow());
}
PlayerSetting Player::GetPlayerSetting(std::string const& source, uint32 index)
{
auto it = m_charSettingsMap.find(source);
if (it == m_charSettingsMap.end() || static_cast(index) >= it->second.size())
{
UpdatePlayerSetting(source, index, 0);
return m_charSettingsMap[source][index];
}
return it->second[index];
}
void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans)
{
if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
return;
for (auto const& [source, settings] : m_charSettingsMap)
{
if (settings.empty())
continue;
CharacterDatabasePreparedStatement* stmt = PlayerSettingsStore::PrepareReplaceStatement(GetGUID().GetCounter(), source, settings);
trans->Append(stmt);
}
}
void Player::UpdatePlayerSetting(std::string const& source, uint32 index, uint32 value)
{
auto it = m_charSettingsMap.find(source);
size_t const requiredSize = static_cast(index) + 1;
if (it == m_charSettingsMap.end())
{
// Settings not found, create new vector of appropriate size
PlayerSettingVector settings(requiredSize); // default-initialized PlayerSetting
settings[index].value = value;
m_charSettingsMap.emplace(source, std::move(settings));
}
else
{
PlayerSettingVector& settings = it->second;
if (settings.size() < requiredSize)
settings.resize(requiredSize); // new elements default to zero
settings[index].value = value;
}
}