diff --git a/source/WorldServer/Entity.cpp b/source/WorldServer/Entity.cpp index d5e0c49..f3d152b 100644 --- a/source/WorldServer/Entity.cpp +++ b/source/WorldServer/Entity.cpp @@ -32,6 +32,7 @@ #include "Skills.h" #include "Rules/Rules.h" #include "LuaInterface.h" +#include "WorldDatabase.h" extern World world; extern MasterItemList master_item_list; @@ -40,6 +41,7 @@ extern MasterSkillList master_skill_list; extern RuleManager rule_manager; extern Classes classes; extern LuaInterface* lua_interface; +extern WorldDatabase database; Entity::Entity(){ MapInfoStruct(); @@ -616,6 +618,65 @@ void Entity::MapInfoStruct() set_float_funcs["max_chase_distance"] = l::bind(&InfoStruct::set_max_chase_distance, &info_struct, l::_1); } +void Entity::RegisterProperty(const std::string& name) { + int32 charID = 0; + + if(IsPlayer()) + charID = ((Player*)this)->GetCharacterID(); + + { + std::shared_lock rlock(propertiesMutex); + if (set_string_funcs.find(name) != set_string_funcs.end() || + get_string_funcs.find(name) != get_string_funcs.end()) + return; + } + + { + std::unique_lock wlock(propertiesMutex); + if (set_string_funcs.find(name) != set_string_funcs.end() || + get_string_funcs.find(name) != get_string_funcs.end()) { + return; + } + + set_string_funcs.emplace(name, [this, name, database, charID](std::string v) { + { + std::lock_guard lk(GetInfoStruct()->classMutex); + GetInfoStruct()->props[name] = v; + } + if(charID) + database.insertCharacterProperty(charID, const_cast(name.c_str()), const_cast(v.c_str())); + }); + + get_string_funcs.emplace(name, [this, name]() -> std::string { + std::lock_guard lk(GetInfoStruct()->classMutex); + auto it = GetInfoStruct()->props.find(name); + return (it == GetInfoStruct()->props.end()) ? std::string{} : it->second; + }); + } +} + +void Entity::SetProperty(const std::string& name, const std::string& value) { + auto it = set_string_funcs.find(name); + if (it == set_string_funcs.end()) + return; + + int32 charID = 0; + + if(IsPlayer()) + charID = ((Player*)this)->GetCharacterID(); + + if(charID) + database.insertCharacterProperty(charID, const_cast(name.c_str()), const_cast(value.c_str())); + + return it->second(value); +} + +std::optional Entity::GetProperty(const std::string& name) const { + auto it = get_string_funcs.find(name); + if (it == get_string_funcs.end()) return std::nullopt; + return it->second(); +} + bool Entity::HasMoved(bool include_heading){ if(GetX() == last_x && GetY() == last_y && GetZ() == last_z && ((!include_heading) || (include_heading && GetHeading() == last_heading))) return false; @@ -3780,251 +3841,271 @@ void Entity::HaltMovement() std::string Entity::GetInfoStructString(std::string field) { - map>::const_iterator itr = get_string_funcs.find(field); - if(itr != get_string_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_string_funcs.find(field); + if(itr != get_string_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return std::string(""); } int8 Entity::GetInfoStructInt8(std::string field) { - map>::const_iterator itr = get_int8_funcs.find(field); - if(itr != get_int8_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_int8_funcs.find(field); + if(itr != get_int8_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } int16 Entity::GetInfoStructInt16(std::string field) { - map>::const_iterator itr = get_int16_funcs.find(field); - if(itr != get_int16_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_int16_funcs.find(field); + if(itr != get_int16_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } int32 Entity::GetInfoStructInt32(std::string field) { - map>::const_iterator itr = get_int32_funcs.find(field); - if(itr != get_int32_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_int32_funcs.find(field); + if(itr != get_int32_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } int64 Entity::GetInfoStructInt64(std::string field) { - map>::const_iterator itr = get_int64_funcs.find(field); - if(itr != get_int64_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_int64_funcs.find(field); + if(itr != get_int64_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } sint8 Entity::GetInfoStructSInt8(std::string field) { - map>::const_iterator itr = get_sint8_funcs.find(field); - if(itr != get_sint8_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_sint8_funcs.find(field); + if(itr != get_sint8_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } sint16 Entity::GetInfoStructSInt16(std::string field) { - map>::const_iterator itr = get_sint16_funcs.find(field); - if(itr != get_sint16_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_sint16_funcs.find(field); + if(itr != get_sint16_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } sint32 Entity::GetInfoStructSInt32(std::string field) { - map>::const_iterator itr = get_sint32_funcs.find(field); - if(itr != get_sint32_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_sint32_funcs.find(field); + if(itr != get_sint32_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } sint64 Entity::GetInfoStructSInt64(std::string field) { - map>::const_iterator itr = get_sint64_funcs.find(field); - if(itr != get_sint64_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_sint64_funcs.find(field); + if(itr != get_sint64_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0; } float Entity::GetInfoStructFloat(std::string field) { - map>::const_iterator itr = get_float_funcs.find(field); - if(itr != get_float_funcs.end()) - { - auto func = (itr->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_float_funcs.find(field); + if(itr != get_float_funcs.end()) + { + auto func = (itr->second)(); + return func; + } return 0.0f; } int64 Entity::GetInfoStructUInt(std::string field) { - map>::const_iterator itr = get_int8_funcs.find(field); - if(itr != get_int8_funcs.end()) - { - auto func = (itr->second)(); - return func; - } - map>::const_iterator itr2 = get_int16_funcs.find(field); - if(itr2 != get_int16_funcs.end()) - { - auto func = (itr2->second)(); - return func; - } - map>::const_iterator itr3 = get_int32_funcs.find(field); - if(itr3 != get_int32_funcs.end()) - { - auto func = (itr3->second)(); - return func; - } - map>::const_iterator itr4 = get_int64_funcs.find(field); - if(itr4 != get_int64_funcs.end()) - { - auto func = (itr4->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_int8_funcs.find(field); + if(itr != get_int8_funcs.end()) + { + auto func = (itr->second)(); + return func; + } + map>::const_iterator itr2 = get_int16_funcs.find(field); + if(itr2 != get_int16_funcs.end()) + { + auto func = (itr2->second)(); + return func; + } + map>::const_iterator itr3 = get_int32_funcs.find(field); + if(itr3 != get_int32_funcs.end()) + { + auto func = (itr3->second)(); + return func; + } + map>::const_iterator itr4 = get_int64_funcs.find(field); + if(itr4 != get_int64_funcs.end()) + { + auto func = (itr4->second)(); + return func; + } return 0; } sint64 Entity::GetInfoStructSInt(std::string field) { - map>::const_iterator itr = get_sint8_funcs.find(field); - if(itr != get_sint8_funcs.end()) - { - auto func = (itr->second)(); - return func; - } - map>::const_iterator itr2 = get_sint16_funcs.find(field); - if(itr2 != get_sint16_funcs.end()) - { - auto func = (itr2->second)(); - return func; - } - map>::const_iterator itr3 = get_sint32_funcs.find(field); - if(itr3 != get_sint32_funcs.end()) - { - auto func = (itr3->second)(); - return func; - } - map>::const_iterator itr4 = get_sint64_funcs.find(field); - if(itr4 != get_sint64_funcs.end()) - { - auto func = (itr4->second)(); - return func; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = get_sint8_funcs.find(field); + if(itr != get_sint8_funcs.end()) + { + auto func = (itr->second)(); + return func; + } + map>::const_iterator itr2 = get_sint16_funcs.find(field); + if(itr2 != get_sint16_funcs.end()) + { + auto func = (itr2->second)(); + return func; + } + map>::const_iterator itr3 = get_sint32_funcs.find(field); + if(itr3 != get_sint32_funcs.end()) + { + auto func = (itr3->second)(); + return func; + } + map>::const_iterator itr4 = get_sint64_funcs.find(field); + if(itr4 != get_sint64_funcs.end()) + { + auto func = (itr4->second)(); + return func; + } return 0; } bool Entity::SetInfoStructString(std::string field, std::string value) { - map>::const_iterator itr = set_string_funcs.find(field); - if(itr != set_string_funcs.end()) - { - (itr->second)(value); - return true; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = set_string_funcs.find(field); + if(itr != set_string_funcs.end()) + { + (itr->second)(value); + return true; + } + else { + RegisterProperty(field); + SetProperty(field, value); + } return false; } bool Entity::SetInfoStructUInt(std::string field, int64 value) { - map>::const_iterator itr = set_int8_funcs.find(field); - if(itr != set_int8_funcs.end()) - { - (itr->second)((int8)value); - return true; - } - map>::const_iterator itr2 = set_int16_funcs.find(field); - if(itr2 != set_int16_funcs.end()) - { - (itr2->second)((int16)value); - return true; - } - map>::const_iterator itr3 = set_int32_funcs.find(field); - if(itr3 != set_int32_funcs.end()) - { - (itr3->second)((int32)value); - return true; - } - map>::const_iterator itr4 = set_int64_funcs.find(field); - if(itr4 != set_int64_funcs.end()) - { - (itr4->second)(value); - return true; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = set_int8_funcs.find(field); + if(itr != set_int8_funcs.end()) + { + (itr->second)((int8)value); + return true; + } + map>::const_iterator itr2 = set_int16_funcs.find(field); + if(itr2 != set_int16_funcs.end()) + { + (itr2->second)((int16)value); + return true; + } + map>::const_iterator itr3 = set_int32_funcs.find(field); + if(itr3 != set_int32_funcs.end()) + { + (itr3->second)((int32)value); + return true; + } + map>::const_iterator itr4 = set_int64_funcs.find(field); + if(itr4 != set_int64_funcs.end()) + { + (itr4->second)(value); + return true; + } return false; } bool Entity::SetInfoStructSInt(std::string field, sint64 value) { - map>::const_iterator itr = set_sint8_funcs.find(field); - if(itr != set_sint8_funcs.end()) - { - (itr->second)((sint8)value); - return true; - } - map>::const_iterator itr2 = set_sint16_funcs.find(field); - if(itr2 != set_sint16_funcs.end()) - { - (itr2->second)((sint16)value); - return true; - } - map>::const_iterator itr3 = set_sint32_funcs.find(field); - if(itr3 != set_sint32_funcs.end()) - { - (itr3->second)((sint32)value); - return true; - } - map>::const_iterator itr4 = set_sint64_funcs.find(field); - if(itr4 != set_sint64_funcs.end()) - { - (itr4->second)(value); - return true; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = set_sint8_funcs.find(field); + if(itr != set_sint8_funcs.end()) + { + (itr->second)((sint8)value); + return true; + } + map>::const_iterator itr2 = set_sint16_funcs.find(field); + if(itr2 != set_sint16_funcs.end()) + { + (itr2->second)((sint16)value); + return true; + } + map>::const_iterator itr3 = set_sint32_funcs.find(field); + if(itr3 != set_sint32_funcs.end()) + { + (itr3->second)((sint32)value); + return true; + } + map>::const_iterator itr4 = set_sint64_funcs.find(field); + if(itr4 != set_sint64_funcs.end()) + { + (itr4->second)(value); + return true; + } return false; } bool Entity::SetInfoStructFloat(std::string field, float value) { - map>::const_iterator itr = set_float_funcs.find(field); - if(itr != set_float_funcs.end()) - { - (itr->second)(value); - return true; - } + std::shared_lock rlock(propertiesMutex); + map>::const_iterator itr = set_float_funcs.find(field); + if(itr != set_float_funcs.end()) + { + (itr->second)(value); + return true; + } return false; } diff --git a/source/WorldServer/Entity.h b/source/WorldServer/Entity.h index fd16b6d..c0dccf9 100644 --- a/source/WorldServer/Entity.h +++ b/source/WorldServer/Entity.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -1110,6 +1112,9 @@ struct InfoStruct{ // maintained via their own mutex SpellEffects spell_effects[45]; MaintainedEffects maintained_effects[30]; + // when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock + std::mutex classMutex; + std::unordered_map props; private: std::string name_; int8 class1_; @@ -1328,8 +1333,6 @@ private: int8 max_spell_reduction_override_; float max_chase_distance_; - // when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock - std::mutex classMutex; }; struct WardInfo { @@ -1449,6 +1452,9 @@ public: void DeleteSpellEffects(bool removeClient = false); void RemoveSpells(bool unfriendlyOnly = false); void MapInfoStruct(); + void RegisterProperty(const std::string& name); + void SetProperty(const std::string& name, const std::string& value); + std::optional GetProperty(const std::string& name) const; virtual float GetDodgeChance(); virtual void AddMaintainedSpell(LuaSpell* spell); virtual void AddSpellEffect(LuaSpell* spell, int32 override_expire_time = 0); @@ -2205,6 +2211,8 @@ private: map > set_sint8_funcs; map > set_string_funcs; + + mutable std::shared_mutex propertiesMutex; }; #endif diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index 4a7a550..7061bc2 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -2146,125 +2146,187 @@ bool WorldDatabase::insertCharacterProperty(Client* client, char* propName, char return true; } -bool WorldDatabase::loadCharacterProperties(Client* client) { +bool WorldDatabase::insertCharacterProperty(int32 charID, char* propName, char* propValue) { + Query query, query2; + + string update_status = string("update character_properties set propvalue='%s' where charid=%i and propname='%s'"); + query.RunQuery2(Q_UPDATE, update_status.c_str(), propValue, charID, propName); + if (!query.GetAffectedRows()) + { + query2.RunQuery2(Q_UPDATE, "insert into character_properties (charid, propname, propvalue) values(%i, '%s', '%s')", charID, propName, propValue); + if (query2.GetErrorNumber() && query2.GetError() && query2.GetErrorNumber() < 0xFFFFFFFF) { + LogWrite(WORLD__ERROR, 0, "World", "Error in insertCharacterProperty query '%s': %s", query.GetQuery(), query.GetError()); + return false; + } + } + return true; +} + +bool WorldDatabase::loadCharacterProperties(Client* client, bool preload) { Query query; MYSQL_ROW row; int32 id = 0; - MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT propname, propvalue FROM character_properties where charid = %i", client->GetCharacterID()); + MYSQL_RES* result = query.RunQuery2(Q_SELECT, + "SELECT propname, propvalue FROM character_properties WHERE charid = %i", + client->GetCharacterID()); + // no character found if (result == NULL) { - LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character properties for '%s'", client->GetPlayer()->GetName()); + LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character properties for '%s'", + client->GetPlayer()->GetName()); return false; } while (result && (row = mysql_fetch_row(result))) { - char* prop_name = row[0]; + char* prop_name = row[0]; char* prop_value = row[1]; if (!prop_name || !prop_value) continue; - if (!stricmp(prop_name, CHAR_PROPERTY_SPEED)) - { - float new_speed = atof(prop_value); - client->GetPlayer()->SetSpeed(new_speed, true); - client->GetPlayer()->SetCharSheetChanged(true); - } - else if (!stricmp(prop_name, CHAR_PROPERTY_FLYMODE)) - { - int8 flymode = atoul(prop_value); - if (flymode) // avoid fly mode notification unless enabled - ClientPacketFunctions::SendFlyMode(client, flymode, false); - } - else if (!stricmp(prop_name, CHAR_PROPERTY_INVUL)) - { - int8 invul = atoul(prop_value); - client->GetPlayer()->SetInvulnerable(invul == 1); - if (client->GetPlayer()->GetInvulnerable()) - client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are now invulnerable!"); - } - else if (!stricmp(prop_name, CHAR_PROPERTY_GMVISION)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->SetGMVision(val == 1); - client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false); - if (val) - client->SimpleMessage(CHANNEL_COLOR_YELLOW, "GM Vision Enabled!"); - } - else if (!stricmp(prop_name, CHAR_PROPERTY_REGIONDEBUG)) - { - int8 val = atoul(prop_value); + bool matched = false; - client->SetRegionDebug(val == 1); - if (val) - client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Region Debug Enabled!"); - } - else if (!stricmp(prop_name, CHAR_PROPERTY_LUADEBUG)) - { - int8 val = atoul(prop_value); - if (val) - { - client->SetLuaDebugClient(true); - if (lua_interface) - lua_interface->UpdateDebugClients(client); - - client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You will now receive LUA error messages."); + if (!stricmp(prop_name, CHAR_PROPERTY_SPEED)) { + matched = true; + if (!preload) { + float new_speed = (float)atof(prop_value); + client->GetPlayer()->SetSpeed(new_speed, true); + client->GetPlayer()->SetCharSheetChanged(true); } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOOTMETHOD)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_loot_method(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_FLYMODE)) { + matched = true; + if (!preload) { + int8 flymode = (int8)atoul(prop_value); + if (flymode) // avoid fly mode notification unless enabled + ClientPacketFunctions::SendFlyMode(client, flymode, false); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOOTITEMRARITY)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_loot_items_rarity(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_INVUL)) { + matched = true; + if (!preload) { + int8 invul = (int8)atoul(prop_value); + client->GetPlayer()->SetInvulnerable(invul == 1); + if (client->GetPlayer()->GetInvulnerable()) + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are now invulnerable!"); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPAUTOSPLIT)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_auto_split(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_GMVISION)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->SetGMVision(val == 1); + client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false); + if (val) + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "GM Vision Enabled!"); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPDEFAULTYELL)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_default_yell(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_REGIONDEBUG)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->SetRegionDebug(val == 1); + if (val) + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Region Debug Enabled!"); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPAUTOLOCK)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_autolock(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_LUADEBUG)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + if (val) { + client->SetLuaDebugClient(true); + if (lua_interface) + lua_interface->UpdateDebugClients(client); + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You will now receive LUA error messages."); + } + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPSOLOAUTOLOCK)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_solo_autolock(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOOTMETHOD)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_loot_method(val); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_AUTOLOOTMETHOD)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_auto_loot_method(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOOTITEMRARITY)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_loot_items_rarity(val); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOCKMETHOD)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_group_lock_method(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPAUTOSPLIT)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_auto_split(val); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_ASSISTAUTOATTACK)) - { - int8 val = atoul(prop_value); - client->GetPlayer()->GetInfoStruct()->set_assist_auto_attack(val); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPDEFAULTYELL)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_default_yell(val); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_SETACTIVEFOOD)) - { - int32 val = atoul(prop_value); - client->GetPlayer()->SetActiveFoodUniqueID(val, false); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPAUTOLOCK)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_autolock(val); + } } - else if (!stricmp(prop_name, CHAR_PROPERTY_SETACTIVEDRINK)) - { - int32 val = atoul(prop_value); - client->GetPlayer()->SetActiveDrinkUniqueID(val, false); + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPSOLOAUTOLOCK)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_solo_autolock(val); + } + } + else if (!stricmp(prop_name, CHAR_PROPERTY_AUTOLOOTMETHOD)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_auto_loot_method(val); + } + } + else if (!stricmp(prop_name, CHAR_PROPERTY_GROUPLOCKMETHOD)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_group_lock_method(val); + } + } + else if (!stricmp(prop_name, CHAR_PROPERTY_ASSISTAUTOATTACK)) { + matched = true; + if (!preload) { + int8 val = (int8)atoul(prop_value); + client->GetPlayer()->GetInfoStruct()->set_assist_auto_attack(val); + } + } + else if (!stricmp(prop_name, CHAR_PROPERTY_SETACTIVEFOOD)) { + matched = true; + if (!preload) { + int32 val = (int32)atoul(prop_value); + client->GetPlayer()->SetActiveFoodUniqueID(val, false); + } + } + else if (!stricmp(prop_name, CHAR_PROPERTY_SETACTIVEDRINK)) { + matched = true; + if (!preload) { + int32 val = (int32)atoul(prop_value); + client->GetPlayer()->SetActiveDrinkUniqueID(val, false); + } + } + else { + // Unknown property: only act during preload AND only if no stricmp matched + // (we're in the 'else', so matched == false by definition) + if (preload) { + client->GetPlayer()->RegisterProperty(std::string(prop_name)); + client->GetPlayer()->SetProperty(std::string(prop_name), std::string(prop_value)); + } + // When preload == false, we intentionally ignore unknown properties. } } diff --git a/source/WorldServer/WorldDatabase.h b/source/WorldServer/WorldDatabase.h index 6c61261..0ef5067 100644 --- a/source/WorldServer/WorldDatabase.h +++ b/source/WorldServer/WorldDatabase.h @@ -333,7 +333,8 @@ public: bool InsertCharacterStats(int32 character_id, int8 class_id, int8 race_id); bool UpdateCharacterTimeStamp(int32 account_id, int32 character_id, int32 timestamp); bool insertCharacterProperty(Client* client, char* propName, char* propValue); - bool loadCharacterProperties(Client* client); + bool insertCharacterProperty(int32 charID, char* propName, char* propValue); + bool loadCharacterProperties(Client* client, bool preload = false); string GetPlayerName(char* name); int32 GetCharacterTimeStamp(int32 character_id, int32 account_id,bool* char_exists); int32 GetCharacterTimeStamp(int32 character_id); diff --git a/source/WorldServer/client.cpp b/source/WorldServer/client.cpp index 4766c66..186af6a 100644 --- a/source/WorldServer/client.cpp +++ b/source/WorldServer/client.cpp @@ -12249,6 +12249,7 @@ bool Client::HandleNewLogin(int32 account_id, int32 access_code) new_client_login = NewLoginState::LOGIN_ALLOWED; } + database.loadCharacterProperties(this, true); // vault slots RefreshVaultSlotCount();