diff options
-rw-r--r-- | sql/updates/auth/2015_04_21_00_auth.sql | 9 | ||||
-rw-r--r-- | sql/updates/characters/2015_04_21_00_characters.sql | 16 | ||||
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 4 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 75 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 33 | ||||
-rw-r--r-- | src/server/game/Handlers/AuthHandler.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuthenticationPackets.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AuthenticationPackets.h | 16 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_reload.cpp | 10 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 2 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.h | 2 |
13 files changed, 180 insertions, 21 deletions
diff --git a/sql/updates/auth/2015_04_21_00_auth.sql b/sql/updates/auth/2015_04_21_00_auth.sql new file mode 100644 index 00000000000..1a9ac877fbd --- /dev/null +++ b/sql/updates/auth/2015_04_21_00_auth.sql @@ -0,0 +1,9 @@ +DELETE FROM `rbac_permissions` WHERE `id` IN (10, 662); +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(10, 'Use character templates'), +(662, 'Command: reload character_template'); + +DELETE FROM `rbac_linked_permissions` WHERE `linkedId` IN (10, 662); +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(196, 10), +(196, 662); diff --git a/sql/updates/characters/2015_04_21_00_characters.sql b/sql/updates/characters/2015_04_21_00_characters.sql new file mode 100644 index 00000000000..b5fc1bd2ac8 --- /dev/null +++ b/sql/updates/characters/2015_04_21_00_characters.sql @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS `character_template`; +CREATE TABLE IF NOT EXISTS `character_template` ( + `id` int(10) unsigned NOT NULL, + `name` varchar(70) NOT NULL, + `description` varchar(100) NOT NULL, + `level` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `character_template_class`; +CREATE TABLE IF NOT EXISTS `character_template_class` ( + `templateId` int(10) unsigned NOT NULL, + `factionGroup` tinyint(3) unsigned NOT NULL COMMENT '3 - Alliance, 5 - Horde', + `class` tinyint(3) unsigned NOT NULL, + PRIMARY KEY (`templateId`,`factionGroup`,`class`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index e913880ac77..2a499db8fdb 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -59,7 +59,7 @@ enum RBACPermissions // 7 - reuse // 8 - reuse // 9 - reuse - // 10 - reuse + RBAC_PERM_USE_CHARACTER_TEMPLATES = 10, RBAC_PERM_LOG_GM_TRADE = 11, // 12 - reuse RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES = 13, @@ -566,7 +566,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_LOCALES_CRETURE_TEXT = 659, RBAC_PERM_COMMAND_RELOAD_LOCALES_GAMEOBJECT = 660, RBAC_PERM_COMMAND_RELOAD_LOCALES_GOSSIP_MENU_OPTION = 661, - // UNUSED + RBAC_PERM_COMMAND_RELOAD_CHARACTER_TEMPLATE = 662, RBAC_PERM_COMMAND_RELOAD_LOCALES_ITEM_SET_NAME = 663, RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING = 664, RBAC_PERM_COMMAND_RELOAD_LOCALES_PAGE_TEXT = 665, diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index fda6779c30f..eafcf16383c 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -9133,6 +9133,81 @@ void ObjectMgr::LoadRaceAndClassExpansionRequirements() TC_LOG_INFO("server.loading", ">> Loaded 0 class expansion requirements. DB table `class_expansion_requirement` is empty."); } +void ObjectMgr::LoadCharacterTemplates() +{ + uint32 oldMSTime = getMSTime(); + _characterTemplateStore.clear(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TEMPLATES); + PreparedQueryResult templates = CharacterDatabase.Query(stmt); + + if (!templates) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 character templates. DB table `character_template` is empty."); + return; + } + + PreparedQueryResult classes; + uint32 count = 0; + + do + { + Field* fields = templates->Fetch(); + + uint32 templateSetId = fields[0].GetUInt32(); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TEMPLATE_CLASSES); + stmt->setUInt32(0, templateSetId); + classes = CharacterDatabase.Query(stmt); + + if (classes) + { + CharacterTemplate templ; + templ.TemplateSetId = templateSetId; + templ.Name = fields[1].GetString(); + templ.Description = fields[2].GetString(); + templ.Level = fields[3].GetUInt8(); + + do + { + fields = classes->Fetch(); + + uint8 factionGroup = fields[0].GetUInt8(); + uint8 classID = fields[1].GetUInt8(); + + if (!((factionGroup & (FACTION_MASK_PLAYER | FACTION_MASK_ALLIANCE)) == (FACTION_MASK_PLAYER | FACTION_MASK_ALLIANCE)) && + !((factionGroup & (FACTION_MASK_PLAYER | FACTION_MASK_HORDE)) == (FACTION_MASK_PLAYER | FACTION_MASK_HORDE))) + { + TC_LOG_ERROR("sql.sql", "Faction group %u defined for character template %u in `character_template_class` is invalid. Skipped.", factionGroup, templateSetId); + continue; + } + + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(classID); + if (!classEntry) + { + TC_LOG_ERROR("sql.sql", "Class %u defined for character template %u in `character_template_class` does not exists, skipped.", classID, templateSetId); + continue; + } + + templ.Classes.emplace_back(factionGroup, classID); + + } while (classes->NextRow()); + + if (!templ.Classes.empty()) + { + _characterTemplateStore[templateSetId] = templ; + ++count; + } + } + else + { + TC_LOG_ERROR("sql.sql", "Character template %u does not have any classes defined in `character_template_class`. Skipped.", templateSetId); + continue; + } + } while (templates->NextRow()); + TC_LOG_INFO("server.loading", ">> Loaded %u character templates in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadRealmNames() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index b8e16ec1c4d..bde5aab51e1 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -596,6 +596,26 @@ typedef std::unordered_map<uint32, TrainerSpellData> CacheTrainerSpellContainer; typedef std::unordered_map<uint8, uint8> ExpansionRequirementContainer; typedef std::unordered_map<uint32, std::string> RealmNameContainer; +struct CharcterTemplateClass +{ + CharcterTemplateClass(uint8 factionGroup, uint8 classID) : + FactionGroup(factionGroup), ClassID(classID) { } + + uint8 FactionGroup; + uint8 ClassID; +}; + +struct CharacterTemplate +{ + uint32 TemplateSetId; + std::list<CharcterTemplateClass> Classes; + std::string Name; + std::string Description; + uint8 Level; +}; + +typedef std::unordered_map<uint32, CharacterTemplate> CharacterTemplateContainer; + enum SkillRangeType { SKILL_RANGE_LANGUAGE, // 300..300 @@ -1287,6 +1307,7 @@ class ObjectMgr bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId) != 0; } void LoadRaceAndClassExpansionRequirements(); + void LoadCharacterTemplates(); void LoadRealmNames(); std::string GetRealmName(uint32 realm) const; @@ -1309,6 +1330,16 @@ class ObjectMgr return EXPANSION_CLASSIC; } + CharacterTemplateContainer const& GetCharacterTemplates() const { return _characterTemplateStore; } + CharacterTemplate const* GetCharacterTemplate(uint32 id) const + { + auto itr = _characterTemplateStore.find(id); + if (itr != _characterTemplateStore.end()) + return &itr->second; + + return nullptr; + } + private: // first free id for selected id type uint32 _auctionId; @@ -1457,6 +1488,8 @@ class ObjectMgr ExpansionRequirementContainer _classExpansionRequirementStore; RealmNameContainer _realmNameStore; + CharacterTemplateContainer _characterTemplateStore; + enum CreatureLinkedRespawnType { CREATURE_TO_CREATURE, diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp index e353279ad57..10db667c549 100644 --- a/src/server/game/Handlers/AuthHandler.cpp +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -39,6 +39,10 @@ void WorldSession::SendAuthResponse(uint8 code, bool queued, uint32 queuePos) // Send current home realm. Also there is no need to send it later in realm queries. response.SuccessInfo.Value.VirtualRealms.emplace_back(GetVirtualRealmAddress(), true, false, realmName, realmName); + if (HasPermission(rbac::RBAC_PERM_USE_CHARACTER_TEMPLATES)) + for (auto& templ : sObjectMgr->GetCharacterTemplates()) + response.SuccessInfo.Value.Templates.emplace_back(templ.second); + response.SuccessInfo.Value.AvailableClasses = &sObjectMgr->GetClassExpansionRequirements(); response.SuccessInfo.Value.AvailableRaces = &sObjectMgr->GetRaceExpansionRequirements(); } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 6b6bd1a1f7d..c7960772507 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -705,6 +705,25 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac LoginDatabase.CommitTransaction(trans); + if (createInfo->TemplateSet.HasValue) + { + if (HasPermission(rbac::RBAC_PERM_USE_CHARACTER_TEMPLATES)) + { + if (CharacterTemplate const* charTemplate = sObjectMgr->GetCharacterTemplate(createInfo->TemplateSet.Value)) + { + if (charTemplate->Level != 1) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_LEVEL); + stmt->setUInt8(0, uint8(charTemplate->Level)); + stmt->setUInt64(1, newChar.GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); + } + } + } + else + TC_LOG_WARN("cheat", "Account: %u (IP: %s) tried to use a character template without given permission. Possible cheating attempt.", GetAccountId(), GetRemoteAddress().c_str()); + } + SendCharCreate(CHAR_CREATE_SUCCESS); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Create Character: %s %s", GetAccountId(), GetRemoteAddress().c_str(), createInfo->Name.c_str(), newChar.GetGUID().ToString().c_str()); diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index b6d2ff21630..8dfb05e69f7 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -104,11 +104,11 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() for (auto& templat : SuccessInfo.Value.Templates) { _worldPacket << uint32(templat.TemplateSetId); - _worldPacket << uint32(templat.TemplateClasses.size()); - for (auto& templatClass : templat.TemplateClasses) + _worldPacket << uint32(templat.Classes.size()); + for (auto& templateClass : templat.Classes) { - _worldPacket << uint8(templatClass.Class); - _worldPacket << uint8(templatClass.FactionGroup); + _worldPacket << uint8(templateClass.ClassID); + _worldPacket << uint8(templateClass.FactionGroup); } _worldPacket.WriteBits(templat.Name.length(), 7); diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index f914e18f6bc..719993e4ee4 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -83,20 +83,6 @@ namespace WorldPackets std::string RealmNameNormalized; ///< the name of the realm without spaces }; - struct CharacterTemplate - { - struct TemplateClass - { - uint8 Class; - uint8 FactionGroup; ///< @todo research - }; - - uint32 TemplateSetId; ///< @todo research - std::list<TemplateClass> TemplateClasses; - std::string Name; - std::string Description; - }; - struct AuthSuccessInfo { uint32 TimeRemain = 0; ///< the remaining game time that the account has in seconds. It is not currently implemented and probably won't ever be. @@ -111,7 +97,7 @@ namespace WorldPackets uint32 CurrencyID = 0; ///< this is probably used for the ingame shop. @todo implement std::list<RealmInfo> VirtualRealms; ///< list of realms connected to this one (inclusive) @todo implement - std::list<CharacterTemplate> Templates; ///< list of pre-made character templates. @todo implement + std::list<CharacterTemplate> Templates; ///< list of pre-made character templates. ExpansionRequirementContainer const* AvailableClasses = nullptr; ///< the minimum AccountExpansion required to select the classes ExpansionRequirementContainer const* AvailableRaces = nullptr; ///< the minimum AccountExpansion required to select the races diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 7010982dc2b..05f75358a7b 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2028,6 +2028,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading race and class expansion requirements..."); sObjectMgr->LoadRaceAndClassExpansionRequirements(); + TC_LOG_INFO("server.loading", "Loading character templates..."); + sObjectMgr->LoadCharacterTemplates(); + TC_LOG_INFO("server.loading", "Loading realm names..."); sObjectMgr->LoadRealmNames(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index c8066ee92e9..556589e281d 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -76,6 +76,7 @@ public: { "areatrigger_teleport", rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TELEPORT, true, &HandleReloadAreaTriggerTeleportCommand, "", NULL }, { "autobroadcast", rbac::RBAC_PERM_COMMAND_RELOAD_AUTOBROADCAST, true, &HandleReloadAutobroadcastCommand, "", NULL }, { "battleground_template", rbac::RBAC_PERM_COMMAND_RELOAD_BATTLEGROUND_TEMPLATE, true, &HandleReloadBattlegroundTemplate, "", NULL }, + { "character_template", rbac::RBAC_PERM_COMMAND_RELOAD_CHARACTER_TEMPLATE, true, &HandleReloadCharacterTemplate, "", NULL }, { "command", rbac::RBAC_PERM_COMMAND_RELOAD_COMMAND, true, &HandleReloadCommandCommand, "", NULL }, { "conditions", rbac::RBAC_PERM_COMMAND_RELOAD_CONDITIONS, true, &HandleReloadConditions, "", NULL }, { "config", rbac::RBAC_PERM_COMMAND_RELOAD_CONFIG, true, &HandleReloadConfigCommand, "", NULL }, @@ -202,6 +203,7 @@ public: HandleReloadAutobroadcastCommand(handler, ""); HandleReloadBattlegroundTemplate(handler, ""); + HandleReloadCharacterTemplate(handler, ""); return true; } @@ -383,6 +385,14 @@ public: return true; } + static bool HandleReloadCharacterTemplate(ChatHandler* handler, char const* /*args*/) + { + TC_LOG_INFO("misc", "Re-Loading Character Templates..."); + sObjectMgr->LoadCharacterTemplates(); + handler->SendGlobalGMSysMessage("DB table `character_template` and `character_template_class` reloaded."); + return true; + } + static bool HandleReloadCommandCommand(ChatHandler* handler, const char* /*args*/) { handler->SetLoadCommandTable(true); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index cf871ab79a4..c7a63911a4c 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -68,6 +68,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_TEMPLATES, "SELECT id, name, description, level FROM character_template", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_TEMPLATE_CLASSES, "SELECT factionGroup, class FROM character_template_class WHERE templateId = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL, "DELETE FROM character_battleground_random", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index e6c0a0db48c..b6897204b6a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -71,6 +71,8 @@ enum CharacterDatabaseStatements CHAR_SEL_CHAR_ZONE, CHAR_SEL_CHAR_POSITION_XYZ, CHAR_SEL_CHAR_POSITION, + CHAR_SEL_CHARACTER_TEMPLATES, + CHAR_SEL_CHARACTER_TEMPLATE_CLASSES, CHAR_DEL_BATTLEGROUND_RANDOM_ALL, CHAR_DEL_BATTLEGROUND_RANDOM, |