From 4b4237174fa7cfefadad38dbe236213c33390225 Mon Sep 17 00:00:00 2001 From: Zedron Date: Sun, 24 Jan 2016 17:09:02 -0600 Subject: [PATCH 01/79] Core/Spells: Fixed a possible crash in spell_pal_light_s_beacon --- src/server/scripts/Spells/spell_paladin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 5e8b5ab8885..5887aded51c 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -912,6 +912,8 @@ class spell_pal_light_s_beacon : public SpellScriptLoader bool CheckProc(ProcEventInfo& eventInfo) { + if (!eventInfo.GetActionTarget()) + return false; if (eventInfo.GetActionTarget()->HasAura(SPELL_PALADIN_BEACON_OF_LIGHT, eventInfo.GetActor()->GetGUID())) return false; return true; From 3f503cd1d10c1785ef1520ff960e0577131b6005 Mon Sep 17 00:00:00 2001 From: Boomper Date: Wed, 27 Jan 2016 21:53:05 +0100 Subject: [PATCH 02/79] Core/Spells: Fixed Heroic Leap Closes #14807 Closes #14134 --- sql/updates/world/2016_01_27_00_world.sql | 6 + src/server/scripts/Spells/spell_warrior.cpp | 119 +++++++++++++++++++- 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 sql/updates/world/2016_01_27_00_world.sql diff --git a/sql/updates/world/2016_01_27_00_world.sql b/sql/updates/world/2016_01_27_00_world.sql new file mode 100644 index 00000000000..0690f8ceed7 --- /dev/null +++ b/sql/updates/world/2016_01_27_00_world.sql @@ -0,0 +1,6 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_warr_heroic_leap', 'spell_warr_heroic_leap_jump'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(6544,'spell_warr_heroic_leap'), +(178368,'spell_warr_heroic_leap_jump'); + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x80 WHERE `entry`=47319; diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 2619a5af065..5d686f6aa38 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -62,7 +62,11 @@ enum WarriorSpells SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1 = 64849, SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, SPELL_WARRIOR_VIGILANCE_PROC = 50725, - SPELL_WARRIOR_VENGEANCE = 76691 + SPELL_WARRIOR_VENGEANCE = 76691, + SPELL_WARRIOR_HEROIC_LEAP_JUMP = 178368, + SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP = 159708, + SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP_BUFF = 133278, + SPELL_WARRIOR_IMPROVED_HEROIC_LEAP = 157449, }; enum WarriorSpellIcons @@ -948,6 +952,117 @@ class spell_warr_vigilance_trigger : public SpellScriptLoader } }; +// Heroic leap - 6544 +class spell_warr_heroic_leap : public SpellScriptLoader +{ +public: + spell_warr_heroic_leap() : SpellScriptLoader("spell_warr_heroic_leap") { } + + class spell_warr_heroic_leap_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_heroic_leap_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_HEROIC_LEAP_JUMP)) + return false; + return true; + } + + SpellCastResult CheckElevation() + { + if (WorldLocation const* dest = GetExplTargetDest()) + { + if (GetCaster()->HasUnitMovementFlag(MOVEMENTFLAG_ROOT)) + return SPELL_FAILED_ROOTED; + + if (GetCaster()->GetMap()->Instanceable()) + { + float range = GetSpellInfo()->GetMaxRange(true, GetCaster()) * 1.5f; + + PathGenerator generatedPath(GetCaster()); + generatedPath.SetPathLengthLimit(range); + + bool result = generatedPath.CalculatePath(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), false, true); + if (generatedPath.GetPathType() & PATHFIND_SHORT) + return SPELL_FAILED_OUT_OF_RANGE; + else if (!result || generatedPath.GetPathType() & PATHFIND_NOPATH) + { + result = generatedPath.CalculatePath(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), false, false); + if (generatedPath.GetPathType() & PATHFIND_SHORT) + return SPELL_FAILED_OUT_OF_RANGE; + else if (!result || generatedPath.GetPathType() & PATHFIND_NOPATH) + return SPELL_FAILED_NOPATH; + } + } + else if (dest->GetPositionZ() > GetCaster()->GetPositionZ() + 4.0f) + return SPELL_FAILED_NOPATH; + + return SPELL_CAST_OK; + } + + return SPELL_FAILED_NO_VALID_TARGETS; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (WorldLocation* dest = GetHitDest()) + GetCaster()->CastSpell(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), SPELL_WARRIOR_HEROIC_LEAP_JUMP, true); + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_warr_heroic_leap_SpellScript::CheckElevation); + OnEffectHit += SpellEffectFn(spell_warr_heroic_leap_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_warr_heroic_leap_SpellScript(); + } +}; + +// Heroic Leap (triggered by Heroic Leap (6544)) - 178368 +class spell_warr_heroic_leap_jump : public SpellScriptLoader +{ +public: + spell_warr_heroic_leap_jump() : SpellScriptLoader("spell_warr_heroic_leap_jump") { } + + class spell_warr_heroic_leap_jump_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_heroic_leap_jump_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP) || + !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP_BUFF) || + !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_IMPROVED_HEROIC_LEAP) || + !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_TAUNT)) + return false; + return true; + } + + void AfterJump(SpellEffIndex /*effIndex*/) + { + if (GetCaster()->HasAura(SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP)) + GetCaster()->CastSpell(GetCaster(), SPELL_WARRIOR_GLYPH_OF_HEROIC_LEAP_BUFF, true); + if (GetCaster()->HasAura(SPELL_WARRIOR_IMPROVED_HEROIC_LEAP)) + GetCaster()->GetSpellHistory()->ResetCooldown(SPELL_WARRIOR_TAUNT, true); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_warr_heroic_leap_jump_SpellScript::AfterJump, EFFECT_1, SPELL_EFFECT_JUMP_DEST); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_warr_heroic_leap_jump_SpellScript(); + } +}; + void AddSC_warrior_spell_scripts() { new spell_warr_bloodthirst(); @@ -972,4 +1087,6 @@ void AddSC_warrior_spell_scripts() new spell_warr_victorious(); new spell_warr_vigilance(); new spell_warr_vigilance_trigger(); + new spell_warr_heroic_leap(); + new spell_warr_heroic_leap_jump(); } From 01be486f2f0f35e8421d1a1919bd037194756932 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 28 Jan 2016 17:49:41 +0100 Subject: [PATCH 03/79] Core/Misc: Removed unneccessary boost/asio/buffer.hpp include --- src/server/game/Server/WorldSocket.h | 1 - src/server/shared/Packets/ByteBuffer.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 59975c12f13..d6d29fb2826 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -28,7 +28,6 @@ #include "WorldSession.h" #include #include -#include using boost::asio::ip::tcp; struct z_stream_s; diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 1f9fcacb772..b8c6ee1c36e 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -33,7 +33,6 @@ #include #include #include -#include class MessageBuffer; From a224c400b14b9e4cf82c43bd6f8ed18d83d17e6d Mon Sep 17 00:00:00 2001 From: Dr-J Date: Sat, 30 Jan 2016 15:16:18 +0000 Subject: [PATCH 04/79] DB/SAI: Overthane Balargarde A couple of updates to previous commit https://github.com/TrinityCore/TrinityCore/commit/a258e36039392b60a0f0c98a466f9e4f1121f3eb Closes #4841 --- sql/updates/world/2016_01_30_05_world.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 sql/updates/world/2016_01_30_05_world.sql diff --git a/sql/updates/world/2016_01_30_05_world.sql b/sql/updates/world/2016_01_30_05_world.sql new file mode 100644 index 00000000000..1e341506dfc --- /dev/null +++ b/sql/updates/world/2016_01_30_05_world.sql @@ -0,0 +1,2 @@ +UPDATE `smart_scripts` SET `event_param1`=60600, `event_param2`=60600 WHERE `entryorguid`=3101600 AND `source_type`=9 AND `id`=8 AND `link`=0; +UPDATE `smart_scripts` SET `action_param1`=2, `comment`='Overthane Balargarde - On Data Set - Set Phase 2' WHERE `entryorguid`=31016 AND `source_type`=0 AND `id`=26 AND `link`=33; From 3d2d6288899d7164218fd22c0f8402258b5fb9a4 Mon Sep 17 00:00:00 2001 From: Dr-J Date: Sat, 30 Jan 2016 15:23:37 +0000 Subject: [PATCH 05/79] Remove unintended file --- sql/updates/world/2016_01_30_05_world.sql | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 sql/updates/world/2016_01_30_05_world.sql diff --git a/sql/updates/world/2016_01_30_05_world.sql b/sql/updates/world/2016_01_30_05_world.sql deleted file mode 100644 index 1e341506dfc..00000000000 --- a/sql/updates/world/2016_01_30_05_world.sql +++ /dev/null @@ -1,2 +0,0 @@ -UPDATE `smart_scripts` SET `event_param1`=60600, `event_param2`=60600 WHERE `entryorguid`=3101600 AND `source_type`=9 AND `id`=8 AND `link`=0; -UPDATE `smart_scripts` SET `action_param1`=2, `comment`='Overthane Balargarde - On Data Set - Set Phase 2' WHERE `entryorguid`=31016 AND `source_type`=0 AND `id`=26 AND `link`=33; From 32e8b6506fc064fdba134d692dfe99298e43f055 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Sat, 30 Jan 2016 01:18:40 +0100 Subject: [PATCH 06/79] Collision/MMap: Fix a memleak reported by valgrind Tiles which are owned by the mesh should have the DT_TILE_FREE_DATA flag to ensure deallocation on removal from the mesh. Log: ==23516== 6,181,976 bytes in 6 blocks are definitely lost in loss record 15 of 15 ==23516== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389) ==23516== by 0x2052660: dtCustomAlloc(int, dtAllocHint) (Memory.h:11) ==23516== by 0x29D7FDA: dtAlloc(int, dtAllocHint) (DetourAlloc.cpp:43) ==23516== by 0x230AA70: MMAP::MMapManager::loadMap(std::string const&, unsigned int, int, int) (MMapManager.cpp:166) ==23516== by 0x1DD585B: Map::LoadMMap(int, int) (Map.cpp:125) ==23516== by 0x1DD7266: Map::LoadMapAndVMap(int, int) (Map.cpp:200) ==23516== by 0x1DD93C6: Map::EnsureGridCreated_i(CoordPair<64u> const&) (Map.cpp:453) ==23516== by 0x1DD9129: Map::EnsureGridCreated(CoordPair<64u> const&) (Map.cpp:429) ==23516== by 0x1DED100: Map::GetGrid(float, float) (Map.cpp:2200) ==23516== by 0x1DE0F4C: Map::GetAreaFlag(float, float, float, bool*) const (Map.cpp:2349) ==23516== by 0x198521B: Map::GetZoneId(float, float, float) const (Map.h:353) ==23516== by 0x197CFF0: WorldObject::GetZoneId() const (Object.cpp:1277) Phase tiles aren't managed by detour so they shouldn't be free'd automatically on removal. See MMapManager::UnloadPhaseTile --- src/common/Collision/Management/MMapManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp index 3f873b704d1..486219b9f32 100644 --- a/src/common/Collision/Management/MMapManager.cpp +++ b/src/common/Collision/Management/MMapManager.cpp @@ -179,7 +179,7 @@ namespace MMAP dtTileRef tileRef = 0; // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed - if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, 0/*DT_TILE_FREE_DATA*/, 0, &tileRef))) + if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) { mmap->loadedTileRefs.insert(std::pair(packedGridPos, tileRef)); ++loadedTiles; From a174fa4d7b0b76f47239a76a8c4c36d6090217da Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 30 Jan 2016 23:56:02 +0100 Subject: [PATCH 07/79] Core/PacketIO: Updated and enabled CMSG_CONFIRM_RESPEC_WIPE, SMSG_RESPEC_WIPE_CONFIRM --- src/server/game/Entities/Player/Player.cpp | 9 ++++--- src/server/game/Entities/Player/Player.h | 8 ++++++ src/server/game/Handlers/SkillHandler.cpp | 16 ++++++------ .../game/Server/Packets/TalentPackets.cpp | 16 +++++++++++- .../game/Server/Packets/TalentPackets.h | 25 ++++++++++++++++++- src/server/game/Server/Protocol/Opcodes.cpp | 4 +-- src/server/game/Server/WorldSession.h | 3 ++- 7 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a26c1f3c841..82c5bb27e5c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9045,10 +9045,11 @@ void Player::SetBindPoint(ObjectGuid guid) const void Player::SendRespecWipeConfirm(ObjectGuid const& guid, uint32 cost) const { - WorldPacket data(SMSG_RESPEC_WIPE_CONFIRM, 8 + 4); - data << guid; - data << cost; - GetSession()->SendPacket(&data); + WorldPackets::Talent::RespecWipeConfirm respecWipeConfirm; + respecWipeConfirm.RespecMaster = guid; + respecWipeConfirm.Cost = cost; + respecWipeConfirm.RespecType = SPEC_RESET_TALENTS; + GetSession()->SendPacket(respecWipeConfirm.Write()); } void Player::ResetPetTalents() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 6b235a3d0e0..d6fcd7a3cee 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -155,6 +155,14 @@ enum TalentSpecialization // talent tabs TALENT_SPEC_MONK_MISTWEAVER = 270 }; +enum SpecResetType +{ + SPEC_RESET_TALENTS = 0, + SPEC_RESET_SPECIALIZATION = 1, + SPEC_RESET_GLYPHS = 2, + SPEC_RESET_PET_TALENTS = 3 +}; + // Spell modifier (used for modify other spells) struct SpellModifier { diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp index 59ffde0d6b4..2060468a41a 100644 --- a/src/server/game/Handlers/SkillHandler.cpp +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -37,16 +37,18 @@ void WorldSession::HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents& _player->SendTalentsInfoData(); } -void WorldSession::HandleConfirmRespecWipeOpcode(WorldPacket& recvData) +void WorldSession::HandleConfirmRespecWipeOpcode(WorldPackets::Talent::ConfirmRespecWipe& confirmRespecWipe) { - TC_LOG_DEBUG("network", "MSG_TALENT_WIPE_CONFIRM"); - ObjectGuid guid; - recvData >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(confirmRespecWipe.RespecMaster, UNIT_NPC_FLAG_TRAINER); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleConfirmRespecWipeOpcode - %s not found or you can't interact with him.", guid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleConfirmRespecWipeOpcode - %s not found or you can't interact with him.", confirmRespecWipe.RespecMaster.ToString().c_str()); + return; + } + + if (confirmRespecWipe.RespecType != SPEC_RESET_TALENTS) + { + TC_LOG_DEBUG("network", "WORLD: HandleConfirmRespecWipeOpcode - reset type %d is not implemented.", confirmRespecWipe.RespecType); return; } diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp index 932392e0cb4..7dc2daaa706 100644 --- a/src/server/game/Server/Packets/TalentPackets.cpp +++ b/src/server/game/Server/Packets/TalentPackets.cpp @@ -54,4 +54,18 @@ void WorldPackets::Talent::LearnTalents::Read() _worldPacket >> talent; Talents.push_back(talent); } -} \ No newline at end of file +} + +WorldPacket const* WorldPackets::Talent::RespecWipeConfirm::Write() +{ + _worldPacket << int8(RespecType); + _worldPacket << uint32(Cost); + _worldPacket << RespecMaster; + return &_worldPacket; +} + +void WorldPackets::Talent::ConfirmRespecWipe::Read() +{ + _worldPacket >> RespecMaster; + _worldPacket >> RespecType; +} diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h index 47519ba4e3b..ca6b0217a28 100644 --- a/src/server/game/Server/Packets/TalentPackets.h +++ b/src/server/game/Server/Packets/TalentPackets.h @@ -68,8 +68,31 @@ namespace WorldPackets void Read() override; std::vector Talents; - }; + + class RespecWipeConfirm final : public ServerPacket + { + public: + RespecWipeConfirm() : ServerPacket(SMSG_RESPEC_WIPE_CONFIRM, 16 + 4 +1) { } + + WorldPacket const* Write() override; + + ObjectGuid RespecMaster; + uint32 Cost = 0; + int8 RespecType = 0; + }; + + class ConfirmRespecWipe final : public ClientPacket + { + public: + ConfirmRespecWipe(WorldPacket&& packet) : ClientPacket(CMSG_CONFIRM_RESPEC_WIPE, std::move(packet)) { } + + void Read() override; + + ObjectGuid RespecMaster; + uint8 RespecType = 0; + }; + } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index e006a352c4b..a40564aa1f2 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -294,7 +294,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_COMPLAINT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleComplainOpcode ); DEFINE_HANDLER(CMSG_COMPLETE_CINEMATIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::CompleteCinematic, &WorldSession::HandleCompleteCinematic); DEFINE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CONFIRM_RESPEC_WIPE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleConfirmRespecWipeOpcode ); + DEFINE_HANDLER(CMSG_CONFIRM_RESPEC_WIPE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::ConfirmRespecWipe, &WorldSession::HandleConfirmRespecWipeOpcode); DEFINE_HANDLER(CMSG_CONNECT_TO_FAILED, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_CONVERT_RAID, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ConvertRaid, &WorldSession::HandleConvertRaidOpcode); DEFINE_HANDLER(CMSG_CREATE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CreateCharacter, &WorldSession::HandleCharCreateOpcode); @@ -1527,7 +1527,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_RANGED_COMBAT_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_WEEKLY_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPEC_WIPE_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPEC_WIPE_CONFIRM, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_CAST_BAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index dc4f3b32417..529aa3a56d2 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -582,6 +582,7 @@ namespace WorldPackets { class SetSpecialization; class LearnTalents; + class ConfirmRespecWipe; } namespace Taxi @@ -1369,7 +1370,7 @@ class WorldSession void HandleCancelAutoRepeatSpellOpcode(WorldPackets::Spells::CancelAutoRepeatSpell& cancelAutoRepeatSpell); void HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents& packet); - void HandleConfirmRespecWipeOpcode(WorldPacket& recvPacket); + void HandleConfirmRespecWipeOpcode(WorldPackets::Talent::ConfirmRespecWipe& confirmRespecWipe); void HandleUnlearnSkillOpcode(WorldPackets::Spells::UnlearnSkill& packet); void HandleSetSpecializationOpcode(WorldPackets::Talent::SetSpecialization& packet); From d932f7452f58f672832f3e717c592d0d50402e03 Mon Sep 17 00:00:00 2001 From: imbavirus Date: Mon, 1 Feb 2016 19:21:08 +0200 Subject: [PATCH 08/79] Rename incorrectly named files --- ...ld_2015_12_14_00.sql => 2016_01_16_00_world_2015_12_14_00.sql} | 0 ...ld_2015_12_15_03.sql => 2016_01_16_01_world_2015_12_15_03.sql} | 0 ...ld_2015_12_16_00.sql => 2016_01_16_02_world_2015_12_16_00.sql} | 0 ...ld_2015_12_16_01.sql => 2016_01_16_03_world_2015_12_16_01.sql} | 0 ...ld_2015_12_17_00.sql => 2016_01_16_05_world_2015_12_17_00.sql} | 0 ...ld_2015_12_18_01.sql => 2016_01_16_06_world_2015_12_18_01.sql} | 0 ...ld_2015_12_18_02.sql => 2016_01_16_07_world_2015_12_18_02.sql} | 0 ...ld_2015_12_18_04.sql => 2016_01_16_08_world_2015_12_18_04.sql} | 0 ...ld_2015_12_20_00.sql => 2016_01_16_09_world_2015_12_20_00.sql} | 0 ...ld_2015_12_24_00.sql => 2016_01_16_10_world_2015_12_24_00.sql} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename sql/updates/world/{2015_01_16_00_world_2015_12_14_00.sql => 2016_01_16_00_world_2015_12_14_00.sql} (100%) rename sql/updates/world/{2016_01_16_00_world_2015_12_15_03.sql => 2016_01_16_01_world_2015_12_15_03.sql} (100%) rename sql/updates/world/{2016_01_16_01_world_2015_12_16_00.sql => 2016_01_16_02_world_2015_12_16_00.sql} (100%) rename sql/updates/world/{2016_01_16_02_world_2015_12_16_01.sql => 2016_01_16_03_world_2015_12_16_01.sql} (100%) rename sql/updates/world/{2016_01_16_03_world_2015_12_17_00.sql => 2016_01_16_05_world_2015_12_17_00.sql} (100%) rename sql/updates/world/{2016_01_16_04_world_2015_12_18_01.sql => 2016_01_16_06_world_2015_12_18_01.sql} (100%) rename sql/updates/world/{2016_01_16_05_world_2015_12_18_02.sql => 2016_01_16_07_world_2015_12_18_02.sql} (100%) rename sql/updates/world/{2016_01_16_06_world_2015_12_18_04.sql => 2016_01_16_08_world_2015_12_18_04.sql} (100%) rename sql/updates/world/{2016_01_16_07_world_2015_12_20_00.sql => 2016_01_16_09_world_2015_12_20_00.sql} (100%) rename sql/updates/world/{2016_01_16_08_world_2015_12_24_00.sql => 2016_01_16_10_world_2015_12_24_00.sql} (100%) diff --git a/sql/updates/world/2015_01_16_00_world_2015_12_14_00.sql b/sql/updates/world/2016_01_16_00_world_2015_12_14_00.sql similarity index 100% rename from sql/updates/world/2015_01_16_00_world_2015_12_14_00.sql rename to sql/updates/world/2016_01_16_00_world_2015_12_14_00.sql diff --git a/sql/updates/world/2016_01_16_00_world_2015_12_15_03.sql b/sql/updates/world/2016_01_16_01_world_2015_12_15_03.sql similarity index 100% rename from sql/updates/world/2016_01_16_00_world_2015_12_15_03.sql rename to sql/updates/world/2016_01_16_01_world_2015_12_15_03.sql diff --git a/sql/updates/world/2016_01_16_01_world_2015_12_16_00.sql b/sql/updates/world/2016_01_16_02_world_2015_12_16_00.sql similarity index 100% rename from sql/updates/world/2016_01_16_01_world_2015_12_16_00.sql rename to sql/updates/world/2016_01_16_02_world_2015_12_16_00.sql diff --git a/sql/updates/world/2016_01_16_02_world_2015_12_16_01.sql b/sql/updates/world/2016_01_16_03_world_2015_12_16_01.sql similarity index 100% rename from sql/updates/world/2016_01_16_02_world_2015_12_16_01.sql rename to sql/updates/world/2016_01_16_03_world_2015_12_16_01.sql diff --git a/sql/updates/world/2016_01_16_03_world_2015_12_17_00.sql b/sql/updates/world/2016_01_16_05_world_2015_12_17_00.sql similarity index 100% rename from sql/updates/world/2016_01_16_03_world_2015_12_17_00.sql rename to sql/updates/world/2016_01_16_05_world_2015_12_17_00.sql diff --git a/sql/updates/world/2016_01_16_04_world_2015_12_18_01.sql b/sql/updates/world/2016_01_16_06_world_2015_12_18_01.sql similarity index 100% rename from sql/updates/world/2016_01_16_04_world_2015_12_18_01.sql rename to sql/updates/world/2016_01_16_06_world_2015_12_18_01.sql diff --git a/sql/updates/world/2016_01_16_05_world_2015_12_18_02.sql b/sql/updates/world/2016_01_16_07_world_2015_12_18_02.sql similarity index 100% rename from sql/updates/world/2016_01_16_05_world_2015_12_18_02.sql rename to sql/updates/world/2016_01_16_07_world_2015_12_18_02.sql diff --git a/sql/updates/world/2016_01_16_06_world_2015_12_18_04.sql b/sql/updates/world/2016_01_16_08_world_2015_12_18_04.sql similarity index 100% rename from sql/updates/world/2016_01_16_06_world_2015_12_18_04.sql rename to sql/updates/world/2016_01_16_08_world_2015_12_18_04.sql diff --git a/sql/updates/world/2016_01_16_07_world_2015_12_20_00.sql b/sql/updates/world/2016_01_16_09_world_2015_12_20_00.sql similarity index 100% rename from sql/updates/world/2016_01_16_07_world_2015_12_20_00.sql rename to sql/updates/world/2016_01_16_09_world_2015_12_20_00.sql diff --git a/sql/updates/world/2016_01_16_08_world_2015_12_24_00.sql b/sql/updates/world/2016_01_16_10_world_2015_12_24_00.sql similarity index 100% rename from sql/updates/world/2016_01_16_08_world_2015_12_24_00.sql rename to sql/updates/world/2016_01_16_10_world_2015_12_24_00.sql From 6fbfc61de1931f1e70aee80249535436e368c113 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Mon, 1 Feb 2016 20:14:10 +0100 Subject: [PATCH 09/79] Core/PacketIO: Updated and enabled CMSG_DISMISS_CRITTER --- src/server/game/Handlers/PetHandler.cpp | 12 ++---- src/server/game/Server/Packets/AllPackets.h | 1 + .../game/Server/Packets/PartyPackets.cpp | 2 +- src/server/game/Server/Packets/PetPackets.cpp | 24 ++++++++++++ src/server/game/Server/Packets/PetPackets.h | 39 +++++++++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 7 +++- 7 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/server/game/Server/Packets/PetPackets.cpp create mode 100644 src/server/game/Server/Packets/PetPackets.h diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 83792e6fc05..20c31930de6 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -33,22 +33,18 @@ #include "SpellHistory.h" #include "SpellInfo.h" #include "Player.h" +#include "PetPackets.h" #include "SpellPackets.h" #include "QueryPackets.h" -void WorldSession::HandleDismissCritter(WorldPacket& recvData) +void WorldSession::HandleDismissCritter(WorldPackets::Pet::DismissCritter& packet) { - ObjectGuid guid; - recvData >> guid; - - TC_LOG_DEBUG("network", "WORLD: Received CMSG_DISMISS_CRITTER for %s", guid.ToString().c_str()); - - Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.CritterGUID); if (!pet) { TC_LOG_DEBUG("network", "Vanitypet (%s) does not exist - player '%s' (%s / account: %u) attempted to dismiss it (possibly lagged out)", - guid.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str(), GetAccountId()); + packet.CritterGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str(), GetAccountId()); return; } diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 186d702cc8b..f9d06a56286 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -50,6 +50,7 @@ #include "NPCPackets.h" #include "PacketUtilities.h" #include "PartyPackets.h" +#include "PetPackets.h" #include "PetitionPackets.h" #include "QueryPackets.h" #include "QuestPackets.h" diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp index e93c0030cd5..01a2da40c7b 100644 --- a/src/server/game/Server/Packets/PartyPackets.cpp +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -503,7 +503,7 @@ void WorldPackets::Party::PartyMemberStats::Initialize(Player const* player) // Pet if (player->GetPet()) { - Pet* pet = player->GetPet(); + ::Pet* pet = player->GetPet(); MemberStats.PetStats = boost::in_place(); diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp new file mode 100644 index 00000000000..fb0d9beff83 --- /dev/null +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -0,0 +1,24 @@ +#include "PetPackets.h" +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 "PetPackets.h" + +void WorldPackets::Pet::DismissCritter::Read() +{ + _worldPacket >> CritterGUID; +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h new file mode 100644 index 00000000000..69d251eb76c --- /dev/null +++ b/src/server/game/Server/Packets/PetPackets.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 . + */ + +#ifndef PetPackets_h__ +#define PetPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace Pet + { + class DismissCritter final : public ClientPacket + { + public: + DismissCritter(WorldPacket&& packet) : ClientPacket(CMSG_DISMISS_CRITTER, std::move(packet)) { } + + void Read() override; + + ObjectGuid CritterGUID; + }; + } +} +#endif // PetPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a40564aa1f2..b9767a7299e 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -320,7 +320,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_DF_SET_ROLES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetRolesOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_DF_TELEPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgTeleportOpcode ); DEFINE_HANDLER(CMSG_DISCARDED_TIME_SYNC_ACKS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_DISMISS_CRITTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissCritter ); + DEFINE_HANDLER(CMSG_DISMISS_CRITTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Pet::DismissCritter, &WorldSession::HandleDismissCritter); DEFINE_HANDLER(CMSG_DO_MASTER_LOOT_ROLL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_DO_READY_CHECK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::DoReadyCheck, &WorldSession::HandleDoReadyCheckOpcode); DEFINE_HANDLER(CMSG_DUEL_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Duel::DuelResponse, &WorldSession::HandleDuelResponseOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 529aa3a56d2..b539ff4391b 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -476,6 +476,11 @@ namespace WorldPackets class ClearRaidMarker; } + namespace Pet + { + class DismissCritter; + } + namespace Petition { class DeclinePetition; @@ -1450,7 +1455,7 @@ class WorldSession void HandleSetActionBarToggles(WorldPackets::Character::SetActionBarToggles& packet); void HandleTotemDestroyed(WorldPackets::Totem::TotemDestroyed& totemDestroyed); - void HandleDismissCritter(WorldPacket& recvData); + void HandleDismissCritter(WorldPackets::Pet::DismissCritter& dismissCritter); //Battleground void HandleBattlemasterHelloOpcode(WorldPackets::NPC::Hello& hello); From 391992ed80f3f91b95d19d5cab1b0b4e8f8fb8be Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 01:06:44 +0100 Subject: [PATCH 10/79] Core/PacketIO: Updated and enabled CMSG_ITEM_PURCHASE_REFUND --- src/server/game/Handlers/ItemHandler.cpp | 11 ++++------- src/server/game/Server/Packets/ItemPackets.cpp | 5 +++++ src/server/game/Server/Packets/ItemPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 7a88c3a1315..c43c996614a 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1083,20 +1083,17 @@ void WorldSession::HandleGetItemPurchaseData(WorldPackets::Item::GetItemPurchase GetPlayer()->SendRefundInfo(item); } -void WorldSession::HandleItemRefund(WorldPacket &recvData) +void WorldSession::HandleItemRefund(WorldPackets::Item::ItemPurchaseRefund& packet) { - ObjectGuid guid; - recvData >> guid; // item guid - - Item* item = _player->GetItemByGuid(guid); + Item* item = _player->GetItemByGuid(packet.ItemGUID); if (!item) { - TC_LOG_DEBUG("network", "Item refund: item not found!"); + TC_LOG_DEBUG("network", "WorldSession::HandleItemRefund: Item (%s) not found!", packet.ItemGUID.ToString().c_str()); return; } // Don't try to refund item currently being disenchanted - if (_player->GetLootGUID() == guid) + if (_player->GetLootGUID() == packet.ItemGUID) return; GetPlayer()->RefundItem(item); diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index ab25edcecf0..e627d80fdea 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -109,6 +109,11 @@ WorldPacket const* WorldPackets::Item::SetItemPurchaseData::Write() return &_worldPacket; } +void WorldPackets::Item::ItemPurchaseRefund::Read() +{ + _worldPacket >> ItemGUID; +} + WorldPacket const* WorldPackets::Item::ItemPurchaseRefundResult::Write() { _worldPacket << ItemGUID; diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index ecf264b1fde..833d1bd9261 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -147,6 +147,16 @@ namespace WorldPackets ObjectGuid ItemGUID; }; + class ItemPurchaseRefund final : public ClientPacket + { + public: + ItemPurchaseRefund(WorldPacket&& packet) : ClientPacket(CMSG_ITEM_PURCHASE_REFUND, std::move(packet)) { } + + void Read() override; + + ObjectGuid ItemGUID; + }; + class ItemPurchaseRefundResult final : public ServerPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index b9767a7299e..a017bf91210 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -422,7 +422,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::Inspect, &WorldSession::HandleInspectOpcode); DEFINE_HANDLER(CMSG_INSPECT_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::InspectPVPRequest, &WorldSession::HandleInspectPVP); DEFINE_HANDLER(CMSG_INSTANCE_LOCK_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Instance::InstanceLockResponse, &WorldSession::HandleInstanceLockResponse); - DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_PURCHASE_REFUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefund ); + DEFINE_HANDLER(CMSG_ITEM_PURCHASE_REFUND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::ItemPurchaseRefund, &WorldSession::HandleItemRefund); DEFINE_HANDLER(CMSG_ITEM_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::ItemTextQuery, &WorldSession::HandleItemTextQuery); DEFINE_HANDLER(CMSG_JOIN_PET_BATTLE_QUEUE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_JOIN_RATED_BATTLEGROUND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index b539ff4391b..505e5faab4e 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -346,6 +346,7 @@ namespace WorldPackets class BuyBackItem; class DestroyItem; class GetItemPurchaseData; + class ItemPurchaseRefund; class RepairItem; class ReadItem; class SellItem; @@ -1535,7 +1536,7 @@ class WorldSession void HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment& cancelTempEnchantment); void HandleGetItemPurchaseData(WorldPackets::Item::GetItemPurchaseData& packet); - void HandleItemRefund(WorldPacket& recvData); + void HandleItemRefund(WorldPackets::Item::ItemPurchaseRefund& packet); void HandleSetTaxiBenchmarkOpcode(WorldPacket& recvData); From 0b763812833be6802bcc63955d9b4531268960e7 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 01:18:27 +0100 Subject: [PATCH 11/79] Core/PacketIO: Updated and enabled CMSG_PET_ABANDON --- src/server/game/Handlers/PetHandler.cpp | 9 ++------- src/server/game/Server/Packets/PetPackets.cpp | 6 +++++- src/server/game/Server/Packets/PetPackets.h | 11 +++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 20c31930de6..1b6e496a1bf 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -662,17 +662,12 @@ void WorldSession::HandlePetRename(WorldPacket& recvData) pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped } -void WorldSession::HandlePetAbandon(WorldPacket& recvData) +void WorldSession::HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet) { - ObjectGuid guid; - recvData >> guid; //pet guid - TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_ABANDON %s", guid.ToString().c_str()); - if (!_player->IsInWorld()) return; - // pet/charmed - Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.Pet); if (pet) { if (pet->IsPet()) diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index fb0d9beff83..9963e0fde6a 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -1,4 +1,3 @@ -#include "PetPackets.h" /* * Copyright (C) 2008-2016 TrinityCore * @@ -22,3 +21,8 @@ void WorldPackets::Pet::DismissCritter::Read() { _worldPacket >> CritterGUID; } + +void WorldPackets::Pet::PetAbandon::Read() +{ + _worldPacket >> Pet; +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 69d251eb76c..bfa7c910260 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -34,6 +34,17 @@ namespace WorldPackets ObjectGuid CritterGUID; }; + + class PetAbandon final : public ClientPacket + { + public: + PetAbandon(WorldPacket&& packet) : ClientPacket(CMSG_PET_ABANDON, std::move(packet)) { } + + void Read() override; + + ObjectGuid Pet; + }; } } + #endif // PetPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a017bf91210..c36eda4548d 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -557,7 +557,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_PETITION_RENAME_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionRenameGuild, &WorldSession::HandlePetitionRenameGuild); DEFINE_HANDLER(CMSG_PETITION_SHOW_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionShowList, &WorldSession::HandlePetitionShowList); DEFINE_HANDLER(CMSG_PETITION_SHOW_SIGNATURES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionShowSignatures, &WorldSession::HandlePetitionShowSignatures); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_ABANDON, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAbandon ); + DEFINE_HANDLER(CMSG_PET_ABANDON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Pet::PetAbandon ,&WorldSession::HandlePetAbandon); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_ACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAction ); DEFINE_HANDLER(CMSG_PET_BATTLE_FINAL_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_PET_BATTLE_INPUT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 505e5faab4e..442aa03b3aa 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -480,6 +480,7 @@ namespace WorldPackets namespace Pet { class DismissCritter; + class PetAbandon; } namespace Petition @@ -1447,7 +1448,7 @@ class WorldSession void HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spellid, uint16 flag, ObjectGuid guid2, float x, float y, float z); void HandleQueryPetName(WorldPackets::Query::QueryPetName& packet); void HandlePetSetAction(WorldPacket& recvData); - void HandlePetAbandon(WorldPacket& recvData); + void HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet); void HandlePetRename(WorldPacket& recvData); void HandlePetCancelAuraOpcode(WorldPacket& recvPacket); void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); From 5b313bf74d00f46d4d1ce006cd8274e6cbd14286 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 01:38:29 +0100 Subject: [PATCH 12/79] Core/PacketIO: Updated and enabled CMSG_PET_CANCEL_AURA --- src/server/game/Handlers/SpellHandler.cpp | 20 +++++++------------ .../game/Server/Packets/SpellPackets.cpp | 6 ++++++ src/server/game/Server/Packets/SpellPackets.h | 11 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index b58e2fca69e..cbbb468938e 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -367,32 +367,26 @@ void WorldSession::HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& canc } } -void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) +void WorldSession::HandlePetCancelAuraOpcode(WorldPackets::Spells::PetCancelAura& packet) { - ObjectGuid guid; - uint32 spellId; - - recvPacket >> guid; - recvPacket >> spellId; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID); if (!spellInfo) { - TC_LOG_ERROR("network", "WORLD: unknown PET spell id %u", spellId); + TC_LOG_ERROR("network", "WORLD: unknown PET spell id %u", packet.SpellID); return; } - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.PetGUID); if (!pet) { - TC_LOG_ERROR("network", "HandlePetCancelAura: Attempt to cancel an aura for non-existant %s by player '%s'", guid.ToString().c_str(), GetPlayer()->GetName().c_str()); + TC_LOG_ERROR("network", "HandlePetCancelAura: Attempt to cancel an aura for non-existant %s by player '%s'", packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str()); return; } if (pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm()) { - TC_LOG_ERROR("network", "HandlePetCancelAura: %s is not a pet of player '%s'", guid.ToString().c_str(), GetPlayer()->GetName().c_str()); + TC_LOG_ERROR("network", "HandlePetCancelAura: %s is not a pet of player '%s'", packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str()); return; } @@ -402,7 +396,7 @@ void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) return; } - pet->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL); + pet->RemoveOwnedAura(packet.SpellID, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL); } void WorldSession::HandleCancelGrowthAuraOpcode(WorldPackets::Spells::CancelGrowthAura& /*cancelGrowthAura*/) diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index 0d0be9eae94..251d7069b52 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -24,6 +24,12 @@ void WorldPackets::Spells::CancelAura::Read() _worldPacket >> CasterGUID; } +void WorldPackets::Spells::PetCancelAura::Read() +{ + _worldPacket >> PetGUID; + _worldPacket >> SpellID; +} + void WorldPackets::Spells::CancelChannelling::Read() { _worldPacket >> ChannelSpell; diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 3fc1d6cca56..1a6cb9bc60b 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -72,6 +72,17 @@ namespace WorldPackets void Read() override { } }; + class PetCancelAura final : public ClientPacket + { + public: + PetCancelAura(WorldPacket&& packet) : ClientPacket(CMSG_PET_CANCEL_AURA, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGUID; + uint32 SpellID; + }; + class RequestCategoryCooldowns final : public ClientPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c36eda4548d..a0fd06f8330 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -568,7 +568,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_PET_BATTLE_REQUEST_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_PET_BATTLE_REQUEST_WILD, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_PET_BATTLE_SCRIPT_ERROR_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_CANCEL_AURA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode ); + DEFINE_HANDLER(CMSG_PET_CANCEL_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::PetCancelAura, &WorldSession::HandlePetCancelAuraOpcode); DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::PetCastSpell, &WorldSession::HandlePetCastSpellOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_RENAME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_SET_ACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSetAction ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 442aa03b3aa..66320475e3d 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -572,6 +572,7 @@ namespace WorldPackets class CancelChannelling; class CancelGrowthAura; class CancelMountAura; + class PetCancelAura; class RequestCategoryCooldowns; class CancelCast; class CastSpell; @@ -1450,7 +1451,7 @@ class WorldSession void HandlePetSetAction(WorldPacket& recvData); void HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet); void HandlePetRename(WorldPacket& recvData); - void HandlePetCancelAuraOpcode(WorldPacket& recvPacket); + void HandlePetCancelAuraOpcode(WorldPackets::Spells::PetCancelAura& packet); void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); void HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell); From dea718e4ed89cf6006c5456c4fec82e0ceac6536 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 01:56:51 +0100 Subject: [PATCH 13/79] Core/PacketIO: Updated and enabled CMSG_PET_STOP_ATTACK --- src/server/game/Handlers/PetHandler.cpp | 13 ++++--------- src/server/game/Server/Packets/PetPackets.cpp | 5 +++++ src/server/game/Server/Packets/PetPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 1b6e496a1bf..7c53a6c3936 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -115,25 +115,20 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) } } -void WorldSession::HandlePetStopAttack(WorldPacket &recvData) +void WorldSession::HandlePetStopAttack(WorldPackets::Pet::PetStopAttack& packet) { - ObjectGuid guid; - recvData >> guid; - - TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_STOP_ATTACK for %s", guid.ToString().c_str()); - - Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.PetGUID); if (!pet) { - TC_LOG_ERROR("network", "HandlePetStopAttack: %s does not exist", guid.ToString().c_str()); + TC_LOG_ERROR("network", "HandlePetStopAttack: %s does not exist", packet.PetGUID.ToString().c_str()); return; } if (pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) { TC_LOG_ERROR("network", "HandlePetStopAttack: %s isn't a pet or charmed creature of player %s", - guid.ToString().c_str(), GetPlayer()->GetName().c_str()); + packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str()); return; } diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index 9963e0fde6a..1eb41790072 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -26,3 +26,8 @@ void WorldPackets::Pet::PetAbandon::Read() { _worldPacket >> Pet; } + +void WorldPackets::Pet::PetStopAttack::Read() +{ + _worldPacket >> PetGUID; +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index bfa7c910260..2afd5383afa 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -44,6 +44,16 @@ namespace WorldPackets ObjectGuid Pet; }; + + class PetStopAttack final : public ClientPacket + { + public: + PetStopAttack(WorldPacket&& packet) : ClientPacket(CMSG_PET_STOP_ATTACK, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGUID; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a0fd06f8330..d68887ac20f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -573,7 +573,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_RENAME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_SET_ACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSetAction ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_SPELL_AUTOCAST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSpellAutocastOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_STOP_ATTACK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetStopAttack ); + DEFINE_HANDLER(CMSG_PET_STOP_ATTACK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Pet::PetStopAttack, &WorldSession::HandlePetStopAttack); DEFINE_HANDLER(CMSG_PING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_PLAYER_LOGIN, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::PlayerLogin, &WorldSession::HandlePlayerLoginOpcode); DEFINE_HANDLER(CMSG_PROTOCOL_MISMATCH, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 66320475e3d..38d66935539 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -481,6 +481,7 @@ namespace WorldPackets { class DismissCritter; class PetAbandon; + class PetStopAttack; } namespace Petition @@ -1445,7 +1446,7 @@ class WorldSession //Pet void HandlePetAction(WorldPacket& recvData); - void HandlePetStopAttack(WorldPacket& recvData); + void HandlePetStopAttack(WorldPackets::Pet::PetStopAttack& packet); void HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spellid, uint16 flag, ObjectGuid guid2, float x, float y, float z); void HandleQueryPetName(WorldPackets::Query::QueryPetName& packet); void HandlePetSetAction(WorldPacket& recvData); From 1f8268c89c73312faff67e3b2d271bfec0ccefc3 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 16:38:36 +0100 Subject: [PATCH 14/79] Core/PacketIO: Updated and enabled CMSG_PET_SPELL_AUTOCAST --- src/server/game/Entities/Pet/Pet.cpp | 24 +++---- src/server/game/Handlers/PetHandler.cpp | 62 +++++++++---------- src/server/game/Server/Packets/PetPackets.cpp | 7 +++ src/server/game/Server/Packets/PetPackets.h | 12 ++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 +- 6 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index b5fb841333c..d4db53634c2 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1726,25 +1726,22 @@ uint8 Pet::GetMaxTalentPointsForLevel(uint8 level) const void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply) { + ASSERT(spellInfo); + if (!spellInfo->IsAutocastable()) return; - uint32 spellid = spellInfo->Id; - - PetSpellMap::iterator itr = m_spells.find(spellid); + PetSpellMap::iterator itr = m_spells.find(spellInfo->Id); if (itr == m_spells.end()) return; - uint32 i; + auto autospellItr = std::find(m_autospells.begin(), m_autospells.end(), spellInfo->Id); if (apply) { - for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; ++i) - ; // just search - - if (i == m_autospells.size()) + if (autospellItr == m_autospells.end()) { - m_autospells.push_back(spellid); + m_autospells.push_back(spellInfo->Id); if (itr->second.active != ACT_ENABLED) { @@ -1756,13 +1753,10 @@ void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply) } else { - AutoSpellList::iterator itr2 = m_autospells.begin(); - for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; ++i, ++itr2) - ; // just search - - if (i < m_autospells.size()) + if (autospellItr != m_autospells.end()) { - m_autospells.erase(itr2); + m_autospells.erase(autospellItr); + if (itr->second.active != ACT_DISABLED) { itr->second.active = ACT_DISABLED; diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 7c53a6c3936..32d988179c2 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -666,57 +666,52 @@ void WorldSession::HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet) if (pet) { if (pet->IsPet()) - _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); + _player->RemovePet(pet->ToPet(), PET_SAVE_AS_DELETED); else if (pet->GetGUID() == _player->GetCharmGUID()) _player->StopCastingCharm(); } } -void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) +void WorldSession::HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutocast& packet) { - ObjectGuid guid; - uint32 spellid; - uint8 state; //1 for on, 0 for off - recvPacket >> guid >> spellid >> state; - - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - if (ObjectAccessor::FindPlayer(guid)) - return; - - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm())) + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.PetGUID); + if (!pet) { - TC_LOG_ERROR("network", "HandlePetSpellAutocastOpcode. %s isn't pet of player %s (%s).", guid.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); + TC_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcode: Pet %s not found.", packet.PetGUID.ToString().c_str()); return; } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + if (pet != _player->GetGuardianPet() && pet != _player->GetCharm()) + { + TC_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcode: %s isn't pet of player %s (%s).", + packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); + return; + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID); if (!spellInfo) { - TC_LOG_ERROR("network", "WORLD: unknown PET spell id %u", spellid); + TC_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id %u used by %s.", packet.SpellID, packet.PetGUID.ToString().c_str()); return; } // do not add not learned spells/ passive spells - if (!pet->HasSpell(spellid) || !spellInfo->IsAutocastable()) + if (!pet->HasSpell(packet.SpellID) || !spellInfo->IsAutocastable()) return; CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { - TC_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcod: object (%s) is considered pet-like but doesn't have a charminfo!", pet->GetGUID().ToString().c_str()); + TC_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcode: object (%s) is considered pet-like but doesn't have a charminfo!", pet->GetGUID().ToString().c_str()); return; } if (pet->IsPet()) - ((Pet*)pet)->ToggleAutocast(spellInfo, state != 0); + pet->ToPet()->ToggleAutocast(spellInfo, packet.AutocastEnabled); else - pet->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, state != 0); + charmInfo->ToggleCreatureAutocast(spellInfo, packet.AutocastEnabled); - charmInfo->SetSpellAutocast(spellInfo, state != 0); + charmInfo->SetSpellAutocast(spellInfo, packet.AutocastEnabled); } void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell) @@ -724,19 +719,22 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petCastSpell.Cast.SpellID); if (!spellInfo) { - TC_LOG_ERROR("network", "WORLD: unknown PET spell id %i", petCastSpell.Cast.SpellID); + TC_LOG_ERROR("network", "WorldSession::HandlePetCastSpellOpcode: unknown spell id %i tried to cast by %s", + petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString().c_str()); + return; + } + + Unit* caster = ObjectAccessor::GetUnit(*_player, petCastSpell.PetGUID); + if (!caster) + { + TC_LOG_ERROR("network", "WorldSession::HandlePetCastSpellOpcode: Caster %s not found.", petCastSpell.PetGUID.ToString().c_str()); return; } // This opcode is also sent from charmed and possessed units (players and creatures) - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - Unit* caster = ObjectAccessor::GetUnit(*_player, petCastSpell.PetGUID); - - if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) + if (caster != _player->GetGuardianPet() && caster != _player->GetCharm()) { - TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: %s isn't pet of player %s (%s).", petCastSpell.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); + TC_LOG_ERROR("network", "WorldSession::HandlePetCastSpellOpcode: %s isn't pet of player %s (%s).", petCastSpell.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); return; } diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index 1eb41790072..803b956b4ee 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -31,3 +31,10 @@ void WorldPackets::Pet::PetStopAttack::Read() { _worldPacket >> PetGUID; } + +void WorldPackets::Pet::PetSpellAutocast::Read() +{ + _worldPacket >> PetGUID; + _worldPacket >> SpellID; + AutocastEnabled = _worldPacket.ReadBit(); +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 2afd5383afa..5b80d4c7da0 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -54,6 +54,18 @@ namespace WorldPackets ObjectGuid PetGUID; }; + + class PetSpellAutocast final : public ClientPacket + { + public: + PetSpellAutocast(WorldPacket&& packet) : ClientPacket(CMSG_PET_SPELL_AUTOCAST, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGUID; + uint32 SpellID; + bool AutocastEnabled; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index d68887ac20f..6ec00cd721e 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -572,7 +572,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::PetCastSpell, &WorldSession::HandlePetCastSpellOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_RENAME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_SET_ACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSetAction ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_SPELL_AUTOCAST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSpellAutocastOpcode ); + DEFINE_HANDLER(CMSG_PET_SPELL_AUTOCAST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Pet::PetSpellAutocast, &WorldSession::HandlePetSpellAutocastOpcode); DEFINE_HANDLER(CMSG_PET_STOP_ATTACK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Pet::PetStopAttack, &WorldSession::HandlePetStopAttack); DEFINE_HANDLER(CMSG_PING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_PLAYER_LOGIN, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::PlayerLogin, &WorldSession::HandlePlayerLoginOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 38d66935539..cea0b454a01 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -482,6 +482,7 @@ namespace WorldPackets class DismissCritter; class PetAbandon; class PetStopAttack; + class PetSpellAutocast; } namespace Petition @@ -1453,7 +1454,7 @@ class WorldSession void HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet); void HandlePetRename(WorldPacket& recvData); void HandlePetCancelAuraOpcode(WorldPackets::Spells::PetCancelAura& packet); - void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); + void HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutocast& packet); void HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell); void HandleSetActionBarToggles(WorldPackets::Character::SetActionBarToggles& packet); From 229322d4d80ea2c5a6bb7ac91e5008038f4c44ed Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 17:18:47 +0100 Subject: [PATCH 15/79] Core/PacketIO: Updated and enabled CMSG_PUSH_QUEST_TO_PARTY --- src/server/game/Handlers/QuestHandler.cpp | 13 ++++--------- src/server/game/Server/Packets/QuestPackets.cpp | 5 +++++ src/server/game/Server/Packets/QuestPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 83369002096..78fe8f7661b 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -543,17 +543,12 @@ void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/) { } -void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) +void WorldSession::HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty& packet) { - uint32 questId; - recvPacket >> questId; - - if (!_player->CanShareQuest(questId)) + if (!_player->CanShareQuest(packet.QuestID)) return; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_PUSHQUESTTOPARTY questId = %u", questId); - - Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID); if (!quest) return; @@ -576,7 +571,7 @@ void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) continue; } - if (receiver->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + if (receiver->GetQuestStatus(packet.QuestID) == QUEST_STATUS_COMPLETE) { sender->SendPushToPartyResponse(receiver, QUEST_PUSH_ALREADY_DONE); continue; diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp index 371da76570c..f7604e864d3 100644 --- a/src/server/game/Server/Packets/QuestPackets.cpp +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -538,3 +538,8 @@ WorldPacket const* WorldPackets::Quest::QuestGiverQuestFailed::Write() return &_worldPacket; } + +void WorldPackets::Quest::PushQuestToParty::Read() +{ + _worldPacket >> QuestID; +} diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index b509bcc94af..82920d6baa4 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -548,6 +548,16 @@ namespace WorldPackets uint32 QuestID = 0; uint32 Reason = 0; }; + + class PushQuestToParty final : public ClientPacket + { + public: + PushQuestToParty(WorldPacket&& packet) : ClientPacket(CMSG_PUSH_QUEST_TO_PARTY, std::move(packet)) { } + + void Read() override; + + uint32 QuestID; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 6ec00cd721e..1c3af2d4fde 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -577,7 +577,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_PING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_PLAYER_LOGIN, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::PlayerLogin, &WorldSession::HandlePlayerLoginOpcode); DEFINE_HANDLER(CMSG_PROTOCOL_MISMATCH, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PUSH_QUEST_TO_PARTY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePushQuestToParty ); + DEFINE_HANDLER(CMSG_PUSH_QUEST_TO_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::PushQuestToParty, &WorldSession::HandlePushQuestToParty); DEFINE_HANDLER(CMSG_PVP_LOG_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::PVPLogDataRequest, &WorldSession::HandlePVPLogDataOpcode); DEFINE_HANDLER(CMSG_QUERY_BATTLE_PET_NAME, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_QUERY_CORPSE_LOCATION_FROM_CLIENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::QueryCorpseLocationFromClient, &WorldSession::HandleQueryCorpseLocation); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index cea0b454a01..2b35cb6aa79 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -529,6 +529,7 @@ namespace WorldPackets class QuestGiverAcceptQuest; class QuestLogRemoveQuest; class QuestPushResult; + class PushQuestToParty; } namespace RaF @@ -1397,7 +1398,7 @@ class WorldSession void HandleQuestConfirmAccept(WorldPackets::Quest::QuestConfirmAccept& packet); void HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiverCompleteQuest& packet); void HandleQuestgiverQuestAutoLaunch(WorldPacket& recvPacket); - void HandlePushQuestToParty(WorldPacket& recvPacket); + void HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty& packet); void HandleQuestPushResult(WorldPackets::Quest::QuestPushResult& packet); void HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& chatMessage); From ea3cfa91469f6d55b792f761ca22e4d836769456 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 17:30:19 +0100 Subject: [PATCH 16/79] Core/PacketIO: Initialize some vars --- src/server/game/Server/Packets/PetPackets.h | 4 ++-- src/server/game/Server/Packets/QuestPackets.h | 2 +- src/server/game/Server/Packets/SpellPackets.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 5b80d4c7da0..95e70140234 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -63,8 +63,8 @@ namespace WorldPackets void Read() override; ObjectGuid PetGUID; - uint32 SpellID; - bool AutocastEnabled; + uint32 SpellID = 0; + bool AutocastEnabled = false; }; } } diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index 82920d6baa4..ff5835047b5 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -556,7 +556,7 @@ namespace WorldPackets void Read() override; - uint32 QuestID; + uint32 QuestID = 0; }; } } diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 1a6cb9bc60b..adcdcdc99b2 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -80,7 +80,7 @@ namespace WorldPackets void Read() override; ObjectGuid PetGUID; - uint32 SpellID; + uint32 SpellID = 0; }; class RequestCategoryCooldowns final : public ClientPacket From fd162fb6046ba399d12f71a69905dbc3503ae58e Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 18:04:36 +0100 Subject: [PATCH 17/79] Core/PacketIO: Add CMSG_REQUEST_PET_INFO packet class for further usage --- src/server/game/Handlers/MiscHandler.cpp | 7 ------- src/server/game/Handlers/PetHandler.cpp | 4 ++++ src/server/game/Server/Packets/PetPackets.h | 8 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index a51b61050ee..8c53837ebc5 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -988,13 +988,6 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff } } -void WorldSession::HandleRequestPetInfoOpcode(WorldPacket& /*recvData */) -{ - /* - recvData.hexlike(); - */ -} - void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket& recvData) { uint8 mode; diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 32d988179c2..ae093c4f33e 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -55,6 +55,10 @@ void WorldSession::HandleDismissCritter(WorldPackets::Pet::DismissCritter& packe } } +void WorldSession::HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& /*recvData */) +{ +} + void WorldSession::HandlePetAction(WorldPacket& recvData) { ObjectGuid guid1; diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 95e70140234..04af0d2bdd3 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -35,6 +35,14 @@ namespace WorldPackets ObjectGuid CritterGUID; }; + class RequestPetInfo final : public ClientPacket + { + public: + RequestPetInfo(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PET_INFO, std::move(packet)) { } + + void Read() override { } + }; + class PetAbandon final : public ClientPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 1c3af2d4fde..d3c60ba4358 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -637,7 +637,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_LFG_LIST_BLACKLIST, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_REQUEST_PARTY_JOIN_UPDATES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyJoinUpdates, &WorldSession::HandleRequestPartyJoinUpdates); DEFINE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyMemberStats, &WorldSession::HandleRequestPartyMemberStatsOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode ); + DEFINE_HANDLER(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Pet::RequestPetInfo, &WorldSession::HandleRequestPetInfo); DEFINE_HANDLER(CMSG_REQUEST_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::RequestPlayedTime, &WorldSession::HandlePlayedTime); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PVP_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestPvpReward ); DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 2b35cb6aa79..1a0188338cf 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -480,6 +480,7 @@ namespace WorldPackets namespace Pet { class DismissCritter; + class RequestPetInfo; class PetAbandon; class PetStopAttack; class PetSpellAutocast; @@ -1533,7 +1534,7 @@ class WorldSession void HandleSelfResOpcode(WorldPackets::Spells::SelfRes& packet); void HandleComplainOpcode(WorldPacket& recvData); - void HandleRequestPetInfoOpcode(WorldPacket& recvData); + void HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& packet); // Socket gem void HandleSocketGems(WorldPackets::Item::SocketGems& socketGems); From 46addc21cda6efa706ee454596b5ccae9b2e69d2 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 18:30:34 +0100 Subject: [PATCH 18/79] Core/PacketIO: Updated and enabled CMSG_REQUEST_PVP_REWARDS --- src/server/game/Handlers/BattleGroundHandler.cpp | 2 +- src/server/game/Handlers/PetHandler.cpp | 2 +- src/server/game/Server/Packets/BattlegroundPackets.h | 8 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index c37928d32ad..0b1b7ef667c 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -640,7 +640,7 @@ void WorldSession::HandleGetPVPOptionsEnabled(WorldPackets::Battleground::GetPVP SendPacket(pvpOptionsEnabled.Write()); } -void WorldSession::HandleRequestPvpReward(WorldPacket& /*recvData*/) +void WorldSession::HandleRequestPvpReward(WorldPackets::Battleground::RequestPVPRewards& /*packet*/) { _player->SendPvpRewards(); } diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index ae093c4f33e..6f62fc7cd5a 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -55,7 +55,7 @@ void WorldSession::HandleDismissCritter(WorldPackets::Pet::DismissCritter& packe } } -void WorldSession::HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& /*recvData */) +void WorldSession::HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& /*packet */) { } diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h index 7d9c6017db8..f0213a126c0 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.h +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -378,6 +378,14 @@ namespace WorldPackets ObjectGuid Guid; }; + + class RequestPVPRewards final : public ClientPacket + { + public: + RequestPVPRewards(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PVP_REWARDS, std::move(packet)) { } + + void Read() override { } + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index d3c60ba4358..e35cfef1930 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -639,7 +639,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyMemberStats, &WorldSession::HandleRequestPartyMemberStatsOpcode); DEFINE_HANDLER(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Pet::RequestPetInfo, &WorldSession::HandleRequestPetInfo); DEFINE_HANDLER(CMSG_REQUEST_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::RequestPlayedTime, &WorldSession::HandlePlayedTime); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PVP_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestPvpReward ); + DEFINE_HANDLER(CMSG_REQUEST_PVP_REWARDS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::RequestPVPRewards, &WorldSession::HandleRequestPvpReward); DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRatedBattlefieldInfo); DEFINE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 1a0188338cf..03b74c792a8 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -125,6 +125,7 @@ namespace WorldPackets class GetPVPOptionsEnabled; class RequestBattlefieldStatus; class ReportPvPPlayerAFK; + class RequestPVPRewards; } namespace BattlePet @@ -1475,7 +1476,7 @@ class WorldSession void HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlayerAFK& reportPvPPlayerAFK); void HandleRequestRatedBattlefieldInfo(WorldPacket& recvData); void HandleGetPVPOptionsEnabled(WorldPackets::Battleground::GetPVPOptionsEnabled& getPvPOptionsEnabled); - void HandleRequestPvpReward(WorldPacket& recvData); + void HandleRequestPvpReward(WorldPackets::Battleground::RequestPVPRewards& packet); void HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery& areaSpiritHealerQuery); void HandleAreaSpiritHealerQueueOpcode(WorldPackets::Battleground::AreaSpiritHealerQueue& areaSpiritHealerQueue); void HandleHearthAndResurrect(WorldPackets::Battleground::HearthAndResurrect& hearthAndResurrect); From db0b8bf24e2b8eb87e6aed7b031ebe138717403d Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 2 Feb 2016 19:13:04 +0100 Subject: [PATCH 19/79] Core/Maps: Changed the way area data is stored in maps, it now uses ID field from AreaTable.dbc instead AreaBit used for exploration marker (and is not unique anymore on top of simply being stupidly confusing) Note: Extracting maps is required --- .../game/AI/SmartScripts/SmartScriptMgr.cpp | 2 +- .../game/Achievements/AchievementMgr.cpp | 13 +-- src/server/game/Chat/Chat.cpp | 4 +- src/server/game/Conditions/ConditionMgr.cpp | 11 +-- src/server/game/DataStores/DBCStores.cpp | 66 ++------------- src/server/game/DataStores/DBCStores.h | 8 +- src/server/game/DataStores/DBCfmt.h | 2 +- src/server/game/Entities/Player/Player.cpp | 46 +++++------ src/server/game/Globals/ObjectMgr.cpp | 6 +- .../game/Handlers/BattleGroundHandler.cpp | 2 +- src/server/game/Handlers/ChannelHandler.cpp | 2 +- src/server/game/Handlers/MiscHandler.cpp | 2 +- src/server/game/Loot/LootMgr.cpp | 4 +- src/server/game/Maps/Map.cpp | 81 +++++++++---------- src/server/game/Maps/Map.h | 26 ++---- src/server/game/Maps/MapManager.h | 14 ++-- src/server/game/OutdoorPvP/OutdoorPvP.cpp | 2 +- src/server/game/Spells/Spell.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 4 +- src/server/game/Spells/SpellMgr.cpp | 2 +- src/server/scripts/Commands/cs_go.cpp | 4 +- src/server/scripts/Commands/cs_group.cpp | 4 +- src/server/scripts/Commands/cs_lookup.cpp | 8 +- src/server/scripts/Commands/cs_misc.cpp | 56 +++++++++---- src/tools/map_extractor/System.cpp | 58 +++---------- src/tools/mmaps_generator/TerrainBuilder.cpp | 2 +- 26 files changed, 168 insertions(+), 263 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 9796464e821..b02906a7164 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -469,7 +469,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); return false; } - if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area)) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); return false; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 7c9739217d2..6462c89a694 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -2275,17 +2275,18 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteria const* achieve bool matchFound = false; for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) { - uint32 area_id = worldOverlayEntry->AreaID[j]; - if (!area_id) // array have 0 only in empty tail + AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->AreaID[j]); + if (!area) break; - int32 exploreFlag = GetAreaFlagByAreaID(area_id); - if (exploreFlag < 0) + if (area->AreaBit < 0) continue; - uint32 playerIndexOffset = uint32(exploreFlag) / 32; - uint32 mask = 1 << (uint32(exploreFlag) % 32); + uint32 playerIndexOffset = uint32(area->AreaBit) / 32; + if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE) + continue; + uint32 mask = 1 << (uint32(area->AreaBit) % 32); if (referencePlayer->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) { matchFound = true; diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 89d871137f2..07e77a4e6a3 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -297,10 +297,10 @@ bool ChatHandler::ExecuteCommandInTable(std::vector const& table, c uint32 areaId = player->GetAreaId(); std::string areaName = "Unknown"; std::string zoneName = "Unknown"; - if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) { areaName = area->AreaName_lang; - if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID)) + if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID)) zoneName = zone->AreaName_lang; } diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index ff08b5ea7e8..ed3ae7cb8e5 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1768,7 +1768,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const } case CONDITION_SOURCE_TYPE_PHASE: { - if (cond->SourceEntry && !GetAreaEntryByAreaID(cond->SourceEntry)) + if (cond->SourceEntry && !sAreaTableStore.LookupEntry(cond->SourceEntry)) { TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in AreaTable.dbc, ignoring.", cond->ToString().c_str()); return false; @@ -1845,7 +1845,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_ZONEID: { - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1); if (!areaEntry) { TC_LOG_ERROR("sql.sql", "%s Area (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); @@ -2592,12 +2592,9 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player* player, PlayerConditionEntry for (std::size_t i = 0; i < ExploredCount::value; ++i) { - if (condition->Explored[i]) - { - int32 exploreFlag = GetAreaFlagByAreaID(condition->Explored[i]); - if (exploreFlag != -1 && !(player->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + exploreFlag / 32) & (1 << (uint32(exploreFlag) % 32)))) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(condition->Explored[i])) + if (area->AreaBit != -1 && !(player->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + area->AreaBit / 32) & (1 << (uint32(area->AreaBit) % 32)))) return false; - } } } diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 2bf38bdc769..b1a8a1179c6 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -44,16 +44,12 @@ struct WMOAreaTableTripple int32 adtId; }; -typedef std::map AreaFlagByAreaID; -typedef std::map AreaFlagByMapID; typedef std::multimap CharSectionsMap; typedef std::map> FactionTeamMap; typedef std::map WMOAreaInfoByTripple; DBCStorage sAnimKitStore(AnimKitfmt); -DBCStorage sAreaStore(AreaTablefmt); -static AreaFlagByAreaID sAreaFlagByAreaID; -static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files +DBCStorage sAreaTableStore(AreaTablefmt); DBCStorage sAreaTriggerStore(AreaTriggerfmt); DBCStorage sArmorLocationStore(ArmorLocationfmt); @@ -298,7 +294,7 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale) #define LOAD_DBC(store, file) LoadDBC(availableDbcLocales, bad_dbc_files, store, dbcPath, file, defaultLocale) LOAD_DBC(sAnimKitStore, "AnimKit.dbc");//20444 - LOAD_DBC(sAreaStore, "AreaTable.dbc");//20444 + LOAD_DBC(sAreaTableStore, "AreaTable.dbc");//20444 LOAD_DBC(sAreaTriggerStore, "AreaTrigger.dbc");//20444 LOAD_DBC(sArmorLocationStore, "ArmorLocation.dbc");//20444 LOAD_DBC(sBankBagSlotPricesStore, "BankBagSlotPrices.dbc");//20444 @@ -382,20 +378,6 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale) #undef LOAD_DBC - // must be after sAreaStore loading - for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0 - { - if (AreaTableEntry const* area = sAreaStore.LookupEntry(i)) - { - // fill AreaId->DBC records - sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->AreaBit)); - - // fill MapId->DBC records (skip sub zones and continents) - if (area->ParentAreaID == 0) - sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->MapID, area->AreaBit)); - } - } - for (uint32 i = 0; i < sCharSectionsStore.GetNumRows(); ++i) if (CharSectionsEntry const* entry = sCharSectionsStore.LookupEntry(i)) if (entry->Race && ((1 << (entry->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) //ignore Nonplayable races @@ -494,7 +476,7 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale) } // Check loaded DBC files proper version - if (!sAreaStore.LookupEntry(6565) || // last area (areaflag) added in 6.2.2 (20444) + if (!sAreaTableStore.LookupEntry(7941) || // last area added in 6.2.2 (20444) !sCharTitlesStore.LookupEntry(457) || // last char title added in 6.2.2 (20444) !sGemPropertiesStore.LookupEntry(2544) || // last gem property added in 6.2.2 (20444) !sMapStore.LookupEntry(1497) || // last map added in 6.2.2 (20444) @@ -580,41 +562,12 @@ char const* GetCreatureFamilyPetName(uint32 petfamily, uint32 /*locale*/) return pet_family->Name_lang ? pet_family->Name_lang : NULL; } -int32 GetAreaFlagByAreaID(uint32 area_id) -{ - AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id); - if (i == sAreaFlagByAreaID.end()) - return -1; - - return i->second; -} - WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid) { WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid)); - if (i == sWMOAreaInfoByTripple.end()) - return NULL; - return i->second; -} - -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id) -{ - int32 areaflag = GetAreaFlagByAreaID(area_id); - if (areaflag < 0) + if (i == sWMOAreaInfoByTripple.end()) return NULL; - - return sAreaStore.LookupEntry(areaflag); -} - -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id) -{ - if (area_flag) - return sAreaStore.LookupEntry(area_flag); - - if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id)) - return GetAreaEntryByAreaID(mapEntry->AreaTableID); - - return NULL; + return i->second; } char const* GetRaceName(uint8 race, uint8 /*locale*/) @@ -629,15 +582,6 @@ char const* GetClassName(uint8 class_, uint8 /*locale*/) return classEntry ? classEntry->Name_lang : NULL; } -uint32 GetAreaFlagByMapId(uint32 mapid) -{ - AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid); - if (i == sAreaFlagByMapID.end()) - return 0; - else - return i->second; -} - uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId) { if (mapid != 530 && mapid != 571 && mapid != 732) // speed for most cases diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 017f641fb18..d8af7418be4 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -24,12 +24,6 @@ #include "DB2Structure.h" #include "SharedDefines.h" -// AreaTable -int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id); -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id); -uint32 GetAreaFlagByMapId(uint32 mapid); - // CharSections CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color); @@ -128,7 +122,7 @@ private: }; extern DBCStorage sAnimKitStore; -extern DBCStorage sAreaStore;// recommend access using functions +extern DBCStorage sAreaTableStore; extern DBCStorage sAreaTriggerStore; extern DBCStorage sArmorLocationStore; extern DBCStorage sBankBagSlotPricesStore; diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index ce378ea5d43..d52891576da 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -23,7 +23,7 @@ // n - index (included), l - uint64, p - field present in sql dbc, a - field absent in sql dbc char const AnimKitfmt[] = "nxxx"; -char const AreaTablefmt[] = "iiiniixxxxxxisiiiiixxxxxxxxxx"; +char const AreaTablefmt[] = "niiiiixxxxxxisiiiiixxxxxxxxxx"; char const AreaTriggerfmt[] = "nifffxxxfffffxxxx"; char const ArmorLocationfmt[] = "nfffff"; char const BankBagSlotPricesfmt[] = "ni"; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 82c5bb27e5c..906ee2628ef 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4618,7 +4618,7 @@ void Player::RepopAtGraveyard() // note: this can be called also when the player is alive // for example from WorldSession::HandleMovementOpcodes - AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId()); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId()); // Such zones are considered unreachable as a ghost and the player must be automatically revived if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < MAX_MAP_DEPTH) @@ -4702,7 +4702,7 @@ void Player::UpdateLocalChannels(uint32 newZone) if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar()) return; // The client handles it automatically after loading, but not after teleporting - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone); + AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone); if (!current_zone) return; @@ -5900,23 +5900,32 @@ void Player::CheckAreaExploreAndOutdoor() return; bool isOutdoor; - uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); + uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor) RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY); - if (areaFlag == 0xffff) + if (!areaId) return; - int offset = areaFlag / 32; + + if (!areaEntry) + { + TC_LOG_ERROR("entities.player", "Player '%s' (%s) discovered unknown area (x: %f y: %f z: %f map: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); + return; + } + + uint32 offset = areaEntry->AreaBit / 32; if (offset >= PLAYER_EXPLORED_ZONES_SIZE) { TC_LOG_ERROR("entities.player", "Player::CheckAreaExploreAndOutdoor: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", - areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE); + areaId, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE); return; } - uint32 val = (uint32)(1 << (areaFlag % 32)); + uint32 val = (uint32)(1 << (areaEntry->AreaBit % 32)); uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); if (!(currFields & val)) @@ -5925,20 +5934,11 @@ void Player::CheckAreaExploreAndOutdoor() UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId()); - if (!areaEntry) - { - TC_LOG_ERROR("entities.player", "Player '%s' (%s) discovered unknown area (x: %f y: %f z: %f map: %u)", - GetName().c_str(), GetGUID().ToString().c_str(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); - return; - } - if (areaEntry->ExplorationLevel > 0) { - uint32 area = areaEntry->ID; if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { - SendExplorationExperience(area, 0); + SendExplorationExperience(areaId, 0); } else { @@ -5962,9 +5962,9 @@ void Player::CheckAreaExploreAndOutdoor() } GiveXP(XP, nullptr); - SendExplorationExperience(area, XP); + SendExplorationExperience(areaId, XP); } - TC_LOG_DEBUG("entities.player", "Player '%s' (%s) discovered a new area: %u", GetName().c_str(),GetGUID().ToString().c_str(), area); + TC_LOG_DEBUG("entities.player", "Player '%s' (%s) discovered a new area: %u", GetName().c_str(),GetGUID().ToString().c_str(), areaId); } } } @@ -6871,7 +6871,7 @@ void Player::UpdateArea(uint32 newArea) // so apply them accordingly m_areaUpdateId = newArea; - AreaTableEntry const* area = GetAreaEntryByAreaID(newArea); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea); pvpInfo.IsInFFAPvPArea = area && (area->Flags[0] & AREA_FLAG_ARENA); UpdatePvPState(true); @@ -6923,7 +6923,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // zone changed, so area changed as well, update it UpdateArea(newArea); - AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone); if (!zone) return; @@ -25826,10 +25826,10 @@ std::string Player::GetMapAreaAndZoneString() const uint32 areaId = GetAreaId(); std::string areaName = "Unknown"; std::string zoneName = "Unknown"; - if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) { areaName = area->AreaName_lang; - if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID)) + if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID)) zoneName = zone->AreaName_lang; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index d07ed98d2b3..43c76564ae4 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3928,7 +3928,7 @@ void ObjectMgr::LoadQuests() // client quest log visual (area case) if (qinfo->QuestSortID > 0) { - if (!GetAreaEntryByAreaID(qinfo->QuestSortID)) + if (!sAreaTableStore.LookupEntry(qinfo->QuestSortID)) { TC_LOG_ERROR("sql.sql", "Quest %u has `QuestSortID` = %u (zone case) but zone with this id does not exist.", qinfo->GetQuestId(), qinfo->QuestSortID); @@ -5857,7 +5857,7 @@ void ObjectMgr::LoadGraveyardZones() continue; } - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId); if (!areaEntry) { TC_LOG_ERROR("sql.sql", "Table `graveyard_zone` has a record for non-existing Zone (ID: %u), skipped.", zoneId); @@ -7753,7 +7753,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel() uint32 entry = fields[0].GetUInt32(); int32 skill = fields[1].GetInt16(); - AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); + AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry); if (!fArea) { TC_LOG_ERROR("sql.sql", "AreaId %u defined in `skill_fishing_base_level` does not exist", entry); diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 0b1b7ef667c..90e36ee65c0 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -688,7 +688,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPackets::Battleground::HearthAn return; } - AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); + AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId()); if (!atEntry || !(atEntry->Flags[0] & AREA_FLAG_CAN_HEARTH_AND_RESURRECT)) return; diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp index 09569e833d1..344592580cf 100644 --- a/src/server/game/Handlers/ChannelHandler.cpp +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -35,7 +35,7 @@ void WorldSession::HandleJoinChannel(WorldPackets::Channel::JoinChannel& packet) if (!channel) return; - AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId()); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId()); if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone)) return; } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 8c53837ebc5..a5ab144d319 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -197,7 +197,7 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) if (!wWords.empty()) { std::string aName; - if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(target->GetZoneId())) + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(target->GetZoneId())) aName = areaEntry->AreaName_lang; bool show = false; diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index bbeb2ce3040..e57bf681b8a 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1586,8 +1586,8 @@ void LoadLootTemplates_Fishing() uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet); // remove real entries and check existence loot - for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i) - if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i)) + for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i) + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i)) if (lootIdSet.find(areaEntry->ID) != lootIdSet.end()) lootIdSet.erase(areaEntry->ID); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index d1bc8a278c4..510d678821b 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -40,7 +40,7 @@ #include "Weather.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','5'} }; +u_map_magic MapVersionMagic = { {'v','1','.','6'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1757,7 +1757,7 @@ bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/) _gridArea = header.gridArea; if (!(header.flags & MAP_AREA_NO_AREA)) { - _areaMap = new uint16 [16*16]; + _areaMap = new uint16[16 * 16]; if (fread(_areaMap, sizeof(uint16), 16*16, in) != 16*16) return false; } @@ -2136,12 +2136,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R uint32 liqTypeIdx = liquidEntry->Type; if (entry < 21) { - if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) { uint32 overrideLiquid = area->LiquidTypeID[liquidEntry->Type]; if (!overrideLiquid && area->ParentAreaID) { - area = GetAreaEntryByAreaID(area->ParentAreaID); + area = sAreaTableStore.LookupEntry(area->ParentAreaID); if (area) overrideLiquid = area->LiquidTypeID[liquidEntry->Type]; } @@ -2315,7 +2315,7 @@ bool Map::IsOutdoors(float x, float y, float z) const if (wmoEntry) { TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->AreaTableID); - atEntry = GetAreaEntryByAreaID(wmoEntry->AreaTableID); + atEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); } return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); } @@ -2339,7 +2339,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in return false; } -uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const +uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const { uint32 mogpFlags; int32 adtId, rootId, groupId; @@ -2352,20 +2352,20 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const haveAreaInfo = true; wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); if (wmoEntry) - atEntry = GetAreaEntryByAreaID(wmoEntry->AreaTableID); + atEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); } - uint16 areaflag; + uint32 areaId; if (atEntry) - areaflag = atEntry->AreaBit; + areaId = atEntry->ID; else { if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) - areaflag = gmap->getArea(x, y); + areaId = gmap->getArea(x, y); // this used while not all *.map files generated (instances) else - areaflag = GetAreaFlagByMapId(i_mapEntry->ID); + areaId = i_mapEntry->AreaTableID; } if (isOutdoors) @@ -2375,8 +2375,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const else *isOutdoors = true; } - return areaflag; - } + return areaId; +} + +uint32 Map::GetAreaId(float x, float y, float z) const +{ + return GetAreaId(x, y, z, nullptr); +} + +uint32 Map::GetZoneId(float x, float y, float z) const +{ + uint32 areaId = GetAreaId(x, y, z); + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) + if (area->ParentAreaID) + return area->ParentAreaID; + + return areaId; +} + +void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const +{ + areaid = zoneid = GetAreaId(x, y, z); + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid)) + if (area->ParentAreaID) + zoneid = area->ParentAreaID; +} uint8 Map::GetTerrainType(float x, float y) const { @@ -2412,12 +2435,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp if (liquid_type && liquid_type < 21) { - if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId())) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z))) { uint32 overrideLiquid = area->LiquidTypeID[liquidFlagType]; if (!overrideLiquid && area->ParentAreaID) { - area = GetAreaEntryByAreaID(area->ParentAreaID); + area = sAreaTableStore.LookupEntry(area->ParentAreaID); if (area) overrideLiquid = area->LiquidTypeID[liquidFlagType]; } @@ -2479,34 +2502,6 @@ float Map::GetWaterLevel(float x, float y) const return 0; } -uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - if (entry) - return entry->ID; - else - return 0; -} - -uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - if (entry) - return (entry->ParentAreaID != 0) ? entry->ParentAreaID : entry->ID; - else - return 0; -} - -void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - areaid = entry ? entry->ID : 0; - zoneid = entry ? ((entry->ParentAreaID != 0) ? entry->ParentAreaID : entry->ID) : 0; -} - bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const { return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 3ee28f69f12..bf8770cfd30 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -332,8 +332,11 @@ class Map : public GridRefManager ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; - uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=nullptr) const; - bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; + uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const; + bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; + uint32 GetAreaId(float x, float y, float z) const; + uint32 GetZoneId(float x, float y, float z) const; + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const; bool IsOutdoors(float x, float y, float z) const; @@ -342,25 +345,6 @@ class Map : public GridRefManager bool IsInWater(float x, float y, float z, LiquidData* data = nullptr) const; bool IsUnderWater(float x, float y, float z) const; - static uint32 GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id); - static uint32 GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id); - static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id); - - uint32 GetAreaId(float x, float y, float z) const - { - return GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); - } - - uint32 GetZoneId(float x, float y, float z) const - { - return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); - } - - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const - { - GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId()); - } - void MoveAllCreaturesInMoveList(); void MoveAllGameObjectsInMoveList(); void MoveAllDynamicObjectsInMoveList(); diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 086277448a8..c0811e7fecc 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -42,22 +42,20 @@ class MapManager Map* CreateMap(uint32 mapId, Player* player); Map* FindMap(uint32 mapId, uint32 instanceId) const; - uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const - { - Map const* m = const_cast(this)->CreateBaseMap(mapid); - return m->GetAreaFlag(x, y, z); - } uint32 GetAreaId(uint32 mapid, float x, float y, float z) const { - return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast(this)->CreateBaseMap(mapid); + return m->GetAreaId(x, y, z); } uint32 GetZoneId(uint32 mapid, float x, float y, float z) const { - return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast(this)->CreateBaseMap(mapid); + return m->GetZoneId(x, y, z); } void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) { - Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast(this)->CreateBaseMap(mapid); + m->GetZoneAndAreaId(zoneid, areaid, x, y, z); } void Initialize(void); diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index d10b196f08d..4f05c1871aa 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -650,7 +650,7 @@ void OutdoorPvP::BroadcastWorker(Worker& _worker, uint32 zoneId) void OutdoorPvP::SetMapFromZone(uint32 zone) { - AreaTableEntry const* areaTable = GetAreaEntryByAreaID(zone); + AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(zone); ASSERT(areaTable); Map* map = sMapMgr->CreateBaseMap(areaTable->MapID); ASSERT(!map->Instanceable()); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0be2fed3424..1cef132fcda 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5501,7 +5501,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive()) { Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId()); - if (AreaTableEntry const* area = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId())) if (area->Flags[0] & AREA_FLAG_NO_FLY_ZONE || (Bf && !Bf->CanFlyIn())) return (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d014119f00c..a43c30917b4 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3866,14 +3866,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; // Players can only fight a duel in zones with this flag - AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId()); + AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId()); if (casterAreaEntry && !(casterAreaEntry->Flags[0] & AREA_FLAG_ALLOW_DUELS)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here return; } - AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId()); + AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId()); if (targetAreaEntry && !(targetAreaEntry->Flags[0] & AREA_FLAG_ALLOW_DUELS)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index dd73c261853..a628e934465 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2625,7 +2625,7 @@ void SpellMgr::LoadSpellAreas() } } - if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId)) + if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId)) { TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId); continue; diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 0995746b4b0..081280532fb 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -487,7 +487,7 @@ public: uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId(); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry) { @@ -497,7 +497,7 @@ public: } // update to parent zone if exist (client map show only zones without parents) - AreaTableEntry const* zoneEntry = areaEntry->ParentAreaID ? GetAreaEntryByAreaID(areaEntry->ParentAreaID) : areaEntry; + AreaTableEntry const* zoneEntry = areaEntry->ParentAreaID ? sAreaTableStore.LookupEntry(areaEntry->ParentAreaID) : areaEntry; ASSERT(zoneEntry); Map const* map = sMapMgr->CreateBaseMap(zoneEntry->MapID); diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index 77a157443b8..33356409f17 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -347,10 +347,10 @@ public: onlineState = "online"; phase = (!p->IsGameMaster() ? p->GetPhaseMask() : -1); - AreaTableEntry const* area = GetAreaEntryByAreaID(p->GetAreaId()); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(p->GetAreaId()); if (area) { - AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID); if (zone) zoneName = zone->AreaName_lang; } diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 847634637b0..57bf557771b 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -97,9 +97,9 @@ public: wstrToLower(wNamePart); // Search in AreaTable.dbc - for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag) + for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i) { - AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i); if (areaEntry) { std::string name = areaEntry->AreaName_lang; @@ -118,9 +118,9 @@ public: // send area in "id - [name]" format std::ostringstream ss; if (handler->GetSession()) - ss << areaEntry->ID << " - |cffffffff|Harea:" << areaEntry->ID << "|h[" << name<< "]|h|r"; + ss << i << " - |cffffffff|Harea:" << i << "|h[" << name<< "]|h|r"; else - ss << areaEntry->ID << " - " << name; + ss << i << " - " << name; handler->SendSysMessage(ss.str().c_str()); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 778eaaf44f1..0e9e8aecfec 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -201,8 +201,8 @@ public: uint32 mapId = object->GetMapId(); MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); - AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); float zoneX = object->GetPositionX(); float zoneY = object->GetPositionY(); @@ -988,7 +988,7 @@ public: uint32 zoneId = player->GetZoneId(); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId); if (!areaEntry || areaEntry->ParentAreaID !=0) { handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId); @@ -1079,17 +1079,30 @@ public: return false; } - int32 area = GetAreaFlagByAreaID(atoi((char*)args)); - int32 offset = area / 32; - - if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + if (!area) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } - uint32 val = uint32((1 << (area % 32))); + if (area->AreaBit < 0) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + int32 offset = area->AreaBit / 32; + if (offset >= PLAYER_EXPLORED_ZONES_SIZE) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + uint32 val = uint32((1 << (area->AreaBit % 32))); uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val))); @@ -1110,17 +1123,30 @@ public: return false; } - int32 area = GetAreaFlagByAreaID(atoi((char*)args)); - int32 offset = area / 32; - - if (area < 0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + if (!area) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } - uint32 val = uint32((1 << (area % 32))); + if (area->AreaBit < 0) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + int32 offset = area->AreaBit / 32; + if (offset >= PLAYER_EXPLORED_ZONES_SIZE) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + uint32 val = uint32((1 << (area->AreaBit % 32))); uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val))); @@ -1787,12 +1813,12 @@ public: // Position data MapEntry const* map = sMapStore.LookupEntry(mapId); - AreaTableEntry const* area = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId); if (area) { areaName = area->AreaName_lang; - AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID); if (zone) zoneName = zone->AreaName_lang; } diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 8de3f95f68a..2d36df68df1 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -75,12 +75,10 @@ typedef struct } map_id; map_id *map_ids; -uint16 *areas; uint16 *LiqType; #define MAX_PATH_LENGTH 128 char output_path[MAX_PATH_LENGTH]; char input_path[MAX_PATH_LENGTH]; -uint32 maxAreaId = 0; // ************************************************** // Extractor options @@ -318,35 +316,6 @@ uint32 ReadMapDBC() return map_count; } -void ReadAreaTableDBC() -{ - printf("Read AreaTable.dbc file..."); - HANDLE dbcFile; - if (!CascOpenFile(CascStorage, "DBFilesClient\\AreaTable.dbc", CASC_LOCALE_NONE, 0, &dbcFile)) - { - printf("Fatal error: Cannot find AreaTable.dbc in archive! %s\n", HumanReadableCASCError(GetLastError())); - exit(1); - } - - DBCFile dbc(dbcFile); - if(!dbc.open()) - { - printf("Fatal error: Invalid AreaTable.dbc file format!\n"); - exit(1); - } - - size_t area_count = dbc.getRecordCount(); - maxAreaId = dbc.getMaxId(); - areas = new uint16[maxAreaId + 1]; - memset(areas, 0xFF, sizeof(uint16) * (maxAreaId + 1)); - - for (uint32 x = 0; x < area_count; ++x) - areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); - - CascCloseFile(dbcFile); - printf("Done! (" SZFMTD " areas loaded)\n", area_count); -} - void ReadLiquidTypeTableDBC() { printf("Read LiquidType.dbc file..."); @@ -382,7 +351,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.5"; +static char const* MAP_VERSION_MAGIC = "v1.6"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -458,7 +427,7 @@ float selectUInt16StepStore(float maxDiff) return 65535 / maxDiff; } // Temporary grid data store -uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]; float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; @@ -502,7 +471,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int map.buildMagic = build; // Get area flags data - memset(area_flags, 0xFF, sizeof(area_flags)); + memset(area_ids, 0, sizeof(area_ids)); memset(V9, 0, sizeof(V9)); memset(V8, 0, sizeof(V8)); @@ -519,8 +488,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int adt_MCNK* mcnk = itr->second->As(); // Area data - if (mcnk->areaid <= maxAreaId && areas[mcnk->areaid] != 0xFFFF) - area_flags[mcnk->iy][mcnk->ix] = areas[mcnk->areaid]; + area_ids[mcnk->iy][mcnk->ix] = mcnk->areaid; // Height // Height values for triangles stored in order: @@ -732,12 +700,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int // Try pack area data //============================================ bool fullAreaData = false; - uint32 areaflag = area_flags[0][0]; - for (int y=0;y(areaflag); + areaHeader.gridArea = static_cast(areaId); } //============================================ @@ -966,8 +934,8 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int outFile.write(reinterpret_cast(&map), sizeof(map)); // Store area data outFile.write(reinterpret_cast(&areaHeader), sizeof(areaHeader)); - if (!(areaHeader.flags&MAP_AREA_NO_AREA)) - outFile.write(reinterpret_cast(area_flags), sizeof(area_flags)); + if (!(areaHeader.flags & MAP_AREA_NO_AREA)) + outFile.write(reinterpret_cast(area_ids), sizeof(area_ids)); // Store height data outFile.write(reinterpret_cast(&heightHeader), sizeof(heightHeader)); @@ -1042,7 +1010,6 @@ void ExtractMaps(uint32 build) uint32 map_count = ReadMapDBC(); - ReadAreaTableDBC(); ReadLiquidTypeTableDBC(); std::string path = output_path; @@ -1098,7 +1065,6 @@ void ExtractMaps(uint32 build) } printf("\n"); - delete[] areas; delete[] map_ids; } diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 209c047a5fe..33832f8986d 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.5"; + char const* MAP_VERSION_MAGIC = "v1.6"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } From a130300b861799c2fdc6ce2563d2dbde00ede0e0 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 19:45:57 +0100 Subject: [PATCH 20/79] Core/PacketIO: Updated and enabled CMSG_REQUEST_RATED_BATTLEFIELD_INFO --- src/server/game/Handlers/BattleGroundHandler.cpp | 7 +------ src/server/game/Server/Packets/BattlegroundPackets.h | 8 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 90e36ee65c0..e8fdb384d89 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -595,13 +595,8 @@ void WorldSession::HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlaye reportedPlayer->ReportedAfkBy(_player); } -void WorldSession::HandleRequestRatedBattlefieldInfo(WorldPacket& recvData) +void WorldSession::HandleRequestRatedBattlefieldInfo(WorldPackets::Battleground::RequestRatedBattlefieldInfo& /*packet*/) { - uint8 unk; - recvData >> unk; - - TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleRequestRatedBattlefieldInfo: unk = %u", unk); - /// @Todo: perfome research in this case /// The unk fields are related to arenas WorldPacket data(SMSG_RATED_BATTLEFIELD_INFO, 72); diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h index f0213a126c0..45d0bebc545 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.h +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -386,6 +386,14 @@ namespace WorldPackets void Read() override { } }; + + class RequestRatedBattlefieldInfo final : public ClientPacket + { + public: + RequestRatedBattlefieldInfo(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, std::move(packet)) { } + + void Read() override { } + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index e35cfef1930..26bc817ba80 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -641,7 +641,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::RequestPlayedTime, &WorldSession::HandlePlayedTime); DEFINE_HANDLER(CMSG_REQUEST_PVP_REWARDS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::RequestPVPRewards, &WorldSession::HandleRequestPvpReward); DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRatedBattlefieldInfo); + DEFINE_HANDLER(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::RequestRatedBattlefieldInfo, &WorldSession::HandleRequestRatedBattlefieldInfo); DEFINE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); DEFINE_HANDLER(CMSG_REQUEST_VEHICLE_EXIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RequestVehicleExit, &WorldSession::HandleRequestVehicleExit); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 03b74c792a8..f91193decc7 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -126,6 +126,7 @@ namespace WorldPackets class RequestBattlefieldStatus; class ReportPvPPlayerAFK; class RequestPVPRewards; + class RequestRatedBattlefieldInfo; } namespace BattlePet @@ -1474,7 +1475,7 @@ class WorldSession void HandleBattlefieldLeaveOpcode(WorldPackets::Battleground::BattlefieldLeave& battlefieldLeave); void HandleBattlemasterJoinArena(WorldPackets::Battleground::BattlemasterJoinArena& packet); void HandleReportPvPAFK(WorldPackets::Battleground::ReportPvPPlayerAFK& reportPvPPlayerAFK); - void HandleRequestRatedBattlefieldInfo(WorldPacket& recvData); + void HandleRequestRatedBattlefieldInfo(WorldPackets::Battleground::RequestRatedBattlefieldInfo& packet); void HandleGetPVPOptionsEnabled(WorldPackets::Battleground::GetPVPOptionsEnabled& getPvPOptionsEnabled); void HandleRequestPvpReward(WorldPackets::Battleground::RequestPVPRewards& packet); void HandleAreaSpiritHealerQueryOpcode(WorldPackets::Battleground::AreaSpiritHealerQuery& areaSpiritHealerQuery); From 20a6b54bb635d107a0de639a29be92ef4526a9be Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 20:10:33 +0100 Subject: [PATCH 21/79] Core/PacketIO: Updated and enabled CMSG_REQUEST_STABLED_PETS --- src/server/game/Handlers/NPCHandler.cpp | 11 +++-------- src/server/game/Server/Packets/NPCPackets.cpp | 5 +++++ src/server/game/Server/Packets/NPCPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index e514a1c2767..570e5b4ce48 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -465,14 +465,9 @@ void WorldSession::SendBindPoint(Creature* npc) _player->PlayerTalkClass->SendCloseGossip(); } -void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recvData) +void WorldSession::HandleRequestStabledPets(WorldPackets::NPC::RequestStabledPets& packet) { - TC_LOG_DEBUG("network", "WORLD: Recv MSG_LIST_STABLED_PETS"); - ObjectGuid npcGUID; - - recvData >> npcGUID; - - if (!CheckStableMaster(npcGUID)) + if (!CheckStableMaster(packet.StableMaster)) return; // remove fake death @@ -483,7 +478,7 @@ void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recvData) if (GetPlayer()->IsMounted()) GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); - SendStablePet(npcGUID); + SendStablePet(packet.StableMaster); } void WorldSession::SendStablePet(ObjectGuid guid) diff --git a/src/server/game/Server/Packets/NPCPackets.cpp b/src/server/game/Server/Packets/NPCPackets.cpp index 710a6df42d2..9e8090b03b2 100644 --- a/src/server/game/Server/Packets/NPCPackets.cpp +++ b/src/server/game/Server/Packets/NPCPackets.cpp @@ -191,3 +191,8 @@ WorldPacket const* WorldPackets::NPC::TrainerBuyFailed::Write() return &_worldPacket; } + +void WorldPackets::NPC::RequestStabledPets::Read() +{ + _worldPacket >> StableMaster; +} diff --git a/src/server/game/Server/Packets/NPCPackets.h b/src/server/game/Server/Packets/NPCPackets.h index d20f78f3bf2..28444e87e75 100644 --- a/src/server/game/Server/Packets/NPCPackets.h +++ b/src/server/game/Server/Packets/NPCPackets.h @@ -240,6 +240,16 @@ namespace WorldPackets int32 SpellID = 0; int32 TrainerFailedReason = 0; }; + + class RequestStabledPets final : public ClientPacket + { + public: + RequestStabledPets(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_STABLED_PETS, std::move(packet)) { } + + void Read() override; + + ObjectGuid StableMaster; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 26bc817ba80..1cc7e63a25c 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -643,7 +643,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); DEFINE_HANDLER(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::RequestRatedBattlefieldInfo, &WorldSession::HandleRequestRatedBattlefieldInfo); DEFINE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); + DEFINE_HANDLER(CMSG_REQUEST_STABLED_PETS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::RequestStabledPets, &WorldSession::HandleRequestStabledPets); DEFINE_HANDLER(CMSG_REQUEST_VEHICLE_EXIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RequestVehicleExit, &WorldSession::HandleRequestVehicleExit); DEFINE_HANDLER(CMSG_REQUEST_VEHICLE_NEXT_SEAT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RequestVehicleNextSeat, &WorldSession::HandleRequestVehicleNextSeat); DEFINE_HANDLER(CMSG_REQUEST_VEHICLE_PREV_SEAT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RequestVehiclePrevSeat, &WorldSession::HandleRequestVehiclePrevSeat); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index f91193decc7..869c2b7304f 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -436,6 +436,7 @@ namespace WorldPackets class GossipSelectOption; class SpiritHealerActivate; class TrainerBuySpell; + class RequestStabledPets; } namespace Party @@ -1296,7 +1297,7 @@ class WorldSession void HandleSpiritHealerActivate(WorldPackets::NPC::SpiritHealerActivate& packet); void HandleNpcTextQueryOpcode(WorldPackets::Query::QueryNPCText& packet); void HandleBinderActivateOpcode(WorldPackets::NPC::Hello& packet); - void HandleListStabledPetsOpcode(WorldPacket& recvPacket); + void HandleRequestStabledPets(WorldPackets::NPC::RequestStabledPets& packet); void HandleStablePet(WorldPacket& recvPacket); void HandleStablePetCallback(PreparedQueryResult result); void HandleUnstablePet(WorldPacket& recvPacket); From aa5c9475555a8febb130d98f392546a00e1ebbb2 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 20:55:48 +0100 Subject: [PATCH 22/79] Core/PacketIO: Updated and enabled CMSG_SET_PARTY_ASSIGNMENT --- src/server/game/Handlers/GroupHandler.cpp | 16 ++++------------ src/server/game/Server/Packets/PartyPackets.cpp | 9 +++++++++ src/server/game/Server/Packets/PartyPackets.h | 12 ++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 49a10b61ed5..297cd9c3124 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -524,10 +524,8 @@ void WorldSession::HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssist group->SetGroupMemberFlag(packet.Target, packet.Apply, MEMBER_FLAG_ASSISTANT); } -void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) +void WorldSession::HandleSetPartyAssignment(WorldPackets::Party::SetPartyAssignment& packet) { - TC_LOG_DEBUG("network", "WORLD: Received MSG_PARTY_ASSIGNMENT"); - Group* group = GetPlayer()->GetGroup(); if (!group) return; @@ -536,21 +534,15 @@ void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) return; - uint8 assignment; - bool apply; - ObjectGuid guid; - recvData >> assignment >> apply; - recvData >> guid; - - switch (assignment) + switch (packet.Assignment) { case GROUP_ASSIGN_MAINASSIST: group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINASSIST); + group->SetGroupMemberFlag(packet.Target, packet.Set, MEMBER_FLAG_MAINASSIST); break; case GROUP_ASSIGN_MAINTANK: group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main assist flag from current if any. - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINTANK); + group->SetGroupMemberFlag(packet.Target, packet.Set, MEMBER_FLAG_MAINTANK); default: break; } diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp index 01a2da40c7b..2d5a85d4fd0 100644 --- a/src/server/game/Server/Packets/PartyPackets.cpp +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -163,6 +163,15 @@ void WorldPackets::Party::SetPartyLeader::Read() _worldPacket >> TargetGUID; } +void WorldPackets::Party::SetPartyAssignment::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> Assignment; + _worldPacket >> Target; + Set = _worldPacket.ReadBit(); +} + + void WorldPackets::Party::SetRole::Read() { _worldPacket >> PartyIndex; diff --git a/src/server/game/Server/Packets/PartyPackets.h b/src/server/game/Server/Packets/PartyPackets.h index 85742d09f7e..1c31ba25879 100644 --- a/src/server/game/Server/Packets/PartyPackets.h +++ b/src/server/game/Server/Packets/PartyPackets.h @@ -362,6 +362,18 @@ namespace WorldPackets bool Apply = false; }; + class SetPartyAssignment final : public ClientPacket + { + public: + SetPartyAssignment(WorldPacket&& packet) : ClientPacket(CMSG_SET_PARTY_ASSIGNMENT, std::move(packet)) { } + + void Read() override; + uint8 Assignment = 0; + uint8 PartyIndex = 0; + ObjectGuid Target; + bool Set = false; + }; + class DoReadyCheck final : public ClientPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 1cc7e63a25c..5a25ee63a70 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -691,7 +691,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_LFG_BONUS_FACTION_ID, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_LOOT_METHOD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetLootMethod, &WorldSession::HandleSetLootMethodOpcode); DEFINE_HANDLER(CMSG_SET_LOOT_SPECIALIZATION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Loot::SetLootSpecialization, &WorldSession::HandleSetLootSpecialization); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PARTY_ASSIGNMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode ); + DEFINE_HANDLER(CMSG_SET_PARTY_ASSIGNMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetPartyAssignment, &WorldSession::HandleSetPartyAssignment); DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetPartyLeader, &WorldSession::HandleSetPartyLeaderOpcode); DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 869c2b7304f..7d6d2f310db 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -450,6 +450,7 @@ namespace WorldPackets class RequestPartyMemberStats; class PartyMemberStats; class SetPartyLeader; + class SetPartyAssignment; class SetRole; class RoleChangedInform; class SetLootMethod; @@ -1227,7 +1228,7 @@ class WorldSession void HandleChangeSubGroupOpcode(WorldPackets::Party::ChangeSubGroup& packet); void HandleSwapSubGroupsOpcode(WorldPackets::Party::SwapSubGroups& packet); void HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssistantLeader& packet); - void HandlePartyAssignmentOpcode(WorldPacket& recvData); + void HandleSetPartyAssignment(WorldPackets::Party::SetPartyAssignment& packet); void HandleInitiateRolePoll(WorldPackets::Party::InitiateRolePoll& packet); void HandleSetEveryoneIsAssistant(WorldPackets::Party::SetEveryoneIsAssistant& packet); void HandleClearRaidMarker(WorldPackets::Party::ClearRaidMarker& packet); From 3ea1cfc4d0eeec14a4801de5cc97211a3ad754f1 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 2 Feb 2016 23:19:37 +0100 Subject: [PATCH 23/79] Core/PacketIO: Updated and enabled CMSG_SET_PLAYER_DECLINED_NAMES --- src/server/game/Handlers/CharacterHandler.cpp | 46 ++++++------------- .../game/Server/Packets/CharacterPackets.cpp | 13 ++++++ .../game/Server/Packets/CharacterPackets.h | 11 +++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 +- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 8c89f19357f..e34b2320c10 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1350,80 +1350,64 @@ void WorldSession::HandleCharRenameCallBack(PreparedQueryResult result, WorldPac sWorld->UpdateCharacterInfo(renameInfo->Guid, renameInfo->NewName); } -void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) +void WorldSession::HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlayerDeclinedNames& packet) { - ObjectGuid guid; - - recvData >> guid; - // not accept declined names for unsupported languages std::string name; - if (!ObjectMgr::GetPlayerNameByGUID(guid, name)) + if (!ObjectMgr::GetPlayerNameByGUID(packet.Player, name)) { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, packet.Player); return; } std::wstring wname; if (!Utf8toWStr(name, wname)) { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, packet.Player); return; } if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); - return; - } - - std::string name2; - DeclinedName declinedname; - - recvData >> name2; - - if (name2 != name) // character have different name - { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, packet.Player); return; } for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) { - recvData >> declinedname.name[i]; - if (!normalizePlayerName(declinedname.name[i])) + if (!normalizePlayerName(packet.DeclinedNames.name[i])) { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, packet.Player); return; } } - if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) + if (!ObjectMgr::CheckDeclinedNames(wname, packet.DeclinedNames)) { - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_ERROR, packet.Player); return; } for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - CharacterDatabase.EscapeString(declinedname.name[i]); + CharacterDatabase.EscapeString(packet.DeclinedNames.name[i]); SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME); - stmt->setUInt64(0, guid.GetCounter()); + stmt->setUInt64(0, packet.Player.GetCounter()); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_DECLINED_NAME); - stmt->setUInt64(0, guid.GetCounter()); + stmt->setUInt64(0, packet.Player.GetCounter()); - for (uint8 i = 0; i < 5; i++) - stmt->setString(i+1, declinedname.name[i]); + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; i++) + stmt->setString(i + 1, packet.DeclinedNames.name[i]); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); - SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_SUCCESS, guid); + SendSetPlayerDeclinedNamesResult(DECLINED_NAMES_RESULT_SUCCESS, packet.Player); } void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance& packet) diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index ef41d16c2b2..ed47b32cbcb 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -545,3 +545,16 @@ WorldPacket const* WorldPackets::Character::CharCustomizeFailed::Write() return &_worldPacket; } + +void WorldPackets::Character::SetPlayerDeclinedNames::Read() +{ + _worldPacket >> Player; + + uint8 stringLengths[MAX_DECLINED_NAME_CASES]; + + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + stringLengths[i] = _worldPacket.ReadBits(7); + + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + DeclinedNames.name[i] = _worldPacket.ReadString(stringLengths[i]); +} diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index cbf4f55906c..732e543d3fc 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -716,6 +716,17 @@ namespace WorldPackets uint8 Result = 0; ObjectGuid CharGUID; }; + + class SetPlayerDeclinedNames final : public ClientPacket + { + public: + SetPlayerDeclinedNames(WorldPacket&& packet) : ClientPacket(CMSG_SET_PLAYER_DECLINED_NAMES, std::move(packet)) { } + + void Read() override; + + ObjectGuid Player; + DeclinedName DeclinedNames; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 5a25ee63a70..c3ebe64810e 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -694,7 +694,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_PARTY_ASSIGNMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetPartyAssignment, &WorldSession::HandleSetPartyAssignment); DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetPartyLeader, &WorldSession::HandleSetPartyLeaderOpcode); DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); + DEFINE_HANDLER(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetPlayerDeclinedNames, &WorldSession::HandleSetPlayerDeclinedNames); DEFINE_HANDLER(CMSG_SET_PREFERRED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetPvP, &WorldSession::HandleSetPvP); DEFINE_HANDLER(CMSG_SET_RAID_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetRaidDifficulty, &WorldSession::HandleSetRaidDifficultyOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 7d6d2f310db..7b14b6ca926 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -197,6 +197,7 @@ namespace WorldPackets class SetFactionNotAtWar; class SetFactionInactive; class SetWatchedFaction; + class SetPlayerDeclinedNames; enum class LoginFailureReason : uint8; } @@ -1071,7 +1072,7 @@ class WorldSession void HandlePlayerLogin(LoginQueryHolder * holder); void HandleCharRenameOpcode(WorldPackets::Character::CharacterRenameRequest& request); void HandleCharRenameCallBack(PreparedQueryResult result, WorldPackets::Character::CharacterRenameInfo* renameInfo); - void HandleSetPlayerDeclinedNames(WorldPacket& recvData); + void HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlayerDeclinedNames& packet); void HandleAlterAppearance(WorldPackets::Character::AlterApperance& packet); void HandleCharCustomizeOpcode(WorldPackets::Character::CharCustomize& packet); void HandleCharCustomizeCallback(PreparedQueryResult result, WorldPackets::Character::CharCustomizeInfo* customizeInfo); From 3fa86e79319f055bce56b95a1dc399e6675761b7 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 00:20:07 +0100 Subject: [PATCH 24/79] Core/PacketIO: Updated and enabled CMSG_SET_TAXI_BENCHMARK_MODE --- src/server/game/Handlers/MiscHandler.cpp | 9 ++------- src/server/game/Server/Packets/MiscPackets.cpp | 5 +++++ src/server/game/Server/Packets/MiscPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 ++- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index a5ab144d319..e887c585952 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -988,14 +988,9 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff } } -void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket& recvData) +void WorldSession::HandleSetTaxiBenchmark(WorldPackets::Misc::SetTaxiBenchmarkMode& packet) { - uint8 mode; - recvData >> mode; - - mode ? _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK) : _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK); - - TC_LOG_DEBUG("network", "Client used \"/timetest %d\" command", mode); + packet.Enable ? _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK) : _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK); } void WorldSession::HandleGuildSetFocusedAchievement(WorldPackets::Achievement::GuildSetFocusedAchievement& setFocusedAchievement) diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index ab9acfe2172..83f867363f5 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -604,3 +604,8 @@ WorldPacket const* WorldPackets::Misc::CrossedInebriationThreshold::Write() return &_worldPacket; } + +void WorldPackets::Misc::SetTaxiBenchmarkMode::Read() +{ + Enable = _worldPacket.ReadBit(); +} diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index b653bf4a00a..6481e23d756 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -790,6 +790,16 @@ namespace WorldPackets int32 ItemID = 0; int32 Threshold = 0; }; + + class SetTaxiBenchmarkMode final : public ClientPacket + { + public: + SetTaxiBenchmarkMode(WorldPacket&& packet) : ClientPacket(CMSG_SET_TAXI_BENCHMARK_MODE, std::move(packet)) { } + + void Read() override; + + bool Enable = false; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c3ebe64810e..28ca50c5a13 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -704,7 +704,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_SHEATHED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Combat::SetSheathed, &WorldSession::HandleSetSheathedOpcode); DEFINE_HANDLER(CMSG_SET_SORT_BAGS_RIGHT_TO_LEFT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_SPECIALIZATION, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Talent::SetSpecialization, &WorldSession::HandleSetSpecializationOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TAXI_BENCHMARK_MODE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTaxiBenchmarkOpcode ); + DEFINE_HANDLER(CMSG_SET_TAXI_BENCHMARK_MODE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::SetTaxiBenchmarkMode, &WorldSession::HandleSetTaxiBenchmark); DEFINE_HANDLER(CMSG_SET_TITLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetTitle, &WorldSession::HandleSetTitleOpcode); DEFINE_HANDLER(CMSG_SET_TRADE_CURRENCY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::SetTradeCurrency, &WorldSession::HandleSetTradeCurrencyOpcode); DEFINE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::SetTradeGold, &WorldSession::HandleSetTradeGoldOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 7b14b6ca926..fd0cb061aa4 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -415,6 +415,7 @@ namespace WorldPackets class SetPvP; class WorldTeleport; class MountSpecial; + class SetTaxiBenchmarkMode; } namespace Movement @@ -1549,7 +1550,7 @@ class WorldSession void HandleGetItemPurchaseData(WorldPackets::Item::GetItemPurchaseData& packet); void HandleItemRefund(WorldPackets::Item::ItemPurchaseRefund& packet); - void HandleSetTaxiBenchmarkOpcode(WorldPacket& recvData); + void HandleSetTaxiBenchmark(WorldPackets::Misc::SetTaxiBenchmarkMode& packet); // Guild Bank void HandleGuildPermissionsQuery(WorldPackets::Guild::GuildPermissionsQuery& packet); From 6434fff067b538265d4b55cfef2f20192fdbcdae Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 3 Feb 2016 00:31:07 +0100 Subject: [PATCH 25/79] Warning fix --- src/server/game/DataStores/DBCStructure.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 418c238b52d..f051184b7e7 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -42,7 +42,7 @@ struct AreaTableEntry uint32 ID; // 0 uint32 MapID; // 1 uint32 ParentAreaID; // 2 if 0 then it's zone, else it's zone id of this area - uint32 AreaBit; // 3, main index + int32 AreaBit; // 3 uint32 Flags[2]; // 4-5, //uint32 SoundProviderPref; // 6, //uint32 SoundProviderPrefUnderwater; // 7, From 305b99e06584e7d319c496aedd1dbbf25f30b81e Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 01:25:01 +0100 Subject: [PATCH 26/79] Core/PacketIO: Updated and enabled CMSG_MISSILE_TRAJECTORY_COLLISION --- src/server/game/Handlers/MiscHandler.cpp | 2 +- src/server/game/Handlers/SpellHandler.cpp | 30 ++++++------------- .../game/Server/Packets/SpellPackets.cpp | 8 +++++ src/server/game/Server/Packets/SpellPackets.h | 14 +++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 3 +- 6 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index e887c585952..cd6fe63fad6 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -990,7 +990,7 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff void WorldSession::HandleSetTaxiBenchmark(WorldPackets::Misc::SetTaxiBenchmarkMode& packet) { - packet.Enable ? _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK) : _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK); + _player->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK, packet.Enable); } void WorldSession::HandleGuildSetFocusedAchievement(WorldPackets::Achievement::GuildSetFocusedAchievement& setFocusedAchievement) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index cbbb468938e..6599364a9c4 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -562,38 +562,26 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPackets::Spells::GetMirrorI } } -void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) +void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::MissileTrajectoryCollision& packet) { - ObjectGuid casterGuid; - uint32 spellId; - uint8 castCount; - float x, y, z; // Position of missile hit - - recvPacket >> casterGuid; - recvPacket >> spellId; - recvPacket >> castCount; - recvPacket >> x; - recvPacket >> y; - recvPacket >> z; - - Unit* caster = ObjectAccessor::GetUnit(*_player, casterGuid); + Unit* caster = ObjectAccessor::GetUnit(*_player, packet.Target); if (!caster) return; - Spell* spell = caster->FindCurrentSpellBySpellId(spellId); + Spell* spell = caster->FindCurrentSpellBySpellId(packet.SpellID); if (!spell || !spell->m_targets.HasDst()) return; Position pos = *spell->m_targets.GetDstPos(); - pos.Relocate(x, y, z); + pos.Relocate(packet.CollisionPos.x, packet.CollisionPos.y, packet.CollisionPos.z); spell->m_targets.ModDst(pos); WorldPacket data(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, 21); - data << casterGuid; - data << uint8(castCount); - data << float(x); - data << float(y); - data << float(z); + data << packet.Target; + data << uint8(packet.CastID); + data << float(packet.CollisionPos.x); + data << float(packet.CollisionPos.y); + data << float(packet.CollisionPos.z); caster->SendMessageToSet(&data, true); } diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index 251d7069b52..c5edf1e40c3 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -799,3 +799,11 @@ WorldPacket const* WorldPackets::Spells::ResyncRunes::Write() return &_worldPacket; } + +void WorldPackets::Spells::MissileTrajectoryCollision::Read() +{ + _worldPacket >> Target; + _worldPacket >> SpellID; + _worldPacket >> CastID; + _worldPacket >> CollisionPos; +} diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index adcdcdc99b2..76f60f83528 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -19,6 +19,7 @@ #define SpellPackets_h__ #include "Packet.h" +#include "PacketUtilities.h" #include "Player.h" #include "SpellAuras.h" #include "Spell.h" @@ -824,6 +825,19 @@ namespace WorldPackets std::vector Runes; }; + + class MissileTrajectoryCollision final : public ClientPacket + { + public: + MissileTrajectoryCollision(WorldPacket&& packet) : ClientPacket(CMSG_MISSILE_TRAJECTORY_COLLISION, std::move(packet)) { } + + void Read() override; + + ObjectGuid Target; + int32 SpellID = 0; + uint8 CastID = 0; + G3D::Vector3 CollisionPos; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 28ca50c5a13..83f0b853665 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -474,7 +474,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_MAIL_TAKE_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeMoney, &WorldSession::HandleMailTakeMoney); DEFINE_OPCODE_HANDLER_OLD(CMSG_MASTER_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); DEFINE_HANDLER(CMSG_MINIMAP_PING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::MinimapPingClient, &WorldSession::HandleMinimapPingOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition ); + DEFINE_HANDLER(CMSG_MISSILE_TRAJECTORY_COLLISION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::MissileTrajectoryCollision, &WorldSession::HandleMissileTrajectoryCollision); DEFINE_HANDLER(CMSG_MOUNT_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_MOUNT_SPECIAL_ANIM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::MountSpecial, &WorldSession::HandleMountSpecialAnimOpcode); DEFINE_HANDLER(CMSG_MOVE_APPLY_MOVEMENT_FORCE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index fd0cb061aa4..1b6c4b7f984 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -594,6 +594,7 @@ namespace WorldPackets class SelfRes; class GetMirrorImageData; class SpellClick; + class MissileTrajectoryCollision; } namespace Talent @@ -1613,7 +1614,7 @@ class WorldSession void HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*request*/); void HandleQueryQuestCompletionNPCs(WorldPackets::Query::QueryQuestCompletionNPCs& queryQuestCompletionNPCs); void HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& questPoiQuery); - void HandleUpdateProjectilePosition(WorldPacket& recvPacket); + void HandleMissileTrajectoryCollision(WorldPackets::Spells::MissileTrajectoryCollision& packet); void HandleUpdateMissileTrajectory(WorldPacket& recvPacket); void HandleViolenceLevel(WorldPackets::Misc::ViolenceLevel& violenceLevel); void HandleObjectUpdateFailedOpcode(WorldPackets::Misc::ObjectUpdateFailed& objectUpdateFailed); From f269335bb2d95f486a8eb17a8a44fc5e1a5ee862 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 01:48:02 +0100 Subject: [PATCH 27/79] Core/PacketIO: 305b99e06584e7d319c496aedd1dbbf25f30b81e follow-up --- src/server/game/Handlers/SpellHandler.cpp | 8 ++++---- src/server/game/Server/Packets/SpellPackets.cpp | 2 +- src/server/game/Server/Packets/SpellPackets.h | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 6599364a9c4..bbce8bbd8ed 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -573,15 +573,15 @@ void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::Missil return; Position pos = *spell->m_targets.GetDstPos(); - pos.Relocate(packet.CollisionPos.x, packet.CollisionPos.y, packet.CollisionPos.z); + pos.Relocate(packet.CollisionPos); spell->m_targets.ModDst(pos); WorldPacket data(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, 21); data << packet.Target; data << uint8(packet.CastID); - data << float(packet.CollisionPos.x); - data << float(packet.CollisionPos.y); - data << float(packet.CollisionPos.z); + data << float(packet.CollisionPos.m_positionX); + data << float(packet.CollisionPos.m_positionY); + data << float(packet.CollisionPos.m_positionZ); caster->SendMessageToSet(&data, true); } diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index c5edf1e40c3..a54448e455f 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -805,5 +805,5 @@ void WorldPackets::Spells::MissileTrajectoryCollision::Read() _worldPacket >> Target; _worldPacket >> SpellID; _worldPacket >> CastID; - _worldPacket >> CollisionPos; + _worldPacket >> CollisionPos.PositionXYZStream(); } diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 76f60f83528..50ab5ffdf11 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -19,7 +19,6 @@ #define SpellPackets_h__ #include "Packet.h" -#include "PacketUtilities.h" #include "Player.h" #include "SpellAuras.h" #include "Spell.h" @@ -836,7 +835,7 @@ namespace WorldPackets ObjectGuid Target; int32 SpellID = 0; uint8 CastID = 0; - G3D::Vector3 CollisionPos; + Position CollisionPos; }; } } From 6715a91907628a495deb9e2301d578537c82dce5 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 15:10:58 +0100 Subject: [PATCH 28/79] Core/PacketIO: Updated and enabled CMSG_UPDATE_MISSILE_TRAJECTORY --- src/server/game/Handlers/MiscHandler.cpp | 42 ------------------- src/server/game/Handlers/SpellHandler.cpp | 28 +++++++++++++ .../game/Server/Packets/SpellPackets.cpp | 20 +++++++++ src/server/game/Server/Packets/SpellPackets.h | 17 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 5 ++- 6 files changed, 69 insertions(+), 45 deletions(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index cd6fe63fad6..5b9616a5d68 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1034,48 +1034,6 @@ void WorldSession::HandleInstanceLockResponse(WorldPackets::Instance::InstanceLo _player->SetPendingBind(0, 0); } -void WorldSession::HandleUpdateMissileTrajectory(WorldPacket& recvPacket) -{ - ObjectGuid guid; - uint32 spellId; - float pitch, speed; - float curX, curY, curZ; - float targetX, targetY, targetZ; - uint8 moveStop; - - recvPacket >> guid >> spellId >> pitch >> speed; - recvPacket >> curX >> curY >> curZ; - recvPacket >> targetX >> targetY >> targetZ; - recvPacket >> moveStop; - - Unit* caster = ObjectAccessor::GetUnit(*_player, guid); - Spell* spell = caster ? caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) : NULL; - if (!spell || spell->m_spellInfo->Id != spellId || !spell->m_targets.HasDst() || !spell->m_targets.HasSrc()) - { - recvPacket.rfinish(); - return; - } - - Position pos = *spell->m_targets.GetSrcPos(); - pos.Relocate(curX, curY, curZ); - spell->m_targets.ModSrc(pos); - - pos = *spell->m_targets.GetDstPos(); - pos.Relocate(targetX, targetY, targetZ); - spell->m_targets.ModDst(pos); - - spell->m_targets.SetPitch(pitch); - spell->m_targets.SetSpeed(speed); - - if (moveStop) - { - uint32 opcode; - recvPacket >> opcode; - recvPacket.SetOpcode(CMSG_MOVE_STOP); // always set to CMSG_MOVE_STOP in client SetOpcode - //HandleMovementOpcodes(recvPacket); - } -} - void WorldSession::HandleViolenceLevel(WorldPackets::Misc::ViolenceLevel& /*violenceLevel*/) { // do something? diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index bbce8bbd8ed..4d464e8d39d 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -585,6 +585,34 @@ void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::Missil caster->SendMessageToSet(&data, true); } +void WorldSession::HandleUpdateMissileTrajectory(WorldPackets::Spells::UpdateMissileTrajectory& packet) +{ + Unit* caster = ObjectAccessor::GetUnit(*_player, packet.Guid); + Spell* spell = caster ? caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) : NULL; + if (!spell || spell->m_spellInfo->Id != packet.SpellID || !spell->m_targets.HasDst() || !spell->m_targets.HasSrc()) + return; + + Position pos = *spell->m_targets.GetSrcPos(); + pos.Relocate(packet.FirePos); + spell->m_targets.ModSrc(pos); + + pos = *spell->m_targets.GetDstPos(); + pos.Relocate(packet.ImpactPos); + spell->m_targets.ModDst(pos); + + spell->m_targets.SetPitch(packet.Pitch); + spell->m_targets.SetSpeed(packet.Speed); + + if (packet.Status.is_initialized()) + { + GetPlayer()->ValidateMovementInfo(packet.Status.get_ptr()); + /*uint32 opcode; + recvPacket >> opcode; + recvPacket.SetOpcode(CMSG_MOVE_STOP); // always set to CMSG_MOVE_STOP in client SetOpcode + //HandleMovementOpcodes(recvPacket);*/ + } +} + void WorldSession::HandleRequestCategoryCooldowns(WorldPackets::Spells::RequestCategoryCooldowns& /*requestCategoryCooldowns*/) { _player->SendSpellCategoryCooldowns(); diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index a54448e455f..f066f929faf 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -807,3 +807,23 @@ void WorldPackets::Spells::MissileTrajectoryCollision::Read() _worldPacket >> CastID; _worldPacket >> CollisionPos.PositionXYZStream(); } + +void WorldPackets::Spells::UpdateMissileTrajectory::Read() +{ + _worldPacket >> Guid; + _worldPacket >> MoveMsgID; + _worldPacket >> SpellID; + _worldPacket >> Pitch; + _worldPacket >> Speed; + _worldPacket >> FirePos.PositionXYZStream(); + _worldPacket >> ImpactPos.PositionXYZStream(); + bool hasStatus = _worldPacket.ReadBit(); + + _worldPacket.ResetBitPos(); + if (hasStatus) + { + MovementInfo info; + _worldPacket >> info; + Status = info; + } +} diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 50ab5ffdf11..8785313b6fc 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -837,6 +837,23 @@ namespace WorldPackets uint8 CastID = 0; Position CollisionPos; }; + + class UpdateMissileTrajectory final : public ClientPacket + { + public: + UpdateMissileTrajectory(WorldPacket&& packet) : ClientPacket(CMSG_UPDATE_MISSILE_TRAJECTORY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + uint16 MoveMsgID = 0; + int32 SpellID = 0; + float Pitch = 0.0; + float Speed = 0.0; + Position FirePos; + Position ImpactPos; + Optional Status; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 83f0b853665..5eaefb052fd 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -767,7 +767,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_UNLOCK_VOID_STORAGE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::UnlockVoidStorage, &WorldSession::HandleVoidStorageUnlock); DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::UserClientUpdateAccountData, &WorldSession::HandleUpdateAccountData); DEFINE_HANDLER(CMSG_UPDATE_CLIENT_SETTINGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory ); + DEFINE_HANDLER(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::UpdateMissileTrajectory, &WorldSession::HandleUpdateMissileTrajectory); DEFINE_HANDLER(CMSG_UPDATE_RAID_TARGET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::UpdateRaidTarget, &WorldSession::HandleUpdateRaidTargetOpcode); DEFINE_HANDLER(CMSG_UPDATE_VAS_PURCHASE_STATES, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_AUCTIONABLE_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Token::UpdateListedAuctionableTokens, &WorldSession::HandleUpdateListedAuctionableTokens); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 1b6c4b7f984..dfd8ecb0868 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -595,6 +595,7 @@ namespace WorldPackets class GetMirrorImageData; class SpellClick; class MissileTrajectoryCollision; + class UpdateMissileTrajectory; } namespace Talent @@ -1387,6 +1388,8 @@ class WorldSession void HandleCancelGrowthAuraOpcode(WorldPackets::Spells::CancelGrowthAura& cancelGrowthAura); void HandleCancelMountAuraOpcode(WorldPackets::Spells::CancelMountAura& cancelMountAura); void HandleCancelAutoRepeatSpellOpcode(WorldPackets::Spells::CancelAutoRepeatSpell& cancelAutoRepeatSpell); + void HandleMissileTrajectoryCollision(WorldPackets::Spells::MissileTrajectoryCollision& packet); + void HandleUpdateMissileTrajectory(WorldPackets::Spells::UpdateMissileTrajectory& packet); void HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents& packet); void HandleConfirmRespecWipeOpcode(WorldPackets::Talent::ConfirmRespecWipe& confirmRespecWipe); @@ -1614,8 +1617,6 @@ class WorldSession void HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*request*/); void HandleQueryQuestCompletionNPCs(WorldPackets::Query::QueryQuestCompletionNPCs& queryQuestCompletionNPCs); void HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& questPoiQuery); - void HandleMissileTrajectoryCollision(WorldPackets::Spells::MissileTrajectoryCollision& packet); - void HandleUpdateMissileTrajectory(WorldPacket& recvPacket); void HandleViolenceLevel(WorldPackets::Misc::ViolenceLevel& violenceLevel); void HandleObjectUpdateFailedOpcode(WorldPackets::Misc::ObjectUpdateFailed& objectUpdateFailed); void HandleObjectUpdateRescuedOpcode(WorldPackets::Misc::ObjectUpdateRescued& objectUpdateRescued); From ca967f4374008a6c60540bbc2897fbcc61824372 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 16:47:24 +0100 Subject: [PATCH 29/79] Core/PacketIO: Updated CMSG_VOICE_SESSION_ENABLE and CMSG_SET_ACTIVE_VOICE_CHANNEL for further usage --- src/server/game/Handlers/VoiceChatHandler.cpp | 12 ++--- src/server/game/Server/Packets/AllPackets.h | 1 + .../game/Server/Packets/VoicePackets.cpp | 30 +++++++++++ src/server/game/Server/Packets/VoicePackets.h | 51 +++++++++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 4 +- src/server/game/Server/WorldSession.h | 10 +++- 6 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/server/game/Server/Packets/VoicePackets.cpp create mode 100644 src/server/game/Server/Packets/VoicePackets.h diff --git a/src/server/game/Handlers/VoiceChatHandler.cpp b/src/server/game/Handlers/VoiceChatHandler.cpp index 4c96e6bdebb..37d23c120e7 100644 --- a/src/server/game/Handlers/VoiceChatHandler.cpp +++ b/src/server/game/Handlers/VoiceChatHandler.cpp @@ -16,20 +16,14 @@ * with this program. If not, see . */ -#include "Common.h" -#include "WorldPacket.h" #include "WorldSession.h" +#include "VoicePackets.h" -void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket& recvData) +void WorldSession::HandleVoiceSessionEnable(WorldPackets::Voice::VoiceSessionEnable& /*packet*/) { - // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled - recvData.read_skip(); - recvData.read_skip(); } -void WorldSession::HandleSetActiveVoiceChannel(WorldPacket& recvData) +void WorldSession::HandleSetActiveVoiceChannel(WorldPackets::Voice::SetActiveVoiceChannel& /*packet*/) { - recvData.read_skip(); - recvData.read_skip(); } diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index f9d06a56286..7a36a726098 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -68,6 +68,7 @@ #include "ToyPackets.h" #include "TradePackets.h" #include "VehiclePackets.h" +#include "VoicePackets.h" #include "VoidStoragePackets.h" #include "WhoPackets.h" #include "WorldStatePackets.h" diff --git a/src/server/game/Server/Packets/VoicePackets.cpp b/src/server/game/Server/Packets/VoicePackets.cpp new file mode 100644 index 00000000000..3e2269a0905 --- /dev/null +++ b/src/server/game/Server/Packets/VoicePackets.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 "VoicePackets.h" + +void WorldPackets::Voice::VoiceSessionEnable::Read() +{ + EnableVoiceChat = _worldPacket.ReadBit(); + EnableMicrophone = _worldPacket.ReadBit(); +} + +void WorldPackets::Voice::SetActiveVoiceChannel::Read() +{ + _worldPacket >> ChannelType; + ChannelName = _worldPacket.ReadString(_worldPacket.ReadBits(7)); +} diff --git a/src/server/game/Server/Packets/VoicePackets.h b/src/server/game/Server/Packets/VoicePackets.h new file mode 100644 index 00000000000..0ae2645c498 --- /dev/null +++ b/src/server/game/Server/Packets/VoicePackets.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 . + */ + +#ifndef VoicePackets_h__ +#define VoicePackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Voice + { + class VoiceSessionEnable final : public ClientPacket + { + public: + VoiceSessionEnable(WorldPacket&& packet) : ClientPacket(CMSG_VOICE_SESSION_ENABLE, std::move(packet)) { } + + void Read() override; + + bool EnableVoiceChat = false; + bool EnableMicrophone = false; + }; + + class SetActiveVoiceChannel final : public ClientPacket + { + public: + SetActiveVoiceChannel(WorldPacket&& packet) : ClientPacket(CMSG_SET_ACTIVE_VOICE_CHANNEL, std::move(packet)) { } + + void Read() override; + + uint8 ChannelType = 0; + std::string ChannelName; + }; + } +} + +#endif // VoicePackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 5eaefb052fd..f0bc08f9f7a 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -673,7 +673,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_ACTION_BAR_TOGGLES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetActionBarToggles, &WorldSession::HandleSetActionBarToggles); DEFINE_HANDLER(CMSG_SET_ACTION_BUTTON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SetActionButton, &WorldSession::HandleSetActionButtonOpcode); DEFINE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Movement::SetActiveMover, &WorldSession::HandleSetActiveMoverOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); + DEFINE_HANDLER(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Voice::SetActiveVoiceChannel, &WorldSession::HandleSetActiveVoiceChannel); DEFINE_HANDLER(CMSG_SET_ADVANCED_COMBAT_LOGGING, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::ClientConfig::SetAdvancedCombatLogging, &WorldSession::HandleSetAdvancedCombatLogging); DEFINE_HANDLER(CMSG_SET_ASSISTANT_LEADER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetAssistantLeader, &WorldSession::HandleSetAssistantLeaderOpcode); DEFINE_HANDLER(CMSG_SET_BACKPACK_AUTOSORT_DISABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -782,7 +782,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_VIOLENCE_LEVEL, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Misc::ViolenceLevel, &WorldSession::HandleViolenceLevel); DEFINE_HANDLER(CMSG_VOICE_ADD_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_VOICE_DEL_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_VOICE_SESSION_ENABLE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleVoiceSessionEnableOpcode ); + DEFINE_HANDLER(CMSG_VOICE_SESSION_ENABLE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Voice::VoiceSessionEnable, &WorldSession::HandleVoiceSessionEnable); DEFINE_HANDLER(CMSG_VOID_STORAGE_TRANSFER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::VoidStorageTransfer, &WorldSession::HandleVoidStorageTransfer); DEFINE_OPCODE_HANDLER_OLD(CMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWardenDataOpcode ); DEFINE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Who::WhoRequestPkt, &WorldSession::HandleWhoOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index dfd8ecb0868..9b3f30a14ce 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -665,6 +665,12 @@ namespace WorldPackets class MoveSetVehicleRecIdAck; } + namespace Voice + { + class VoiceSessionEnable; + class SetActiveVoiceChannel; + } + namespace VoidStorage { class UnlockVoidStorage; @@ -1447,8 +1453,8 @@ class WorldSession template void HandleChannelPlayerCommand(WorldPackets::Channel::ChannelPlayerCommand& packet); - void HandleVoiceSessionEnableOpcode(WorldPacket& recvData); - void HandleSetActiveVoiceChannel(WorldPacket& recvData); + void HandleVoiceSessionEnable(WorldPackets::Voice::VoiceSessionEnable& packet); + void HandleSetActiveVoiceChannel(WorldPackets::Voice::SetActiveVoiceChannel& packet); void HandleCompleteCinematic(WorldPackets::Misc::CompleteCinematic& packet); void HandleNextCinematicCamera(WorldPackets::Misc::NextCinematicCamera& packet); From ff9ac9f9b0768fc97f00b24188f53f94516b3ef2 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 17:14:15 +0100 Subject: [PATCH 30/79] Core/PacketIO: Use Vector3 instead of Position since orientation isn't included (MissileTrajectoryCollision and UpdateMissileTrajectory) --- src/server/game/Entities/Object/Position.h | 7 +++++++ src/server/game/Handlers/SpellHandler.cpp | 6 +++--- src/server/game/Server/Packets/SpellPackets.cpp | 6 +++--- src/server/game/Server/Packets/SpellPackets.h | 7 ++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index ce4fd7dcfbc..cc528b973f8 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -20,6 +20,8 @@ #include "Common.h" +#include + class ByteBuffer; struct Position @@ -87,6 +89,11 @@ public: m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); } + void Relocate(G3D::Vector3 const& pos) + { + m_positionX = pos.x; m_positionY = pos.y; m_positionZ = pos.z; + } + void RelocateOffset(Position const &offset); void SetOrientation(float orientation) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 4d464e8d39d..1a0d5b16663 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -579,9 +579,9 @@ void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::Missil WorldPacket data(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, 21); data << packet.Target; data << uint8(packet.CastID); - data << float(packet.CollisionPos.m_positionX); - data << float(packet.CollisionPos.m_positionY); - data << float(packet.CollisionPos.m_positionZ); + data << float(packet.CollisionPos.x); + data << float(packet.CollisionPos.y); + data << float(packet.CollisionPos.z); caster->SendMessageToSet(&data, true); } diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index f066f929faf..ff6ec903990 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -805,7 +805,7 @@ void WorldPackets::Spells::MissileTrajectoryCollision::Read() _worldPacket >> Target; _worldPacket >> SpellID; _worldPacket >> CastID; - _worldPacket >> CollisionPos.PositionXYZStream(); + _worldPacket >> CollisionPos; } void WorldPackets::Spells::UpdateMissileTrajectory::Read() @@ -815,8 +815,8 @@ void WorldPackets::Spells::UpdateMissileTrajectory::Read() _worldPacket >> SpellID; _worldPacket >> Pitch; _worldPacket >> Speed; - _worldPacket >> FirePos.PositionXYZStream(); - _worldPacket >> ImpactPos.PositionXYZStream(); + _worldPacket >> FirePos; + _worldPacket >> ImpactPos; bool hasStatus = _worldPacket.ReadBit(); _worldPacket.ResetBitPos(); diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 8785313b6fc..4a8c1211a85 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -19,6 +19,7 @@ #define SpellPackets_h__ #include "Packet.h" +#include "PacketUtilities.h" #include "Player.h" #include "SpellAuras.h" #include "Spell.h" @@ -835,7 +836,7 @@ namespace WorldPackets ObjectGuid Target; int32 SpellID = 0; uint8 CastID = 0; - Position CollisionPos; + G3D::Vector3 CollisionPos; }; class UpdateMissileTrajectory final : public ClientPacket @@ -850,8 +851,8 @@ namespace WorldPackets int32 SpellID = 0; float Pitch = 0.0; float Speed = 0.0; - Position FirePos; - Position ImpactPos; + G3D::Vector3 FirePos; + G3D::Vector3 ImpactPos; Optional Status; }; } From 15bfabaa0a336ce4319cecdbf607380d581443f4 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 22:53:48 +0100 Subject: [PATCH 31/79] Core/PacketIO: Updated CMSG_COMPLAINT --- src/server/game/Handlers/MiscHandler.cpp | 40 ------------------- src/server/game/Handlers/TicketHandler.cpp | 10 +++++ src/server/game/Server/Packets/SpellPackets.h | 4 +- .../game/Server/Packets/TicketPackets.cpp | 39 ++++++++++++++++++ .../game/Server/Packets/TicketPackets.h | 30 ++++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 4 +- src/server/game/Server/WorldSession.h | 3 +- 7 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 5b9616a5d68..b94b4ce838e 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -724,46 +724,6 @@ void WorldSession::HandleWhoIsOpcode(WorldPackets::Who::WhoIsRequest& packet) SendPacket(response.Write()); } -void WorldSession::HandleComplainOpcode(WorldPacket& recvData) -{ - uint8 spam_type; // 0 - mail, 1 - chat - ObjectGuid spammer_guid; - uint32 unk1 = 0; - uint32 unk2 = 0; - uint32 unk3 = 0; - uint32 unk4 = 0; - std::string description = ""; - recvData >> spam_type; // unk 0x01 const, may be spam type (mail/chat) - recvData >> spammer_guid; // player guid - switch (spam_type) - { - case 0: - recvData >> unk1; // const 0 - recvData >> unk2; // probably mail id - recvData >> unk3; // const 0 - break; - case 1: - recvData >> unk1; // probably language - recvData >> unk2; // message type? - recvData >> unk3; // probably channel id - recvData >> unk4; // time - recvData >> description; // spam description string (messagetype, channel name, player name, message) - break; - } - - // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam. - // if it's mail spam - ALL mails from this spammer automatically removed by client - - // Complaint Received message - WorldPacket data(SMSG_COMPLAINT_RESULT, 2); - data << uint8(0); // value 1 resets CGChat::m_complaintsSystemStatus in client. (unused?) - data << uint8(0); // value 0xC generates a "CalendarError" in client. - SendPacket(&data); - - TC_LOG_DEBUG("network", "REPORT SPAM: type %u, %s, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", - spam_type, spammer_guid.ToString().c_str(), unk1, unk2, unk3, unk4, description.c_str()); -} - void WorldSession::HandleFarSightOpcode(WorldPackets::Misc::FarSight& packet) { if (packet.Enable) diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index 907cd9cd6f4..6f7a6acaa10 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -95,3 +95,13 @@ void WorldSession::HandleBugReportOpcode(WorldPackets::Ticket::BugReport& bugRep stmt->setString(1, bugReport.DiagInfo); CharacterDatabase.Execute(stmt); } + +void WorldSession::HandleComplaint(WorldPackets::Ticket::Complaint& packet) +{ // NOTE: all chat messages from this spammer are automatically ignored by the spam reporter until logout in case of chat spam. + // if it's mail spam - ALL mails from this spammer are automatically removed by client + + WorldPackets::Ticket::ComplaintResult result; + result.ComplaintType = packet.ComplaintType; + result.Result = 0; + SendPacket(result.Write()); +} diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 4a8c1211a85..042c32ac66e 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -849,8 +849,8 @@ namespace WorldPackets ObjectGuid Guid; uint16 MoveMsgID = 0; int32 SpellID = 0; - float Pitch = 0.0; - float Speed = 0.0; + float Pitch = 0.0f; + float Speed = 0.0f; G3D::Vector3 FirePos; G3D::Vector3 ImpactPos; Optional Status; diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index 97c23b47191..4fe9e9e358e 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -223,6 +223,45 @@ void WorldPackets::Ticket::SupportTicketSubmitComplaint::Read() _worldPacket >> LFGListApplicant; } +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::Complaint::ComplaintOffender& complaintOffender) +{ + data >> complaintOffender.PlayerGuid; + data >> complaintOffender.RealmAddress; + data >> complaintOffender.TimeSinceOffence; + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::Complaint::ComplaintChat& chat) +{ + data >> chat.Command; + data >> chat.ChannelID; + chat.MessageLog = data.ReadString(data.ReadBits(12)); + + return data; +} + +void WorldPackets::Ticket::Complaint::Read() +{ + _worldPacket >> ComplaintType; + _worldPacket >> Offender; + + switch (ComplaintType) + { + case 0: + _worldPacket >> MailID; + break; + case 1: + _worldPacket >> Chat; + break; + case 2: + _worldPacket >> EventGuid; + _worldPacket >> InviteGuid; + default: + break; + } +} + WorldPacket const* WorldPackets::Ticket::ComplaintResult::Write() { _worldPacket << uint32(ComplaintType); diff --git a/src/server/game/Server/Packets/TicketPackets.h b/src/server/game/Server/Packets/TicketPackets.h index 9b126d681b0..691a7b27bb8 100644 --- a/src/server/game/Server/Packets/TicketPackets.h +++ b/src/server/game/Server/Packets/TicketPackets.h @@ -193,6 +193,36 @@ namespace WorldPackets }; + class Complaint final : public ClientPacket + { + public: + struct ComplaintOffender + { + ObjectGuid PlayerGuid; + uint32 RealmAddress = 0; + uint32 TimeSinceOffence = 0; + }; + + struct ComplaintChat + { + uint32 Command = 0; + uint32 ChannelID = 0; + std::string MessageLog; + }; + + Complaint(WorldPacket&& packet) : ClientPacket(CMSG_COMPLAINT, std::move(packet)) { } + + void Read() override; + + uint8 ComplaintType = 0; + ComplaintOffender Offender; + uint32 MailID = 0; + ComplaintChat Chat; + ObjectGuid EventGuid; + ObjectGuid InviteGuid; + + }; + class ComplaintResult final : public ServerPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index f0bc08f9f7a..87b1c8a59a9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -291,7 +291,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_COMMENTATOR_GET_MAP_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_COMMENTATOR_GET_PLAYER_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_COMMENTATOR_START_WARGAME, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_COMPLAINT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleComplainOpcode ); + DEFINE_HANDLER(CMSG_COMPLAINT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::Complaint, &WorldSession::HandleComplaint); DEFINE_HANDLER(CMSG_COMPLETE_CINEMATIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::CompleteCinematic, &WorldSession::HandleCompleteCinematic); DEFINE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CONFIRM_RESPEC_WIPE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::ConfirmRespecWipe, &WorldSession::HandleConfirmRespecWipeOpcode); @@ -990,7 +990,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_MAP_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_STATE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLAINT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLAINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLETE_SHIPMENT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_PACKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONNECT_TO, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 9b3f30a14ce..a3a1f85ce3a 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -623,6 +623,7 @@ namespace WorldPackets class SupportTicketSubmitSuggestion; class SupportTicketSubmitComplaint; class BugReport; + class Complaint; } namespace Token @@ -1157,6 +1158,7 @@ class WorldSession void HandleSupportTicketSubmitSuggestion(WorldPackets::Ticket::SupportTicketSubmitSuggestion& packet); void HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet); void HandleBugReportOpcode(WorldPackets::Ticket::BugReport& bugReport); + void HandleComplaint(WorldPackets::Ticket::Complaint& packet); void HandleTogglePvP(WorldPackets::Misc::TogglePvP& packet); void HandleSetPvP(WorldPackets::Misc::SetPvP& packet); @@ -1549,7 +1551,6 @@ class WorldSession void SendLfgTeleportError(uint8 err); void HandleSelfResOpcode(WorldPackets::Spells::SelfRes& packet); - void HandleComplainOpcode(WorldPacket& recvData); void HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& packet); // Socket gem From 93b552685bfe68f8ad805554077f2da0f0e94133 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 3 Feb 2016 23:28:54 +0100 Subject: [PATCH 32/79] Core/PacketIO: Updated CMSG_WARDEN_DATA Note: No packet handling changes made whatsoever. ...and ninja-fix a missing break from previous commit. --- src/server/game/Server/Packets/AllPackets.h | 1 + .../game/Server/Packets/TicketPackets.cpp | 8 ++-- .../game/Server/Packets/WardenPackets.cpp | 29 ++++++++++++++ .../game/Server/Packets/WardenPackets.h | 39 +++++++++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 10 ++++- src/server/game/Support/SupportMgr.h | 7 ++++ src/server/game/Warden/Warden.cpp | 19 ++++----- 8 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 src/server/game/Server/Packets/WardenPackets.cpp create mode 100644 src/server/game/Server/Packets/WardenPackets.h diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 7a36a726098..caf895abe03 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -70,6 +70,7 @@ #include "VehiclePackets.h" #include "VoicePackets.h" #include "VoidStoragePackets.h" +#include "WardenPackets.h" #include "WhoPackets.h" #include "WorldStatePackets.h" diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index 4fe9e9e358e..88ec0dc9465 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -18,6 +18,7 @@ #include "LFGPackets.h" #include "TicketPackets.h" #include "PacketUtilities.h" +#include "SupportMgr.h" using namespace WorldPackets; @@ -248,15 +249,16 @@ void WorldPackets::Ticket::Complaint::Read() switch (ComplaintType) { - case 0: + case SUPPORT_SPAM_TYPE_MAIL: _worldPacket >> MailID; break; - case 1: + case SUPPORT_SAPM_TYPE_CHAT: _worldPacket >> Chat; break; - case 2: + case SUPPORT_SPAM_TYPE_CALENDAR: _worldPacket >> EventGuid; _worldPacket >> InviteGuid; + break; default: break; } diff --git a/src/server/game/Server/Packets/WardenPackets.cpp b/src/server/game/Server/Packets/WardenPackets.cpp new file mode 100644 index 00000000000..89ff90dc175 --- /dev/null +++ b/src/server/game/Server/Packets/WardenPackets.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 "WardenPackets.h" + +void WorldPackets::Warden::WardenData::Read() +{ + uint32 size = _worldPacket.read(); + + if (size) + { + Data.resize(size); + _worldPacket.read(Data.contents(), size); + } +} diff --git a/src/server/game/Server/Packets/WardenPackets.h b/src/server/game/Server/Packets/WardenPackets.h new file mode 100644 index 00000000000..a23046235ff --- /dev/null +++ b/src/server/game/Server/Packets/WardenPackets.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 . + */ + +#ifndef WardenPackets_h__ +#define WardenPackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Warden + { + class WardenData final : public ClientPacket + { + public: + WardenData(WorldPacket&& packet) : ClientPacket(CMSG_WARDEN_DATA, std::move(packet)) { } + + void Read() override; + + ByteBuffer Data; + }; + } +} + +#endif // WardenPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 87b1c8a59a9..36fc1d10ef2 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -784,7 +784,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_VOICE_DEL_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_VOICE_SESSION_ENABLE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Voice::VoiceSessionEnable, &WorldSession::HandleVoiceSessionEnable); DEFINE_HANDLER(CMSG_VOID_STORAGE_TRANSFER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::VoidStorageTransfer, &WorldSession::HandleVoidStorageTransfer); - DEFINE_OPCODE_HANDLER_OLD(CMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWardenDataOpcode ); + DEFINE_HANDLER(CMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Warden::WardenData, &WorldSession::HandleWardenData); DEFINE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Who::WhoRequestPkt, &WorldSession::HandleWhoOpcode); DEFINE_HANDLER(CMSG_WHO_IS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Who::WhoIsRequest, &WorldSession::HandleWhoIsOpcode); DEFINE_HANDLER(CMSG_WORLD_PORT_RESPONSE, STATUS_TRANSFER, PROCESS_THREADUNSAFE, WorldPackets::Movement::WorldPortResponse, &WorldSession::HandleMoveWorldportAckOpcode); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index a3a1f85ce3a..efa1f4151ca 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -680,6 +680,11 @@ namespace WorldPackets class SwapVoidItem; } + namespace Warden + { + class WardenData; + } + namespace Who { class WhoIsRequest; @@ -1509,7 +1514,7 @@ class WorldSession void HandleBfQueueInviteResponse(WorldPackets::Battlefield::BFMgrQueueInviteResponse& bfMgrQueueInviteResponse); void HandleBfQueueExitRequest(WorldPackets::Battlefield::BFMgrQueueExitRequest& bfMgrQueueExitRequest); - void HandleWardenDataOpcode(WorldPacket& recvData); + void HandleWorldTeleportOpcode(WorldPackets::Misc::WorldTeleport& worldTeleport); void HandleMinimapPingOpcode(WorldPackets::Party::MinimapPingClient& packet); void HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet); @@ -1663,6 +1668,9 @@ class WorldSession void HandleBattlePetSummon(WorldPackets::BattlePet::BattlePetSummon& battlePetSummon); void HandleCageBattlePet(WorldPackets::BattlePet::CageBattlePet& cageBattlePet); + // Warden + void HandleWardenData(WorldPackets::Warden::WardenData& packet); + union ConnectToKey { struct diff --git a/src/server/game/Support/SupportMgr.h b/src/server/game/Support/SupportMgr.h index c312651d789..61dae5fd6da 100644 --- a/src/server/game/Support/SupportMgr.h +++ b/src/server/game/Support/SupportMgr.h @@ -41,6 +41,13 @@ enum GMSupportComplaintType GMTICKET_SUPPORT_COMPLAINT_TYPE_SPAMMING = 24 }; +enum SupportSpamType +{ + SUPPORT_SPAM_TYPE_MAIL = 0, + SUPPORT_SAPM_TYPE_CHAT = 1, + SUPPORT_SPAM_TYPE_CALENDAR = 2 +}; + using ChatLog = WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLog; class Ticket diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index 5f5147c739b..906e0cade08 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -26,6 +26,7 @@ #include "Util.h" #include "Warden.h" #include "AccountMgr.h" +#include "WardenPackets.h" #include @@ -220,16 +221,16 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/) return "Undefined"; } -void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData) +void WorldSession::HandleWardenData(WorldPackets::Warden::WardenData& packet) { - if (!_warden || recvData.empty()) + if (!_warden || packet.Data.empty()) return; - _warden->DecryptData(recvData.contents(), recvData.size()); + _warden->DecryptData(packet.Data.contents(), packet.Data.size()); uint8 opcode; - recvData >> opcode; - TC_LOG_DEBUG("warden", "Got packet, opcode %02X, size %u", opcode, uint32(recvData.size())); - recvData.hexlike(); + packet.Data >> opcode; + TC_LOG_DEBUG("warden", "Got packet, opcode %02X, size %u", opcode, uint32(packet.Data.size())); + packet.Data.hexlike(); switch (opcode) { @@ -240,20 +241,20 @@ void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData) _warden->RequestHash(); break; case WARDEN_CMSG_CHEAT_CHECKS_RESULT: - _warden->HandleData(recvData); + _warden->HandleData(packet.Data); break; case WARDEN_CMSG_MEM_CHECKS_RESULT: TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!"); break; case WARDEN_CMSG_HASH_RESULT: - _warden->HandleHashResult(recvData); + _warden->HandleHashResult(packet.Data); _warden->InitializeModule(); break; case WARDEN_CMSG_MODULE_FAILED: TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MODULE_FAILED received!"); break; default: - TC_LOG_DEBUG("warden", "Got unknown warden opcode %02X of size %u.", opcode, uint32(recvData.size() - 1)); + TC_LOG_DEBUG("warden", "Got unknown warden opcode %02X of size %u.", opcode, uint32(packet.Data.size() - 1)); break; } } From b0d8357d144613a03d1ead3fe67d231aa67f5847 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Thu, 4 Feb 2016 01:11:37 +0100 Subject: [PATCH 33/79] Warning fix --- src/server/game/Handlers/SpellHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 1a0d5b16663..ef7c8a8e915 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -589,7 +589,7 @@ void WorldSession::HandleUpdateMissileTrajectory(WorldPackets::Spells::UpdateMis { Unit* caster = ObjectAccessor::GetUnit(*_player, packet.Guid); Spell* spell = caster ? caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) : NULL; - if (!spell || spell->m_spellInfo->Id != packet.SpellID || !spell->m_targets.HasDst() || !spell->m_targets.HasSrc()) + if (!spell || spell->m_spellInfo->Id != uint32(packet.SpellID) || !spell->m_targets.HasDst() || !spell->m_targets.HasSrc()) return; Position pos = *spell->m_targets.GetSrcPos(); From f1685b97d918ec4d4b55070244b30af4f0b45e0d Mon Sep 17 00:00:00 2001 From: Carbenium Date: Thu, 4 Feb 2016 01:33:05 +0100 Subject: [PATCH 34/79] Core/PacketIO: Enable SMSG_AREA_TRIGGER_NO_CORPSE --- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 36fc1d10ef2..70ccac98916 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -822,7 +822,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARCHAEOLOGY_SURVERY_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_DENIED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_NO_CORPSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_NO_CORPSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_RE_PATH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_RE_SHAPE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From 0fc728efb9491bdbbc7c964402d566ade47bce0c Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 4 Feb 2016 21:00:00 +0100 Subject: [PATCH 35/79] Core/PacketIO: Updated and enabled SMSG_AREA_SPIRIT_HEALER_TIME --- src/server/game/Battlefield/Battlefield.cpp | 11 +++++------ src/server/game/Battlefield/Battlefield.h | 2 +- src/server/game/Battlegrounds/BattlegroundMgr.cpp | 10 ++++++---- src/server/game/Battlegrounds/BattlegroundMgr.h | 2 +- .../game/Server/Packets/BattlegroundPackets.cpp | 8 ++++++++ .../game/Server/Packets/BattlegroundPackets.h | 15 +++++++++++++-- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 72c03f7fbce..2f4d101b4f1 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -624,13 +624,12 @@ void Battlefield::RemovePlayerFromResurrectQueue(ObjectGuid playerGuid) } } -void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid guid) +void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid) { - WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time = m_LastResurrectTimer; // resurrect every 30 seconds - - data << guid << time; - player->SendDirectMessage(&data); + WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime; + areaSpiritHealerTime.HealerGuid = guid; + areaSpiritHealerTime.TimeLeft = m_LastResurrectTimer; + player->SendDirectMessage(areaSpiritHealerTime.Write()); } // ---------------------- diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 1b28dd82ed1..0159ba95eeb 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -334,7 +334,7 @@ class Battlefield : public ZoneScript /// Return if we can use mount in battlefield bool CanFlyIn() { return !m_isActive; } - void SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid guid); + void SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid); void StartBattle(); void EndBattle(bool endByTimer); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index f39babba46e..57f61c0e195 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -592,14 +592,16 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt TC_LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance %u (bgType %u) not found while trying to teleport player %s", instanceId, bgTypeId, player->GetName().c_str()); } -void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid) +void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid const& guid) { - WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds if (time_ == uint32(-1)) time_ = 0; - data << guid << time_; - player->GetSession()->SendPacket(&data); + + WorldPackets::Battleground::AreaSpiritHealerTime areaSpiritHealerTime; + areaSpiritHealerTime.HealerGuid = guid; + areaSpiritHealerTime.TimeLeft = time_; + player->GetSession()->SendPacket(areaSpiritHealerTime.Write()); } bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId) diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 9f776e3c62b..354f37b8cd8 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -90,7 +90,7 @@ class BattlegroundMgr void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive* battlefieldStatus, Battleground* bg, Player* player, uint32 ticketId, uint32 joinTime, uint32 arenaType); void BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued* battlefieldStatus, Battleground* bg, Player* player, uint32 ticketId, uint32 joinTime, uint32 avgWaitTime, uint32 arenaType, bool asGroup); void BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed* battlefieldStatus, Battleground* bg, Player* pPlayer, uint32 ticketId, uint32 arenaType, GroupJoinBattlegroundResult result, ObjectGuid const* errorGuid = nullptr); - void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid); + void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid const& guid); /* Battlegrounds */ Battleground* GetBattleground(uint32 InstanceID, BattlegroundTypeId bgTypeId); diff --git a/src/server/game/Server/Packets/BattlegroundPackets.cpp b/src/server/game/Server/Packets/BattlegroundPackets.cpp index cc1eee44c2c..52b99035141 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.cpp +++ b/src/server/game/Server/Packets/BattlegroundPackets.cpp @@ -35,6 +35,14 @@ void WorldPackets::Battleground::AreaSpiritHealerQueue::Read() _worldPacket >> HealerGuid; } +WorldPacket const* WorldPackets::Battleground::AreaSpiritHealerTime::Write() +{ + _worldPacket << HealerGuid; + _worldPacket << int32(TimeLeft); + + return &_worldPacket; +} + ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::PVPLogData::RatingData const& ratingData) { data.append(ratingData.Prematch, 2); diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h index 45d0bebc545..e67860e6727 100644 --- a/src/server/game/Server/Packets/BattlegroundPackets.h +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -59,6 +59,17 @@ namespace WorldPackets ObjectGuid HealerGuid; }; + class AreaSpiritHealerTime final : public ServerPacket + { + public: + AreaSpiritHealerTime() : ServerPacket(SMSG_AREA_SPIRIT_HEALER_TIME, 14 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid HealerGuid; + int32 TimeLeft = 0; + }; + class HearthAndResurrect final : public ClientPacket { public: @@ -383,7 +394,7 @@ namespace WorldPackets { public: RequestPVPRewards(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PVP_REWARDS, std::move(packet)) { } - + void Read() override { } }; @@ -391,7 +402,7 @@ namespace WorldPackets { public: RequestRatedBattlefieldInfo(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, std::move(packet)) { } - + void Read() override { } }; } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 70ccac98916..d95510de220 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -820,7 +820,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_GUILD_ACHIEVEMENTS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARCHAEOLOGY_SURVERY_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_DENIED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_NO_CORPSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_RE_PATH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From bc0850c3aa30568b2960893af7e5b905553c7097 Mon Sep 17 00:00:00 2001 From: MitchesD Date: Thu, 4 Feb 2016 21:55:10 +0100 Subject: [PATCH 36/79] Core/Opcodes: enabled SMSG_PVP_CREDIT --- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index d95510de220..bfb819e2f71 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1458,7 +1458,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PRINT_NOTIFICATION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROC_RESIST, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROPOSE_LEVEL_GRANT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER, CONNECTION_TYPE_REALM); From 75598953fb754962495ba5624dbd21317154a01e Mon Sep 17 00:00:00 2001 From: Carbenium Date: Fri, 5 Feb 2016 00:47:58 +0100 Subject: [PATCH 37/79] Core/PacketIO: Enable SMSG_CORPSE_TRANSPORT_QUERY --- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index bfb819e2f71..436927a4022 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1003,7 +1003,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_COOLDOWN_EVENT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_LOCATION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_TRANSPORT_QUERY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_TRANSPORT_QUERY, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATE_CHAR, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATE_SHIPMENT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); From 8e8f51848c5487406d65f080d6824ce20952d0cd Mon Sep 17 00:00:00 2001 From: Carbenium Date: Fri, 5 Feb 2016 01:04:59 +0100 Subject: [PATCH 38/79] Core/PacketIO: Enable SMSG_GM_TICKET_SYSTEM_STATUS, SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, SMSG_PLAY_SCENE and SMSG_QUERY_ITEM_TEXT_RESPONSE --- src/server/game/Server/Protocol/Opcodes.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 436927a4022..194cb78e1db 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1124,7 +1124,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1384,7 +1384,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MONEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_RECEIVED_MAIL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_MONSTER_MOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_CONTAINER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1446,7 +1446,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_OBJECT_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_ONE_SHOT_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_ORPHAN_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SCENE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SCENE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SOUND, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPEAKERBOT_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1467,7 +1467,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GAME_OBJECT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GARRISON_CREATURE_NAME_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GUILD_INFO_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_ITEM_TEXT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_ITEM_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_NPC_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_PAGE_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_PETITION_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); From d3c556bc40a0aab7e576c1dc8b5f43af9bc82480 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Fri, 5 Feb 2016 01:18:55 +0100 Subject: [PATCH 39/79] Core/PacketIO: Enable SMSG_SPELL_MISS_LOG and SMSG_UPDATE_LAST_INSTANCE --- src/server/game/Server/Packets/TicketPackets.cpp | 2 +- src/server/game/Server/Protocol/Opcodes.cpp | 4 ++-- src/server/game/Support/SupportMgr.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index 88ec0dc9465..1e9eb14e3ea 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -252,7 +252,7 @@ void WorldPackets::Ticket::Complaint::Read() case SUPPORT_SPAM_TYPE_MAIL: _worldPacket >> MailID; break; - case SUPPORT_SAPM_TYPE_CHAT: + case SUPPORT_SPAM_TYPE_CHAT: _worldPacket >> Chat; break; case SUPPORT_SPAM_TYPE_CALENDAR: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 194cb78e1db..1422bfab670 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1614,7 +1614,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_HEAL_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INSTAKILL_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INTERRUPT_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MISS_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MISS_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MULTISTRIKE_EFFECT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_NON_MELEE_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_OR_DAMAGE_IMMUNE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1672,7 +1672,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_EXPANSION_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_TALENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_TASK_PROGRESS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Support/SupportMgr.h b/src/server/game/Support/SupportMgr.h index 61dae5fd6da..f79f71e7b2f 100644 --- a/src/server/game/Support/SupportMgr.h +++ b/src/server/game/Support/SupportMgr.h @@ -43,8 +43,8 @@ enum GMSupportComplaintType enum SupportSpamType { - SUPPORT_SPAM_TYPE_MAIL = 0, - SUPPORT_SAPM_TYPE_CHAT = 1, + SUPPORT_SPAM_TYPE_MAIL = 0, + SUPPORT_SPAM_TYPE_CHAT = 1, SUPPORT_SPAM_TYPE_CALENDAR = 2 }; From 38d6054d52500cf3d6ab0f399b746c4750dcac95 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 5 Feb 2016 21:21:54 +0100 Subject: [PATCH 40/79] Core/PacketIO: Marked SMSG_COMPRESSED_PACKET as enabled (this commit has no effect whether it is enabled or not - this opcode is always enabled as it is sent directly from WorldSocket) --- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 1422bfab670..ed0feb6415b 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -992,7 +992,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_STATE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLAINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLETE_SHIPMENT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_PACKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_PACKET, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONNECT_TO, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONQUEST_FORMULA_CONSTANTS, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONSOLE_WRITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From 983635458bbe84b359713693da0be2bfdcd55536 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 6 Feb 2016 13:53:56 +0100 Subject: [PATCH 41/79] Warning fix --- src/server/game/Entities/Unit/Unit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 3ef6800c7e7..ddc0bf14278 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -668,7 +668,7 @@ enum DamageEffectType }; // Value masks for UNIT_FIELD_FLAGS -enum UnitFlags +enum UnitFlags : uint32 { UNIT_FLAG_SERVER_CONTROLLED = 0x00000001, // set only when unit movement is controlled by server - by SPLINE/MONSTER_MOVE packets, together with UNIT_FLAG_STUNNED; only set to units controlled by client; client function CGUnit_C::IsClientControlled returns false when set for owner UNIT_FLAG_NON_ATTACKABLE = 0x00000002, // not attackable From 3ac2ba721da344b2dda9b2e95d40a1faf36ddc6d Mon Sep 17 00:00:00 2001 From: joschiwald Date: Sat, 6 Feb 2016 18:14:28 +0100 Subject: [PATCH 42/79] Core/Gossips: added some sanity checks to prevent duplicate interaction (cherry picked from commit 8b6954e81b76f8d7c6700eaf1a8b942bebaa85a0) Scripts: addition to 8b6954e81b76f8d7c6700eaf1a8b942bebaa85a0 Closes #16466 (cherry picked from commit b259d5c2bc41a545aad978c286f21347c0ba51a2) --- src/server/game/Entities/Player/Player.cpp | 22 +++++++++++++++---- src/server/game/Entities/Player/Player.h | 5 +++-- src/server/game/Handlers/NPCHandler.cpp | 10 ++++----- src/server/game/Handlers/QuestHandler.cpp | 2 +- src/server/game/Handlers/SpellHandler.cpp | 21 ++++++------------ .../Ulduar/boss_algalon_the_observer.cpp | 3 +++ .../Ulduar/Ulduar/boss_flame_leviathan.cpp | 3 +++ .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 3 +++ 8 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 906ee2628ef..b3007affd83 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2124,7 +2124,7 @@ bool Player::CanInteractWithQuestGiver(Object* questGiver) const return false; } -Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint64 npcflagmask) const +Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, uint64 npcflagmask) const { // unit checks if (!guid) @@ -2168,7 +2168,21 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint64 npcflagmask) c return creature; } -GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTypes type) const +GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const +{ + if (GameObject* go = GetMap()->GetGameObject(guid)) + { + if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) + return go; + + TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal %f is allowed)", + go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this), go->GetInteractionDistance()); + } + + return nullptr; +} + +GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const { if (GameObject* go = GetMap()->GetGameObject(guid)) { @@ -2177,8 +2191,8 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTy if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) return go; - TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal 10 is allowed)", - go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this)); + TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal %f is allowed)", + go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this), go->GetInteractionDistance()); } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d6fcd7a3cee..b5221a8cbc5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1229,8 +1229,9 @@ class Player : public Unit, public GridObject void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome) const; bool CanInteractWithQuestGiver(Object* questGiver) const; - Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint64 npcflagmask) const; - GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTypes type) const; + Creature* GetNPCIfCanInteractWith(ObjectGuid const& guid, uint64 npcflagmask) const; + GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const; + GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const; void ToggleAFK(); void ToggleDND(); diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 570e5b4ce48..7590ef2b120 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -256,7 +256,7 @@ void WorldSession::SendTrainerBuyFailed(ObjectGuid trainerGUID, uint32 spellID, void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) { - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_NONE); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_GOSSIP); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); @@ -296,7 +296,6 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) unit->AI()->sGossipHello(_player); } - void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelectOption& packet) { if (!_player->PlayerTalkClass->GetGossipMenu().GetItem(packet.GossipIndex)) @@ -310,20 +309,19 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelec GameObject* go = nullptr; if (packet.GossipUnit.IsCreatureOrVehicle()) { - unit = GetPlayer()->GetNPCIfCanInteractWith(packet.GossipUnit, UNIT_NPC_FLAG_NONE); + unit = GetPlayer()->GetNPCIfCanInteractWith(packet.GossipUnit, UNIT_NPC_FLAG_GOSSIP); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with him.", packet.GossipUnit.ToString().c_str()); return; } } else if (packet.GossipUnit.IsGameObject()) { - go = _player->GetMap()->GetGameObject(packet.GossipUnit); + go = _player->GetGameObjectIfCanInteractWith(packet.GossipUnit); if (!go) { - TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found.", packet.GossipUnit.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", packet.GossipUnit.ToString().c_str()); return; } } diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 78fe8f7661b..0b496100346 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -71,7 +71,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHe { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_HELLO %s", packet.QuestGiverGUID.ToString().c_str()); - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.QuestGiverGUID, UNIT_NPC_FLAG_NONE); + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.QuestGiverGUID, UNIT_NPC_FLAG_QUESTGIVER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleQuestgiverHelloOpcode - %s not found or you can't interact with him.", diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index ef7c8a8e915..3ee24ef401e 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -216,11 +216,8 @@ void WorldSession::HandleOpenItemOpcode(WorldPackets::Spells::OpenItem& packet) void WorldSession::HandleGameObjectUseOpcode(WorldPackets::GameObject::GameObjUse& packet) { - if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(packet.Guid)) + if (GameObject* obj = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid)) { - if (!obj->IsWithinDistInMap(GetPlayer(), obj->GetInteractionDistance())) - return; - // ignore for remote control state if (GetPlayer()->m_mover != GetPlayer()) if (!(GetPlayer()->IsOnVehicle(GetPlayer()->m_mover) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted()) @@ -236,17 +233,13 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjRe if (_player->m_mover != _player) return; - GameObject* go = GetPlayer()->GetMap()->GetGameObject(packet.Guid); - if (!go) - return; + if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid)) + { + if (go->AI()->GossipHello(_player)) + return; - if (!go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - return; - - if (go->AI()->GossipHello(_player)) - return; - - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); + _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); + } } void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 44686e80115..77657870320 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -979,6 +979,9 @@ class go_celestial_planetarium_access : public GameObjectScript bool GossipHello(Player* player) override { + if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE)) + return true; + bool hasKey = true; if (LockEntry const* lock = sLockStore.LookupEntry(go->GetGOInfo()->GetLockId())) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 2907fb09186..e1c02e7ad99 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -1186,6 +1186,7 @@ class npc_brann_bronzebeard_ulduar_intro : public CreatureScript { if (menuId == GOSSIP_MENU_BRANN_BRONZEBEARD && gossipListId == GOSSIP_OPTION_BRANN_BRONZEBEARD) { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); player->PlayerTalkClass->SendCloseGossip(); if (Creature* loreKeeper = _instance->GetCreature(DATA_LORE_KEEPER_OF_NORGANNON)) loreKeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); @@ -1238,6 +1239,7 @@ class npc_lorekeeper : public CreatureScript { if (menuId == GOSSIP_MENU_LORE_KEEPER && gossipListId == GOSSIP_OPTION_LORE_KEEPER) { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); player->PlayerTalkClass->SendCloseGossip(); _instance->instance->LoadGrid(364, -16); // make sure leviathan is loaded @@ -1250,6 +1252,7 @@ class npc_lorekeeper : public CreatureScript { if (Creature* brann = _instance->GetCreature(DATA_BRANN_BRONZEBEARD_INTRO)) { + brann->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); delorah->GetMotionMaster()->MovePoint(0, brann->GetPositionX() - 4, brann->GetPositionY(), brann->GetPositionZ()); /// @todo delorah->AI()->Talk(xxxx, brann->GetGUID()); when reached at branz } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 059ec7de4e8..3378185c2a8 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -1636,6 +1636,9 @@ class go_mimiron_hardmode_button : public GameObjectScript bool OnGossipHello(Player* /*player*/, GameObject* go) override { + if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE)) + return true; + InstanceScript* instance = go->GetInstanceScript(); if (!instance) return false; From 3bdde71a97e3436ae3b4ed59a8ff44a1faea8ecb Mon Sep 17 00:00:00 2001 From: Carbenium Date: Sat, 6 Feb 2016 23:05:55 +0100 Subject: [PATCH 43/79] Core/PacketIO: Updated and enabled SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION --- src/server/game/Handlers/SpellHandler.cpp | 12 +++++------- src/server/game/Server/Packets/SpellPackets.cpp | 9 +++++++++ src/server/game/Server/Packets/SpellPackets.h | 12 ++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 3ee24ef401e..4a28c076ce6 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -569,13 +569,11 @@ void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::Missil pos.Relocate(packet.CollisionPos); spell->m_targets.ModDst(pos); - WorldPacket data(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, 21); - data << packet.Target; - data << uint8(packet.CastID); - data << float(packet.CollisionPos.x); - data << float(packet.CollisionPos.y); - data << float(packet.CollisionPos.z); - caster->SendMessageToSet(&data, true); + WorldPackets::Spells::NotifyMissileTrajectoryCollision notify; + notify.Caster = packet.Target; + notify.CastID = packet.CastID; + notify.CollisionPos = packet.CollisionPos; + caster->SendMessageToSet(notify.Write(), true); } void WorldSession::HandleUpdateMissileTrajectory(WorldPackets::Spells::UpdateMissileTrajectory& packet) diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index ff6ec903990..f1cb69c32db 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -808,6 +808,15 @@ void WorldPackets::Spells::MissileTrajectoryCollision::Read() _worldPacket >> CollisionPos; } +WorldPacket const * WorldPackets::Spells::NotifyMissileTrajectoryCollision::Write() +{ + _worldPacket << Caster; + _worldPacket << uint8(CastID); + _worldPacket << CollisionPos; + + return &_worldPacket; +} + void WorldPackets::Spells::UpdateMissileTrajectory::Read() { _worldPacket >> Guid; diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 042c32ac66e..15a2ac34fc2 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -839,6 +839,18 @@ namespace WorldPackets G3D::Vector3 CollisionPos; }; + class NotifyMissileTrajectoryCollision : public ServerPacket + { + public: + NotifyMissileTrajectoryCollision() : ServerPacket(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, 8 + 1 + 12) { } + + WorldPacket const* Write() override; + + ObjectGuid Caster; + uint8 CastID = 0; + G3D::Vector3 CollisionPos; + }; + class UpdateMissileTrajectory final : public ClientPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index ed0feb6415b..6b9974da93c 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1380,7 +1380,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MONEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_RECEIVED_MAIL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM); From 4d956c89fc6f20c546a396573cf42aa97b844c09 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 7 Feb 2016 12:12:42 +0100 Subject: [PATCH 44/79] Core/Maps: Use IsValidMapCoord for checking Z coord instead of just std::isfinite - only acceptable values are between -17066.6656 and 17066.6656 --- src/server/game/Grids/GridDefines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 09bcbfb5e64..1e304fcaca3 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -227,7 +227,7 @@ namespace Trinity inline bool IsValidMapCoord(float x, float y, float z) { - return IsValidMapCoord(x, y) && std::isfinite(z); + return IsValidMapCoord(x, y) && IsValidMapCoord(z); } inline bool IsValidMapCoord(float x, float y, float z, float o) From f5ccb7b47480cd9064423da8fe2878992175d8b4 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Sun, 7 Feb 2016 21:02:35 +0100 Subject: [PATCH 45/79] Core/PacketIO: Updated and enabled SMSG_SET_PLAYER_DECLINED_NAMES_RESULT --- src/server/game/Handlers/CharacterHandler.cpp | 10 +++++----- src/server/game/Server/Packets/CharacterPackets.cpp | 8 ++++++++ src/server/game/Server/Packets/CharacterPackets.h | 11 +++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e34b2320c10..ef197cbe541 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -2548,11 +2548,11 @@ void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Cha void WorldSession::SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, ObjectGuid guid) { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4 + 8); - data << uint32(result); - if (result == DECLINED_NAMES_RESULT_SUCCESS) - data << guid; - SendPacket(&data); + WorldPackets::Character::SetPlayerDeclinedNamesResult packet; + packet.ResultCode = result; + packet.Player = guid; + + SendPacket(packet.Write()); } void WorldSession::SendBarberShopResult(BarberShopResult result) diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index ed47b32cbcb..d54402d40c7 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -558,3 +558,11 @@ void WorldPackets::Character::SetPlayerDeclinedNames::Read() for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) DeclinedNames.name[i] = _worldPacket.ReadString(stringLengths[i]); } + +WorldPacket const * WorldPackets::Character::SetPlayerDeclinedNamesResult::Write() +{ + _worldPacket << int32(ResultCode); + _worldPacket << Player; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index 732e543d3fc..bb163b075cc 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -727,6 +727,17 @@ namespace WorldPackets ObjectGuid Player; DeclinedName DeclinedNames; }; + + class SetPlayerDeclinedNamesResult final : public ServerPacket + { + public: + SetPlayerDeclinedNamesResult() : ServerPacket(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 8 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid Player; + int32 ResultCode = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 6b9974da93c..7adadcffeb9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1584,7 +1584,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MOVEMENT_ANIM_KIT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PET_SPECIALIZATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_SPELL_CHARGES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); From 43642630c7cc8a96009a6cb7edbaa895c41f63c0 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 8 Feb 2016 20:57:52 +0100 Subject: [PATCH 46/79] Dep/CascLib: Update to ladislav-zezula/CascLib@919a2d670cb749c501ee15887a88e9b9a538961b --- dep/CascLib/CMakeLists.txt | 13 +- dep/CascLib/src/CascBuildCfg.cpp | 1032 -------------- dep/CascLib/src/CascCommon.cpp | 23 + dep/CascLib/src/CascCommon.h | 255 ++-- dep/CascLib/src/CascDecompress.cpp | 41 +- dep/CascLib/src/CascDecrypt.cpp | 300 +++++ dep/CascLib/src/CascDumpData.cpp | 336 ++--- dep/CascLib/src/CascFiles.cpp | 981 ++++++++++++++ dep/CascLib/src/CascFindFile.cpp | 235 ++-- dep/CascLib/src/CascLib.def | 29 + dep/CascLib/src/CascLib.h | 16 +- .../src/{CascMndxRoot.h => CascMndx.h} | 12 +- dep/CascLib/src/CascOpenFile.cpp | 155 +-- dep/CascLib/src/CascOpenStorage.cpp | 632 +++------ dep/CascLib/src/CascPort.h | 1 + dep/CascLib/src/CascReadFile.cpp | 142 +- dep/CascLib/src/CascRootFile_Diablo3.cpp | 1189 +++++++++++++++++ ...CascMndxRoot.cpp => CascRootFile_Mndx.cpp} | 448 ++++--- ...Root_x86.asm => CascRootFile_Mndx_x86.asm} | 158 +-- dep/CascLib/src/CascRootFile_Ovr.cpp | 199 +++ dep/CascLib/src/CascRootFile_WoW6.cpp | 531 ++++++++ dep/CascLib/src/common/Common.cpp | 230 ++-- dep/CascLib/src/common/Common.h | 24 +- dep/CascLib/src/common/Directory.h | 29 + dep/CascLib/src/common/DumpContext.cpp | 153 +++ dep/CascLib/src/common/DumpContext.h | 38 + dep/CascLib/src/common/DynamicArray.cpp | 101 ++ dep/CascLib/src/common/DynamicArray.h | 37 + dep/CascLib/src/common/FileStream.cpp | 1 - dep/CascLib/src/common/ListFile.cpp | 338 ++--- dep/CascLib/src/common/ListFile.h | 4 + dep/CascLib/src/common/Map.cpp | 183 ++- dep/CascLib/src/common/Map.h | 13 +- dep/CascLib/src/common/RootHandler.cpp | 78 ++ dep/CascLib/src/common/RootHandler.h | 88 ++ .../src/libtomcrypt/src/misc/crypt_argchk.c | 4 +- 36 files changed, 5247 insertions(+), 2802 deletions(-) delete mode 100644 dep/CascLib/src/CascBuildCfg.cpp create mode 100644 dep/CascLib/src/CascDecrypt.cpp create mode 100644 dep/CascLib/src/CascFiles.cpp create mode 100644 dep/CascLib/src/CascLib.def rename dep/CascLib/src/{CascMndxRoot.h => CascMndx.h} (95%) create mode 100644 dep/CascLib/src/CascRootFile_Diablo3.cpp rename dep/CascLib/src/{CascMndxRoot.cpp => CascRootFile_Mndx.cpp} (91%) rename dep/CascLib/src/{CascMndxRoot_x86.asm => CascRootFile_Mndx_x86.asm} (98%) create mode 100644 dep/CascLib/src/CascRootFile_Ovr.cpp create mode 100644 dep/CascLib/src/CascRootFile_WoW6.cpp create mode 100644 dep/CascLib/src/common/Directory.h create mode 100644 dep/CascLib/src/common/DumpContext.cpp create mode 100644 dep/CascLib/src/common/DumpContext.h create mode 100644 dep/CascLib/src/common/DynamicArray.cpp create mode 100644 dep/CascLib/src/common/DynamicArray.h create mode 100644 dep/CascLib/src/common/RootHandler.cpp create mode 100644 dep/CascLib/src/common/RootHandler.h diff --git a/dep/CascLib/CMakeLists.txt b/dep/CascLib/CMakeLists.txt index 429ebfb78e8..83b7ea38493 100644 --- a/dep/CascLib/CMakeLists.txt +++ b/dep/CascLib/CMakeLists.txt @@ -1,7 +1,7 @@ set(HEADER_FILES src/CascCommon.h src/CascLib.h - src/CascMndxRoot.h + src/CascMndx.h src/CascPort.h src/common/Common.h src/common/FileStream.h @@ -13,19 +13,26 @@ set(HEADER_FILES set(SRC_FILES src/common/Common.cpp src/common/Directory.cpp + src/common/DumpContext.cpp + src/common/DynamicArray.cpp src/common/FileStream.cpp src/common/ListFile.cpp src/common/Map.cpp + src/common/RootHandler.cpp src/jenkins/lookup3.c - src/CascBuildCfg.cpp src/CascCommon.cpp src/CascDecompress.cpp + src/CascDecrypt.cpp src/CascDumpData.cpp + src/CascFiles.cpp src/CascFindFile.cpp - src/CascMndxRoot.cpp src/CascOpenFile.cpp src/CascOpenStorage.cpp src/CascReadFile.cpp + src/CascRootFile_Diablo3.cpp + src/CascRootFile_Mndx.cpp + src/CascRootFile_Ovr.cpp + src/CascRootFile_WoW6.cpp ) set(TOMCRYPT_FILES diff --git a/dep/CascLib/src/CascBuildCfg.cpp b/dep/CascLib/src/CascBuildCfg.cpp deleted file mode 100644 index f39f09d886a..00000000000 --- a/dep/CascLib/src/CascBuildCfg.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/*****************************************************************************/ -/* CascBuildCfg.cpp Copyright (c) Ladislav Zezula 2014 */ -/*---------------------------------------------------------------------------*/ -/* Build configuration for CascLib */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 29.04.14 1.00 Lad The first version of CascBuildCfg.cpp */ -/*****************************************************************************/ - -#define __CASCLIB_SELF__ -#include "CascLib.h" -#include "CascCommon.h" - -//----------------------------------------------------------------------------- -// Local functions - -static bool inline IsValueSeparator(LPBYTE pbVarValue) -{ - return ((0 <= pbVarValue[0] && pbVarValue[0] <= 0x20) || (pbVarValue[0] == '|')); -} - -static bool IsCharDigit(BYTE OneByte) -{ - return ('0' <= OneByte && OneByte <= '9'); -} - -static void FreeCascBlob(PQUERY_KEY pBlob) -{ - if(pBlob != NULL) - { - if(pBlob->pbData != NULL) - CASC_FREE(pBlob->pbData); - - pBlob->pbData = NULL; - pBlob->cbData = 0; - } -} - -static DWORD GetLocaleMask(const char * szTag) -{ - if(!strcmp(szTag, "enUS")) - return CASC_LOCALE_ENUS; - - if(!strcmp(szTag, "koKR")) - return CASC_LOCALE_KOKR; - - if(!strcmp(szTag, "frFR")) - return CASC_LOCALE_FRFR; - - if(!strcmp(szTag, "deDE")) - return CASC_LOCALE_DEDE; - - if(!strcmp(szTag, "zhCN")) - return CASC_LOCALE_ZHCN; - - if(!strcmp(szTag, "esES")) - return CASC_LOCALE_ESES; - - if(!strcmp(szTag, "zhTW")) - return CASC_LOCALE_ZHTW; - - if(!strcmp(szTag, "enGB")) - return CASC_LOCALE_ENGB; - - if(!strcmp(szTag, "enCN")) - return CASC_LOCALE_ENCN; - - if(!strcmp(szTag, "enTW")) - return CASC_LOCALE_ENTW; - - if(!strcmp(szTag, "esMX")) - return CASC_LOCALE_ESMX; - - if(!strcmp(szTag, "ruRU")) - return CASC_LOCALE_RURU; - - if(!strcmp(szTag, "ptBR")) - return CASC_LOCALE_PTBR; - - if(!strcmp(szTag, "itIT")) - return CASC_LOCALE_ITIT; - - if(!strcmp(szTag, "ptPT")) - return CASC_LOCALE_PTPT; - - return 0; -} - -static bool IsInfoVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName, const char * szVarType) -{ - size_t nLength; - - // Check the variable name - nLength = strlen(szVarName); - if((size_t)(szLineEnd - szLineBegin) > nLength) - { - // Check the variable name - if(!_strnicmp(szLineBegin, szVarName, nLength)) - { - // Skip variable name and the exclamation mark - szLineBegin += nLength; - if(szLineBegin < szLineEnd && szLineBegin[0] == '!') - { - // Skip the exclamation mark - szLineBegin++; - - // Check the variable type - nLength = strlen(szVarType); - if((size_t)(szLineEnd - szLineBegin) > nLength) - { - // Check the variable name - if(!_strnicmp(szLineBegin, szVarType, nLength)) - { - // Skip variable type and the doublecolon - szLineBegin += nLength; - return (szLineBegin < szLineEnd && szLineBegin[0] == ':'); - } - } - } - } - } - - return false; -} - -static const char * SkipInfoVariable(const char * szLineBegin, const char * szLineEnd) -{ - while(szLineBegin < szLineEnd) - { - if(szLineBegin[0] == '|') - return szLineBegin + 1; - - szLineBegin++; - } - - return NULL; -} - -static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir) -{ - TCHAR * szIndexPath; - - // Cpmbine the index path - szIndexPath = CombinePath(hs->szDataPath, szSubDir); - if(DirectoryExists(szIndexPath)) - { - hs->szIndexPath = szIndexPath; - return hs->szIndexPath; - } - - CASC_FREE(szIndexPath); - return NULL; -} - -TCHAR * AppendBlobText(TCHAR * szBuffer, LPBYTE pbData, DWORD cbData, TCHAR chSeparator) -{ - // Put the separator, if any - if(chSeparator != 0) - *szBuffer++ = chSeparator; - - // Copy the blob data as text - for(DWORD i = 0; i < cbData; i++) - { - *szBuffer++ = IntToHexChar[pbData[0] >> 0x04]; - *szBuffer++ = IntToHexChar[pbData[0] & 0x0F]; - pbData++; - } - - // Terminate the string - *szBuffer = 0; - - // Return new buffer position - return szBuffer; -} - -static int StringBlobToBinaryBlob( - PQUERY_KEY pBlob, - LPBYTE pbBlobBegin, - LPBYTE pbBlobEnd) -{ - // Sanity checks - assert(pBlob != NULL && pBlob->pbData != NULL); - - // Reset the blob length - pBlob->cbData = 0; - - // Convert the blob - while(pbBlobBegin < pbBlobEnd) - { - BYTE DigitOne; - BYTE DigitTwo; - - DigitOne = (BYTE)(AsciiToUpperTable_BkSlash[pbBlobBegin[0]] - '0'); - if(DigitOne > 9) - DigitOne -= 'A' - '9' - 1; - - DigitTwo = (BYTE)(AsciiToUpperTable_BkSlash[pbBlobBegin[1]] - '0'); - if(DigitTwo > 9) - DigitTwo -= 'A' - '9' - 1; - - if(DigitOne > 0x0F || DigitTwo > 0x0F || pBlob->cbData >= MAX_CASC_KEY_LENGTH) - return ERROR_BAD_FORMAT; - - pBlob->pbData[pBlob->cbData++] = (DigitOne << 0x04) | DigitTwo; - pbBlobBegin += 2; - } - - return ERROR_SUCCESS; -} - - -static LPBYTE FindNextSeparator(PQUERY_KEY pFileBlob, LPBYTE pbFilePtr) -{ - LPBYTE pbFileBegin = pFileBlob->pbData; - LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData; - - if(pbFileBegin <= pbFilePtr && pbFilePtr < pbFileEnd) - { - while(pbFilePtr < pbFileEnd && pbFilePtr[0] != '|') - pbFilePtr++; - - return pbFilePtr; - } - - return NULL; -} - -static bool GetNextFileLine(PQUERY_KEY pFileBlob, LPBYTE * ppbLineBegin, LPBYTE * ppbLineEnd) -{ - LPBYTE pbLineBegin = *ppbLineBegin; - LPBYTE pbLineEnd = *ppbLineEnd; - LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData; - - // If there was a previous line, skip all end-of-line chars - if(pbLineEnd != NULL) - { - // Go to the next line - while(pbLineEnd < pbFileEnd && (pbLineEnd[0] == 0x0A || pbLineEnd[0] == 0x0D)) - pbLineEnd++; - pbLineBegin = pbLineEnd; - - // If there is no more data, return false - if(pbLineEnd >= pbFileEnd) - return false; - } - - // Skip all spaces before the line begins - while(pbLineBegin < pbFileEnd && (pbLineBegin[0] == 0x09 || pbLineBegin[0] == 0x20)) - pbLineBegin++; - pbLineEnd = pbLineBegin; - - // Go to the end of the line - while(pbLineEnd < pbFileEnd && pbLineEnd[0] != 0x0A && pbLineEnd[0] != 0x0D) - pbLineEnd++; - - // Give the results to the caller - *ppbLineBegin = pbLineBegin; - *ppbLineEnd = pbLineEnd; - return true; -} - -static LPBYTE CheckLineVariable(LPBYTE pbLineBegin, LPBYTE pbLineEnd, const char * szVarName) -{ - size_t nLineLength = (size_t)(pbLineEnd - pbLineBegin); - size_t nNameLength = strlen(szVarName); - - // If the line longer than the variable name? - if(nLineLength > nNameLength) - { - if(!_strnicmp((const char *)pbLineBegin, szVarName, nNameLength)) - { - // Skip the variable name - pbLineBegin += nNameLength; - - // Skip the separator(s) - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - - // Check if there is "=" - if(pbLineBegin >= pbLineEnd || pbLineBegin[0] != '=') - return NULL; - pbLineBegin++; - - // Skip the separator(s) - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - - // Check if there is "=" - if(pbLineBegin >= pbLineEnd) - return NULL; - - // Return the begin of the variable - return pbLineBegin; - } - } - - return NULL; -} - -static int LoadInfoVariable(PQUERY_KEY pVarBlob, const char * szLineBegin, const char * szLineEnd, bool bHexaValue) -{ - const char * szLinePtr = szLineBegin; - - // Sanity checks - assert(pVarBlob->pbData == NULL); - assert(pVarBlob->cbData == 0); - - // Check length of the variable - while(szLinePtr < szLineEnd && szLinePtr[0] != '|') - szLinePtr++; - - // Allocate space for the blob - if(bHexaValue) - { - // Initialize the blob - pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) / 2); - return StringBlobToBinaryBlob(pVarBlob, (LPBYTE)szLineBegin, (LPBYTE)szLinePtr); - } - - // Initialize the blob - pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1); - pVarBlob->cbData = (DWORD)(szLinePtr - szLineBegin); - - // Check for success - if(pVarBlob->pbData == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Copy the string - memcpy(pVarBlob->pbData, szLineBegin, pVarBlob->cbData); - pVarBlob->pbData[pVarBlob->cbData] = 0; - return ERROR_SUCCESS; -} - - -static void AppendConfigFilePath(TCHAR * szFileName, PQUERY_KEY pFileKey) -{ - // Get to the end of the file name - szFileName = szFileName + _tcslen(szFileName); - - // Append the "config" directory - _tcscat(szFileName, _T("/config")); - szFileName += 7; - - // Append the first level directory - szFileName = AppendBlobText(szFileName, pFileKey->pbData, 1, _T('/')); - szFileName = AppendBlobText(szFileName, pFileKey->pbData + 1, 1, _T('/')); - szFileName = AppendBlobText(szFileName, pFileKey->pbData, pFileKey->cbData, _T('/')); -} - -static DWORD GetBlobCount(LPBYTE pbLineBegin, LPBYTE pbLineEnd) -{ - DWORD dwBlobCount = 0; - - // Until we find an end of the line - while(pbLineBegin < pbLineEnd) - { - // Skip the blob - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin) == false) - pbLineBegin++; - - // Increment the number of blobs - dwBlobCount++; - - // Skip the separator - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - } - - return dwBlobCount; -} - -static int LoadBlobArray( - PQUERY_KEY pBlob, - DWORD dwMaxBlobs, - LPBYTE pbLineBegin, - LPBYTE pbLineEnd, - LPBYTE pbBuffer, - DWORD dwBufferSize) -{ - LPBYTE pbBlobBegin = pbLineBegin; - LPBYTE pbBlobEnd = pbLineBegin; - int nError = ERROR_SUCCESS; - - // Sanity check - assert(pbBuffer != NULL); - - // Until we find an end of the line - while(pbBlobBegin < pbLineEnd) - { - // Convert the blob from string to binary - if(dwBufferSize < MAX_CASC_KEY_LENGTH) - return ERROR_NOT_ENOUGH_MEMORY; - - // Find the end of the text blob - while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd) == false) - pbBlobEnd++; - - // Convert the blob from ANSI to binary - pBlob->pbData = pbBuffer; - nError = StringBlobToBinaryBlob(pBlob, pbBlobBegin, pbBlobEnd); - if(nError != ERROR_SUCCESS || dwMaxBlobs == 1) - break; - - // Move the blob, buffer, and limits - dwBufferSize -= MAX_CASC_KEY_LENGTH; - pbBuffer += MAX_CASC_KEY_LENGTH; - dwMaxBlobs--; - pBlob++; - - // Skip the separator - while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd)) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - return nError; -} - -static int LoadSingleBlob(PQUERY_KEY pBlob, LPBYTE pbBlobBegin, LPBYTE pbBlobEnd) -{ - LPBYTE pbBuffer; - size_t nLength = (pbBlobEnd - pbBlobBegin) / 2; - - // Check maximum size - if(nLength > MAX_CASC_KEY_LENGTH) - return ERROR_INVALID_PARAMETER; - - // Allocate the blob buffer - pbBuffer = CASC_ALLOC(BYTE, MAX_CASC_KEY_LENGTH); - if(pbBuffer == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - return LoadBlobArray(pBlob, 1, pbBlobBegin, pbBlobEnd, pbBuffer, MAX_CASC_KEY_LENGTH); -} - -static PQUERY_KEY LoadMultipleBlobs(LPBYTE pbLineBegin, LPBYTE pbLineEnd, DWORD * pdwBlobCount) -{ - PQUERY_KEY pBlobArray = NULL; - LPBYTE pbBuffer = NULL; - DWORD dwBlobCount = GetBlobCount(pbLineBegin, pbLineEnd); - int nError; - - // Only if there is at least 1 blob - if(dwBlobCount != 0) - { - // Allocate the array of blobs - pBlobArray = CASC_ALLOC(QUERY_KEY, dwBlobCount); - if(pBlobArray != NULL) - { - // Zero the blob array - memset(pBlobArray, 0, dwBlobCount * sizeof(QUERY_KEY)); - - // Allocate buffer for the blobs - pbBuffer = CASC_ALLOC(BYTE, dwBlobCount * MAX_CASC_KEY_LENGTH); - if(pbBuffer != NULL) - { - // Zero the buffer - memset(pbBuffer, 0, dwBlobCount * MAX_CASC_KEY_LENGTH); - - // Load the entire blob array - nError = LoadBlobArray(pBlobArray, dwBlobCount, pbLineBegin, pbLineEnd, pbBuffer, dwBlobCount * MAX_CASC_KEY_LENGTH); - if(nError == ERROR_SUCCESS) - { - *pdwBlobCount = dwBlobCount; - return pBlobArray; - } - - // Free the buffer - CASC_FREE(pbBuffer); - } - - // Free the array of blobs - CASC_FREE(pBlobArray); - pBlobArray = NULL; - } - - // Reset the blob count - dwBlobCount = 0; - } - - *pdwBlobCount = dwBlobCount; - return pBlobArray; -} - -static int LoadTextFile(const TCHAR * szFileName, PQUERY_KEY pFileBlob) -{ - TFileStream * pStream; - ULONGLONG FileSize = 0; - int nError = ERROR_SUCCESS; - - // Open the agent file - pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE); - if(pStream != NULL) - { - // Retrieve its size - FileStream_GetSize(pStream, &FileSize); - - // Load the file to memory - if(0 < FileSize && FileSize < 0x100000) - { - // Initialize the blob - pFileBlob->cbData = (DWORD)FileSize; - pFileBlob->pbData = CASC_ALLOC(BYTE, pFileBlob->cbData + 1); - - // Load the file data into the blob - if(pFileBlob->pbData != NULL) - { - FileStream_Read(pStream, NULL, pFileBlob->pbData, (DWORD)FileSize); - pFileBlob->pbData[pFileBlob->cbData] = 0; - } - else - nError = ERROR_NOT_ENOUGH_MEMORY; - } - else - nError = ERROR_INVALID_PARAMETER; - - FileStream_Close(pStream); - } - else - nError = GetLastError(); - - return nError; -} - -static int GetGameType(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd) -{ - // Alpha build of Heroes of the Storm - if((pbLineEnd - pbVarBegin) == 4 && !_strnicmp((const char *)pbVarBegin, "Hero", 4)) - { - hs->dwGameInfo = CASC_GAME_HOTS; - return ERROR_SUCCESS; - } - - // Alpha build of World of Warcraft - Warlords of Draenor - if((pbLineEnd - pbVarBegin) == 3 && !_strnicmp((const char *)pbVarBegin, "WoW", 3)) - { - hs->dwGameInfo = CASC_GAME_WOW6; - return ERROR_SUCCESS; - } - - // Diablo III BETA 2.2.0 - if((pbLineEnd - pbVarBegin) == 7 && !_strnicmp((const char *)pbVarBegin, "Diablo3", 7)) - { - hs->dwGameInfo = CASC_GAME_DIABLO3; - return ERROR_SUCCESS; - } - - // An unknown game - assert(false); - return ERROR_BAD_FORMAT; -} - -// "B29049" -// "WOW-18125patch6.0.1" -// "30013_Win32_2_2_0_Ptr_ptr" -static int GetBuildNumber(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd) -{ - DWORD dwBuildNumber = 0; - - // Skip all non-digit characters - while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0]) == false) - pbVarBegin++; - - // Convert the build number - while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0])) - dwBuildNumber = (dwBuildNumber * 10) + (*pbVarBegin++ - '0'); - - assert(dwBuildNumber != 0); - hs->dwBuildNumber = dwBuildNumber; - return (dwBuildNumber != 0) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; -} - -static int GetDefaultLocaleMask(TCascStorage * hs, PQUERY_KEY pTagsString) -{ - char * szTagEnd = (char *)pTagsString->pbData + pTagsString->cbData; - char * szTagPtr = (char *)pTagsString->pbData; - char * szNext; - DWORD dwLocaleMask = 0; - - while(szTagPtr < szTagEnd) - { - // Get the next part - szNext = strchr(szTagPtr, ' '); - if(szNext != NULL) - *szNext++ = 0; - - // Check whether the current tag is a language identifier - dwLocaleMask = dwLocaleMask | GetLocaleMask(szTagPtr); - - // Get the next part - if(szNext == NULL) - break; - - // Skip spaces - while(szNext < szTagEnd && szNext[0] == ' ') - szNext++; - szTagPtr = szNext; - } - - hs->dwDefaultLocale = dwLocaleMask; - return ERROR_SUCCESS; -} - -static int FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey, PQUERY_KEY pFileBlob) -{ - TCHAR * szFileName; - int nError; - - // Construct the local file name - szFileName = NewStr(hs->szDataPath, 8 + 3 + 3 + 32); - if(szFileName == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Add the part where the config file path is - AppendConfigFilePath(szFileName, pFileKey); - - // Load the config file - nError = LoadTextFile(szFileName, pFileBlob); - if(nError == ERROR_SUCCESS) - { - // Verify the blob's MD5 - if(!VerifyDataBlockHash(pFileBlob->pbData, pFileBlob->cbData, pFileKey->pbData)) - { - FreeCascBlob(pFileBlob); - nError = ERROR_BAD_FORMAT; - } - } - - CASC_FREE(szFileName); - return nError; -} - -static int ParseInfoFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - QUERY_KEY Active = {NULL, 0}; - QUERY_KEY TagString = {NULL, 0}; - QUERY_KEY CdnHost = {NULL, 0}; - QUERY_KEY CdnPath = {NULL, 0}; - const char * szLineBegin1 = NULL; - const char * szLinePtr1 = NULL; - const char * szLineBegin2 = NULL; - const char * szLineEnd1 = NULL; - const char * szLineEnd2 = NULL; - const char * szFileEnd = (const char *)(pFileBlob->pbData + pFileBlob->cbData); - const char * szFilePtr = (const char *)pFileBlob->pbData; - int nError = ERROR_BAD_FORMAT; - - // Find the first line - szLineBegin1 = szFilePtr; - while(szFilePtr < szFileEnd) - { - // Check for the end of the line - if(szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A) - { - szLineEnd1 = szFilePtr; - break; - } - - szFilePtr++; - } - - while (szFilePtr < szFileEnd) - { - szLinePtr1 = szLineBegin1; - - // Skip the newline character(s) - while (szFilePtr < szFileEnd && (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)) - szFilePtr++; - - // Find the next line - szLineBegin2 = szFilePtr; - while (szFilePtr < szFileEnd) - { - // Check for the end of the line - if (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A) - { - szLineEnd2 = szFilePtr; - break; - } - - szFilePtr++; - } - - // Find the build key, CDN config key and the URL path - while (szLinePtr1 < szLineEnd1) - { - // Check for variables we need - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC")) - LoadInfoVariable(&Active, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX")) - LoadInfoVariable(&hs->CdnBuildKey, szLineBegin2, szLineEnd2, true); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX")) - LoadInfoVariable(&hs->CdnConfigKey, szLineBegin2, szLineEnd2, true); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING")) - LoadInfoVariable(&CdnHost, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING")) - LoadInfoVariable(&CdnPath, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING")) - LoadInfoVariable(&TagString, szLineBegin2, szLineEnd2, false); - - // Move both line pointers - szLinePtr1 = SkipInfoVariable(szLinePtr1, szLineEnd1); - if (szLineBegin1 == NULL) - break; - - szLineBegin2 = SkipInfoVariable(szLineBegin2, szLineEnd2); - if (szLineBegin2 == NULL) - break; - } - - // Stop parsing if found active config - if (Active.pbData != NULL && *Active.pbData == '1') - break; - } - - // All four must be present - if(hs->CdnBuildKey.pbData != NULL && - hs->CdnConfigKey.pbData != NULL && - CdnHost.pbData != NULL && - CdnPath.pbData != NULL) - { - // Merge the CDN host and CDN path - hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1); - if(hs->szUrlPath != NULL) - { - CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData); - CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData); - nError = ERROR_SUCCESS; - } - } - - // If we found tags, we can extract language build from it - if(TagString.pbData != NULL) - GetDefaultLocaleMask(hs, &TagString); - - FreeCascBlob(&CdnHost); - FreeCascBlob(&CdnPath); - FreeCascBlob(&TagString); - return nError; -} - -static int ParseAgentFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbBlobBegin = pFileBlob->pbData; - LPBYTE pbBlobEnd; - int nError = ERROR_SUCCESS; - - // Extract the CDN build hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - nError = LoadSingleBlob(&hs->CdnBuildKey, pbBlobBegin, pbBlobEnd); - - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Extract the CDN config hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - nError = LoadSingleBlob(&hs->CdnConfigKey, pbBlobBegin, pbBlobEnd); - - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Skip the intermediate part - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Extract the URL config hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - hs->szUrlPath = NewStrFromAnsi(pbBlobBegin, pbBlobEnd); - } - - // Verify all variables - if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL) - nError = ERROR_BAD_FORMAT; - return nError; -} - -static int LoadCdnConfigFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbLineBegin = pFileBlob->pbData; - LPBYTE pbVarBegin; - LPBYTE pbLineEnd = NULL; - int nError; - - while(pbLineBegin != NULL) - { - // Get the next line - if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd)) - break; - - // Archive group - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archive-group"); - if(pbVarBegin != NULL) - { - nError = LoadSingleBlob(&hs->ArchiveGroup, pbVarBegin, pbLineEnd); - if(nError != ERROR_SUCCESS) - return nError; - continue; - } - - // Archives - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archives"); - if(pbVarBegin != NULL) - { - hs->pArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->ArchiveCount); - if(hs->pArchiveArray == NULL || hs->ArchiveCount == 0) - return ERROR_BAD_FORMAT; - continue; - } - - // Patch archive group - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archive-group"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->PatchArchiveGroup, pbVarBegin, pbLineEnd); - continue; - } - - // Patch archives - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archives"); - if(pbVarBegin != NULL) - { - hs->pPatchArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->PatchArchiveCount); - continue; - } - } - - // Check if all required fields are present - if(hs->ArchiveGroup.pbData == NULL || hs->ArchiveGroup.cbData == 0 || hs->pArchiveArray == NULL || hs->ArchiveCount == 0) - return ERROR_BAD_FORMAT; - - return ERROR_SUCCESS; -} - -static int LoadCdnBuildFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbLineBegin = pFileBlob->pbData; - LPBYTE pbVarBegin; - LPBYTE pbLineEnd = NULL; - - while(pbLineBegin != NULL) - { - // Get the next line - if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd)) - break; - - // Game name - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-product"); - if(pbVarBegin != NULL) - { - GetGameType(hs, pbVarBegin, pbLineEnd); - continue; - } - - // Game build number - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-name"); - if(pbVarBegin != NULL) - { - GetBuildNumber(hs, pbVarBegin, pbLineEnd); - continue; - } - - // Root - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "root"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->RootKey, pbVarBegin, pbLineEnd); - continue; - } - - // Patch - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->PatchKey, pbVarBegin, pbLineEnd); - continue; - } - - // Download - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "download"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->DownloadKey, pbVarBegin, pbLineEnd); - continue; - } - - // Install - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "install"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->InstallKey, pbVarBegin, pbLineEnd); - continue; - } - - // Encoding keys - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "encoding"); - if(pbVarBegin != NULL) - { - hs->pEncodingKeys = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->EncodingKeys); - if(hs->pEncodingKeys == NULL || hs->EncodingKeys != 2) - return ERROR_BAD_FORMAT; - - hs->EncodingKey = hs->pEncodingKeys[0]; - hs->EncodingEKey = hs->pEncodingKeys[1]; - continue; - } - } - - // Check the encoding keys - if(hs->pEncodingKeys == NULL || hs->EncodingKeys == 0) - return ERROR_BAD_FORMAT; - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// Public functions - -int LoadBuildInfo(TCascStorage * hs) -{ - QUERY_KEY InfoFile = {NULL, 0}; - QUERY_KEY FileData = {NULL, 0}; - TCHAR * szAgentFile; - TCHAR * szInfoFile; - bool bBuildConfigComplete = false; - int nError = ERROR_SUCCESS; - - // Since HOTS build 30027, the game uses build.info file for storage info - if(bBuildConfigComplete == false) - { - szInfoFile = CombinePath(hs->szRootPath, _T(".build.info")); - if(szInfoFile != NULL) - { - nError = LoadTextFile(szInfoFile, &InfoFile); - if(nError == ERROR_SUCCESS) - { - // Parse the info file - nError = ParseInfoFile(hs, &InfoFile); - if(nError == ERROR_SUCCESS) - bBuildConfigComplete = true; - - // Free the loaded blob - FreeCascBlob(&InfoFile); - } - - CASC_FREE(szInfoFile); - } - } - - // If the info file has not been loaded, try the legacy .build.db - if(bBuildConfigComplete == false) - { - szAgentFile = CombinePath(hs->szRootPath, _T(".build.db")); - if(szAgentFile != NULL) - { - nError = LoadTextFile(szAgentFile, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = ParseAgentFile(hs, &FileData); - if(nError == ERROR_SUCCESS) - bBuildConfigComplete = true; - - FreeCascBlob(&FileData); - } - CASC_FREE(szAgentFile); - } - } - - // If the .build.info and .build.db file hasn't been loaded, - if(nError == ERROR_SUCCESS && bBuildConfigComplete == false) - { - nError = ERROR_FILE_CORRUPT; - } - - // Load the configuration file - if(nError == ERROR_SUCCESS) - { - nError = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = LoadCdnConfigFile(hs, &FileData); - FreeCascBlob(&FileData); - } - } - - // Load the build file - if(nError == ERROR_SUCCESS) - { - nError = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = LoadCdnBuildFile(hs, &FileData); - FreeCascBlob(&FileData); - } - } - - // Fill the index directory - if(nError == ERROR_SUCCESS) - { - // First, check for more common "data" subdirectory - if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL) - return ERROR_SUCCESS; - - // Second, try the "darch" subdirectory (older builds of HOTS - Alpha) - if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL) - return ERROR_SUCCESS; - - nError = ERROR_FILE_NOT_FOUND; - } - - return nError; -} diff --git a/dep/CascLib/src/CascCommon.cpp b/dep/CascLib/src/CascCommon.cpp index 8ad7d716b82..34c3df66b5c 100644 --- a/dep/CascLib/src/CascCommon.cpp +++ b/dep/CascLib/src/CascCommon.cpp @@ -65,3 +65,26 @@ ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes) return Value; } + +void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes) +{ + ValueAsBytes[0] = (Value >> 0x18) & 0xFF; + ValueAsBytes[1] = (Value >> 0x10) & 0xFF; + ValueAsBytes[2] = (Value >> 0x08) & 0xFF; + ValueAsBytes[3] = (Value >> 0x00) & 0xFF; +} + +//----------------------------------------------------------------------------- +// Common fre routine of a CASC blob + +void FreeCascBlob(PQUERY_KEY pBlob) +{ + if(pBlob != NULL) + { + if(pBlob->pbData != NULL) + CASC_FREE(pBlob->pbData); + + pBlob->pbData = NULL; + pBlob->cbData = 0; + } +} diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h index 7a2b4071dc6..42e158bfcb2 100644 --- a/dep/CascLib/src/CascCommon.h +++ b/dep/CascLib/src/CascCommon.h @@ -23,9 +23,13 @@ #include "CascPort.h" #include "common/Common.h" +#include "common/DynamicArray.h" #include "common/Map.h" #include "common/FileStream.h" +#include "common/Directory.h" #include "common/ListFile.h" +#include "common/DumpContext.h" +#include "common/RootHandler.h" // Headers from LibTomCrypt #include "libtomcrypt/src/headers/tomcrypt.h" @@ -36,16 +40,17 @@ //----------------------------------------------------------------------------- // CascLib private defines -#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm -#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor -#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 Since PTR 2.2.0 -#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID +#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm +#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor +#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 since PTR 2.2.0 +#define CASC_GAME_OVERWATCH 0x00040000 // Overwatch since PTR 24919 +#define CASC_GAME_STARCRAFT2 0x00050000 // Starcraft II - Legacy of the Void, since build 38996 +#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID #define CASC_INDEX_COUNT 0x10 #define CASC_FILE_KEY_SIZE 0x09 // Size of the file key #define CASC_MAX_DATA_FILES 0x100 -#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported -#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX' +#define CASC_EXTRA_FILES 0x20 // Number of extra entries to be reserved for additionally inserted files #define CASC_SEARCH_HAVE_NAME 0x0001 // Indicated that previous search found a name @@ -71,41 +76,28 @@ #define CASC_PACKAGE_BUFFER 0x1000 -//----------------------------------------------------------------------------- -// On-disk structures - -typedef struct _FILE_LOCALE_BLOCK -{ - DWORD NumberOfFiles; // Number of entries - DWORD Flags; - DWORD Locales; // File locale mask (CASC_LOCALE_XXX) - - // Followed by a block of 32-bit integers (count: NumberOfFiles) - // Followed by the MD5 and file name hash (count: NumberOfFiles) - -} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK; - -typedef struct _FILE_ROOT_ENTRY -{ - DWORD EncodingKey[4]; // MD5 of the file - ULONGLONG FileNameHash; // Jenkins hash of the file name - -} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY; - -typedef struct _ROOT_BLOCK_INFO -{ - PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block - PDWORD pInt32Array; // Pointer to the array of 32-bit integers - PFILE_ROOT_ENTRY pRootEntries; - -} ROOT_BLOCK_INFO, *PROOT_BLOCK_INFO; +#ifndef _maxchars +#define _maxchars(buff) ((sizeof(buff) / sizeof(buff[0])) - 1) +#endif //----------------------------------------------------------------------------- // In-memory structures +// See http://pxr.dk/wowdev/wiki/index.php?title=CASC for more information -class TMndxFindResult; struct TFileStream; -struct _MAR_FILE; + +typedef enum _CBLD_TYPE +{ + CascBuildNone = 0, // No build type found + CascBuildInfo, // .build.info + CascBuildDb, // .build.db (older storages) +} CBLD_TYPE, *PCBLD_TYPE; + +typedef struct _ENCODING_KEY +{ + BYTE Value[MD5_HASH_SIZE]; // MD5 of the file + +} ENCODING_KEY, *PENCODING_KEY; typedef struct _CASC_INDEX_ENTRY { @@ -140,25 +132,34 @@ typedef struct _CASC_FILE_FRAME BYTE md5[MD5_HASH_SIZE]; // MD5 hash of the file sector } CASC_FILE_FRAME, *PCASC_FILE_FRAME; +// The encoding file is in the form of: +// * File header +// * String block #1 +// * Table A header +// * Table A entries +// * Table B header +// * Table B entries +// * String block #2 +// http://pxr.dk/wowdev/wiki/index.php?title=CASC#Key_CASC_Files typedef struct _CASC_ENCODING_HEADER { BYTE Magic[2]; // "EN" - BYTE field_2; - BYTE field_3; - BYTE field_4; - BYTE field_5[2]; - BYTE field_7[2]; - BYTE NumSegments[4]; // Number of entries (big endian) - BYTE field_D[4]; + BYTE Version; // Expected to be 1 by CascLib + BYTE ChecksumSizeA; // The length of the checksums in Encoding Table + BYTE ChecksumSizeB; // The length of the checksums in Encoding Layout Table + BYTE Flags_TableA[2]; // Flags for Encoding Table + BYTE Flags_TableB[2]; // Flags for Encoding Layout Table + BYTE Entries_TableA[4]; // Number of segments in Encoding Table (big endian) + BYTE Entries_TableB[4]; // Number of segments in Encoding Layout Table (big endian) BYTE field_11; - BYTE SegmentsPos[4]; // Offset of encoding segments + BYTE Size_StringTable1[4]; // Size of the string block #1 } CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER; typedef struct _CASC_ENCODING_ENTRY { - USHORT KeyCount; // Number of subitems - BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes + USHORT KeyCount; // Number of index keys + BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key // Followed by the index keys @@ -166,87 +167,21 @@ typedef struct _CASC_ENCODING_ENTRY // Followed by the index keys (number of items = KeyCount) } CASC_ENCODING_ENTRY, *PCASC_ENCODING_ENTRY; -typedef struct _CASC_ROOT_LOCALE_BLOCK +// A version of CASC_ENCODING_ENTRY with one index key +typedef struct _CASC_ENCODING_ENTRY_1 { - DWORD NumberOfFiles; // Number of entries - DWORD Flags; - DWORD FileLocales; // File locales (CASC_LOCALE_XXX) + USHORT KeyCount; // Number of index keys + BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes + BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key + BYTE IndexKey[MD5_HASH_SIZE]; // File index key - // Followed by a block of 32-bit integers (count: NumberOfFiles) - // Followed by the MD5 and file name hash (count: NumberOfFiles) +} CASC_ENCODING_ENTRY_1, *PCASC_ENCODING_ENTRY_1; -} CASC_ROOT_LOCALE_BLOCK, *PCASC_ROOT_LOCALE_BLOCK; +#define GET_INDEX_KEY(pEncodingEntry) (pEncodingEntry->EncodingKey + MD5_HASH_SIZE) +#define FAKE_ENCODING_ENTRY_SIZE (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE) -// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) -// Corresponds to the in-file structure -typedef struct _CASC_ROOT_ENTRY_MNDX -{ - DWORD Flags; // High 8 bits: Flags, low 24 bits: package index - BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file - DWORD FileSize; // Uncompressed file size, in bytes - -} CASC_ROOT_ENTRY_MNDX, *PCASC_ROOT_ENTRY_MNDX; - -// Root file entry for CASC storages without MNDX root file (World of Warcraft 6.0+) -// Does not match to the in-file structure of the root entry -typedef struct _CASC_ROOT_ENTRY -{ - ULONGLONG FileNameHash; // Jenkins hash of the file name - DWORD SumValue; // Sum value - DWORD Locales; // Locale flags of the file - DWORD EncodingKey[4]; // File encoding key (MD5) - -} CASC_ROOT_ENTRY, *PCASC_ROOT_ENTRY; - -// Definition of the hash table for CASC root items -typedef struct _CASC_ROOT_HASH_TABLE -{ - PCASC_ROOT_ENTRY TablePtr; // Pointer to the CASC root table - DWORD TableSize; // Total size of the root table - DWORD ItemCount; // Number of items currently in the table - -} CASC_ROOT_HASH_TABLE, *PCASC_ROOT_HASH_TABLE; - -typedef struct _CASC_MNDX_INFO -{ - bool bRootFileLoaded; // true if the root info file was properly loaded - BYTE RootFileName[MD5_HASH_SIZE]; // Name (aka MD5) of the root file - DWORD HeaderVersion; // Must be <= 2 - DWORD FormatVersion; - DWORD field_1C; - DWORD field_20; - DWORD MarInfoOffset; // Offset of the first MAR entry info - DWORD MarInfoCount; // Number of the MAR info entries - DWORD MarInfoSize; // Size of the MAR info entry - DWORD MndxEntriesOffset; - DWORD MndxEntriesTotal; // Total number of MNDX root entries - DWORD MndxEntriesValid; // Number of valid MNDX root entries - DWORD MndxEntrySize; // Size of one MNDX root entry - struct _MAR_FILE * pMarFile1; // File name list for the packages - struct _MAR_FILE * pMarFile2; // File name list for names stripped of package names - struct _MAR_FILE * pMarFile3; // File name list for complete names - PCASC_ROOT_ENTRY_MNDX pMndxEntries; - PCASC_ROOT_ENTRY_MNDX * ppValidEntries; - -} CASC_MNDX_INFO, *PCASC_MNDX_INFO; - -typedef struct _CASC_PACKAGE -{ - char * szFileName; // Pointer to file name - size_t nLength; // Length of the file name - -} CASC_PACKAGE, *PCASC_PACKAGE; - -typedef struct _CASC_PACKAGES -{ - char * szNameBuffer; // Pointer to the buffer for file names - size_t NameEntries; // Number of name entries in Names - size_t NameBufferUsed; // Number of bytes used in the name buffer - size_t NameBufferMax; // Total size of the name buffer - - CASC_PACKAGE Packages[1]; // List of packages - -} CASC_PACKAGES, *PCASC_PACKAGES; +//----------------------------------------------------------------------------- +// Structures for CASC storage and CASC file typedef struct _TCascStorage { @@ -254,6 +189,7 @@ typedef struct _TCascStorage const TCHAR * szIndexFormat; // Format of the index file name TCHAR * szRootPath; // This is the game directory TCHAR * szDataPath; // This is the directory where data files are + TCHAR * szBuildFile; // Build file name (.build.info or .build.db) TCHAR * szIndexPath; // This is the directory where index files are TCHAR * szUrlPath; // URL to the Blizzard servers DWORD dwRefCount; // Number of references @@ -262,40 +198,29 @@ typedef struct _TCascStorage DWORD dwFileBeginDelta; // This is number of bytes to shift back from archive offset (from index entry) to actual begin of file data DWORD dwDefaultLocale; // Default locale, read from ".build.info" + CBLD_TYPE BuildFileType; // Type of the build file + QUERY_KEY CdnConfigKey; QUERY_KEY CdnBuildKey; - - PQUERY_KEY pArchiveArray; // Array of the archives - QUERY_KEY ArchiveGroup; // Name of the group archive file - DWORD ArchiveCount; // Number of archives in the array - - PQUERY_KEY pPatchArchiveArray; // Array of the patch archives - QUERY_KEY PatchArchiveGroup; // Name of the patch group archive file - DWORD PatchArchiveCount; // Number of patch archives in the array - + QUERY_KEY ArchivesGroup; // Key array of the "archive-group" + QUERY_KEY ArchivesKey; // Key array of the "archives" + QUERY_KEY PatchArchivesKey; // Key array of the "patch-archives" QUERY_KEY RootKey; QUERY_KEY PatchKey; QUERY_KEY DownloadKey; QUERY_KEY InstallKey; - - PQUERY_KEY pEncodingKeys; QUERY_KEY EncodingKey; - QUERY_KEY EncodingEKey; - DWORD EncodingKeys; TFileStream * DataFileArray[CASC_MAX_DATA_FILES]; // Data file handles CASC_MAPPING_TABLE KeyMapping[CASC_INDEX_COUNT]; // Key mapping PCASC_MAP pIndexEntryMap; // Map of index entries - PCASC_ENCODING_HEADER pEncodingHeader; // The encoding file - PCASC_ENCODING_ENTRY * ppEncodingEntries; // Map of encoding entries - size_t nEncodingEntries; + QUERY_KEY EncodingFile; // Content of the ENCODING file + PCASC_MAP pEncodingMap; // Map of encoding entries + DYNAMIC_ARRAY ExtraEntries; // Extra encoding entries - CASC_ROOT_HASH_TABLE RootTable; // Hash table for the root entries - - PCASC_MNDX_INFO pMndxInfo; // Used for storages which have MNDX/MAR file - PCASC_PACKAGES pPackages; // Linear list of present packages + TRootHandler * pRootHandler; // Common handler for various ROOT file formats } TCascStorage; @@ -336,16 +261,19 @@ typedef struct _TCascFile typedef struct _TCascSearch { TCascStorage * hs; // Pointer to the storage handle - const char * szClassName; - TCHAR * szListFile; + const char * szClassName; // Contains "TCascSearch" + TCHAR * szListFile; // Name of the listfile void * pCache; // Listfile cache - TMndxFindResult * pStruct1C; // Search structure for MNDX info - char * szMask; + char * szMask; // Search mask char szFileName[MAX_PATH]; // Buffer for the file name - char szNormName[MAX_PATH]; // Buffer for normalized file name - DWORD RootIndex; // Root index of the previously found item - DWORD dwState; // Pointer to the state (0 = listfile, 1 = nameless, 2 = done) - BYTE BitArray[1]; // Bit array of already-reported files + + // Provider-specific data + void * pRootContext; // Root-specific search context + size_t IndexLevel1; // Root-specific search context + size_t IndexLevel2; // Root-specific search context + DWORD dwState; // Pointer to the search state (0 = listfile, 1 = nameless, 2 = done) + + BYTE BitArray[1]; // Bit array of encoding keys. Set for each entry that has already been reported } TCascSearch; @@ -384,10 +312,15 @@ DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes); DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes); ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes); +void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes); +void FreeCascBlob(PQUERY_KEY pQueryKey); + //----------------------------------------------------------------------------- -// Build configuration reading +// Text file parsing (CascFiles.cpp) int LoadBuildInfo(TCascStorage * hs); +int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory); +int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, PQUERY_KEY pEncodingKey, char * szFileName, size_t nMaxChars); //----------------------------------------------------------------------------- // Internal file functions @@ -395,11 +328,20 @@ int LoadBuildInfo(TCascStorage * hs); TCascStorage * IsValidStorageHandle(HANDLE hStorage); TCascFile * IsValidFileHandle(HANDLE hFile); -PCASC_ROOT_ENTRY FindRootEntry(TCascStorage * hs, const char * szFileName, DWORD * PtrTableIndex); -PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex); +PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex); PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey); -int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer); +int CascDecompress(LPBYTE pvOutBuffer, PDWORD pcbOutBuffer, LPBYTE pvInBuffer, DWORD cbInBuffer); +int CascDecrypt (LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex); +int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer); + +//----------------------------------------------------------------------------- +// Support for ROOT file + +int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask); //----------------------------------------------------------------------------- // Dumping CASC data structures @@ -409,8 +351,7 @@ void CascDumpSparseArray(const char * szFileName, void * pvSparseArray); void CascDumpNameFragTable(const char * szFileName, void * pvMarFile); void CascDumpFileNames(const char * szFileName, void * pvMarFile); void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs); -void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo); -void CascDumpRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, const char * szFormat, const TCHAR * szListFile, int nDumpLevel); +void CascDumpEncodingEntry(TCascStorage * hs, TDumpContext * dc, PCASC_ENCODING_ENTRY pEncodingEntry, int nDumpLevel); void CascDumpFile(const char * szFileName, HANDLE hFile); #endif // _DEBUG diff --git a/dep/CascLib/src/CascDecompress.cpp b/dep/CascLib/src/CascDecompress.cpp index 2858bcec5ab..290b08d64d8 100644 --- a/dep/CascLib/src/CascDecompress.cpp +++ b/dep/CascLib/src/CascDecompress.cpp @@ -13,9 +13,9 @@ #include "CascCommon.h" //----------------------------------------------------------------------------- -// Local functions +// Public functions -static int Decompress_ZLIB(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) +int CascDecompress(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) { z_stream z; // Stream information for zlib int nResult; @@ -44,40 +44,3 @@ static int Decompress_ZLIB(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInB // Return an error code return (nResult == Z_OK || nResult == Z_STREAM_END) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; } - -//----------------------------------------------------------------------------- -// Public functions - -int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer) -{ - LPBYTE pbOutBuffer = (LPBYTE)pvOutBuffer; - LPBYTE pbInBuffer = (LPBYTE)pvInBuffer; - DWORD cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer - BYTE uCompression; // Decompressions applied to the data - - // Verify buffer sizes - if(cbInBuffer <= 1) - return 0; - - // Get applied compression types and decrement data length - uCompression = *pbInBuffer++; - cbInBuffer--; - - // Perform the decompressions - switch(uCompression) - { - case 'N': // Uncompressed - - assert(cbOutBuffer == cbInBuffer); - memcpy(pbOutBuffer, pbInBuffer, cbInBuffer); - *pcbOutBuffer = cbOutBuffer; - return ERROR_SUCCESS; - - case 'Z': // ZLIB - - return Decompress_ZLIB(pbOutBuffer, pcbOutBuffer, pbInBuffer, cbInBuffer); - } - - assert(false); - return ERROR_NOT_SUPPORTED; -} diff --git a/dep/CascLib/src/CascDecrypt.cpp b/dep/CascLib/src/CascDecrypt.cpp new file mode 100644 index 00000000000..5f4dc77dfe8 --- /dev/null +++ b/dep/CascLib/src/CascDecrypt.cpp @@ -0,0 +1,300 @@ +/*****************************************************************************/ +/* CascDecrypt.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Decryption functions for CascLib */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.10.15 1.00 Lad The first version of CascDecrypt.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +typedef struct _CASC_ENCRYPTION_KEY +{ + ULONGLONG KeyName; // "Name" of the key + BYTE Key[0x10]; // The key itself +} CASC_ENCRYPTION_KEY, *PCASC_ENCRYPTION_KEY; + +typedef struct _CASC_SALSA20 +{ + DWORD Key[0x10]; + DWORD dwRounds; + +} CASC_SALSA20, *PCASC_SALSA20; + +//----------------------------------------------------------------------------- +// Local variables + +//keyName FB680CB6A8BF81F3 key 62D90EFA7F36D71C398AE2F1FE37BDB9 keyNameSize 8 keySize 16 +//keyName 402CD9D8D6BFED98 key AEB0EADEA47612FE6C041A03958DF241 keyNameSize 8 keySize 16 +//keyName 87AEBBC9C4E6B601 key 685E86C6063DFDA6C9E85298076B3D42 keyNameSize 8 keySize 16 +//keyName A19C4F859F6EFA54 key 0196CB6F5ECBAD7CB5283891B9712B4B keyNameSize 8 keySize 16 +//keyName 11A9203C9881710A key 2E2CB8C397C2F24ED0B5E452F18DC267 keyNameSize 8 keySize 16 +//keyName DBD3371554F60306 key 34E397ACE6DD30EEFDC98A2AB093CD3C keyNameSize 8 keySize 16 +//keyName DEE3A0521EFF6F03 key AD740CE3FFFF9231468126985708E1B9 keyNameSize 8 keySize 16 +//keyName 8C9106108AA84F07 key 53D859DDA2635A38DC32E72B11B32F29 keyNameSize 8 keySize 16 + +static CASC_ENCRYPTION_KEY CascKeys[] = +{ + {0xFB680CB6A8BF81F3ULL, {0x62, 0xD9, 0x0E, 0xFA, 0x7F, 0x36, 0xD7, 0x1C, 0x39, 0x8A, 0xE2, 0xF1, 0xFE, 0x37, 0xBD, 0xB9}}, + {0x402CD9D8D6BFED98ULL, {0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41}}, + {0x87AEBBC9C4E6B601ULL, {0x68, 0x5E, 0x86, 0xC6, 0x06, 0x3D, 0xFD, 0xA6, 0xC9, 0xE8, 0x52, 0x98, 0x07, 0x6B, 0x3D, 0x42}}, + {0xA19C4F859F6EFA54ULL, {0x01, 0x96, 0xCB, 0x6F, 0x5E, 0xCB, 0xAD, 0x7C, 0xB5, 0x28, 0x38, 0x91, 0xB9, 0x71, 0x2B, 0x4B}}, + {0x11A9203C9881710AULL, {0x2E, 0x2C, 0xB8, 0xC3, 0x97, 0xC2, 0xF2, 0x4E, 0xD0, 0xB5, 0xE4, 0x52, 0xF1, 0x8D, 0xC2, 0x67}}, + {0xDBD3371554F60306ULL, {0x34, 0xE3, 0x97, 0xAC, 0xE6, 0xDD, 0x30, 0xEE, 0xFD, 0xC9, 0x8A, 0x2A, 0xB0, 0x93, 0xCD, 0x3C}}, + {0xDEE3A0521EFF6F03ULL, {0xAD, 0x74, 0x0C, 0xE3, 0xFF, 0xFF, 0x92, 0x31, 0x46, 0x81, 0x26, 0x98, 0x57, 0x08, 0xE1, 0xB9}}, + {0x8C9106108AA84F07ULL, {0x53, 0xD8, 0x59, 0xDD, 0xA2, 0x63, 0x5A, 0x38, 0xDC, 0x32, 0xE7, 0x2B, 0x11, 0xB3, 0x2F, 0x29}}, + {0x49166D358A34D815ULL, {0x66, 0x78, 0x68, 0xCD, 0x94, 0xEA, 0x01, 0x35, 0xB9, 0xB1, 0x6C, 0x93, 0xB1, 0x12, 0x4A, 0xBA}}, + {0, {0}} +}; + +static const char * szKeyConstant16 = "expand 16-byte k"; +static const char * szKeyConstant32 = "expand 32-byte k"; + +//----------------------------------------------------------------------------- +// Local functions + +static DWORD Rol32(DWORD dwValue, DWORD dwRolCount) +{ + return (dwValue << dwRolCount) | (dwValue >> (32 - dwRolCount)); +} + +static LPBYTE FindCascKey(ULONGLONG KeyName) +{ + // Search the known keys + for(size_t i = 0; CascKeys[i].KeyName != 0; i++) + { + if(CascKeys[i].KeyName == KeyName) + return CascKeys[i].Key; + } + + // Key not found + return NULL; +} + +static void Initialize(PCASC_SALSA20 pState, LPBYTE pbKey, DWORD cbKeyLength, LPBYTE pbVector) +{ + const char * szConstants = (cbKeyLength == 32) ? szKeyConstant32 : szKeyConstant16; + DWORD KeyIndex = cbKeyLength - 0x10; + + memset(pState, 0, sizeof(CASC_SALSA20)); + pState->Key[0] = *(PDWORD)(szConstants + 0x00); + pState->Key[1] = *(PDWORD)(pbKey + 0x00); + pState->Key[2] = *(PDWORD)(pbKey + 0x04); + pState->Key[3] = *(PDWORD)(pbKey + 0x08); + pState->Key[4] = *(PDWORD)(pbKey + 0x0C); + pState->Key[5] = *(PDWORD)(szConstants + 0x04); + pState->Key[6] = *(PDWORD)(pbVector + 0x00); + pState->Key[7] = *(PDWORD)(pbVector + 0x04); + pState->Key[8] = 0; + pState->Key[9] = 0; + pState->Key[10] = *(PDWORD)(szConstants + 0x08); + pState->Key[11] = *(PDWORD)(pbKey + KeyIndex + 0x00); + pState->Key[12] = *(PDWORD)(pbKey + KeyIndex + 0x04); + pState->Key[13] = *(PDWORD)(pbKey + KeyIndex + 0x08); + pState->Key[14] = *(PDWORD)(pbKey + KeyIndex + 0x0C); + pState->Key[15] = *(PDWORD)(szConstants + 0x0C); + + pState->dwRounds = 20; +} + +static int Decrypt(PCASC_SALSA20 pState, LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer) +{ + LPBYTE pbXorValue; + DWORD KeyMirror[0x10]; + DWORD XorValue[0x10]; + DWORD BlockSize; + DWORD i; + + // Repeat until we have data to read + while(cbInBuffer > 0) + { + // Create the copy of the key + memcpy(KeyMirror, pState->Key, sizeof(KeyMirror)); + + // Shuffle the key + for(i = 0; i < pState->dwRounds; i += 2) + { + KeyMirror[0x04] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x0C]), 0x07); + KeyMirror[0x08] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x00]), 0x09); + KeyMirror[0x0C] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x04]), 0x0D); + KeyMirror[0x00] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x08]), 0x12); + + KeyMirror[0x09] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x01]), 0x07); + KeyMirror[0x0D] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x05]), 0x09); + KeyMirror[0x01] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x09]), 0x0D); + KeyMirror[0x05] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x0D]), 0x12); + + KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x06]), 0x07); + KeyMirror[0x02] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0A]), 0x09); + KeyMirror[0x06] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x0E]), 0x0D); + KeyMirror[0x0A] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x02]), 0x12); + + KeyMirror[0x03] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0B]), 0x07); + KeyMirror[0x07] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x0F]), 0x09); + KeyMirror[0x0B] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x03]), 0x0D); + KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x07]), 0x12); + + KeyMirror[0x01] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x03]), 0x07); + KeyMirror[0x02] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x00]), 0x09); + KeyMirror[0x03] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x01]), 0x0D); + KeyMirror[0x00] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x02]), 0x12); + + KeyMirror[0x06] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x04]), 0x07); + KeyMirror[0x07] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x05]), 0x09); + KeyMirror[0x04] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x06]), 0x0D); + KeyMirror[0x05] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x07]), 0x12); + + KeyMirror[0x0B] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x09]), 0x07); + KeyMirror[0x08] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x0A]), 0x09); + KeyMirror[0x09] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x0B]), 0x0D); + KeyMirror[0x0A] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x08]), 0x12); + + KeyMirror[0x0C] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0E]), 0x07); + KeyMirror[0x0D] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x0F]), 0x09); + KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x0C]), 0x0D); + KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0D]), 0x12); + } + + // Set the number of remaining bytes + pbXorValue = (LPBYTE)XorValue; + BlockSize = (DWORD)CASCLIB_MIN(cbInBuffer, 0x40); + + // Prepare the XOR constants + for(i = 0; i < 16; i++) + { + XorValue[i] = KeyMirror[i] + pState->Key[i]; + } + + // Decrypt the block + for(i = 0; i < BlockSize; i++) + { + pbOutBuffer[i] = pbInBuffer[i] ^ pbXorValue[i]; + } + + pState->Key[8] = pState->Key[8] + 1; + if(pState->Key[8] == 0) + pState->Key[9] = pState->Key[9] + 1; + + // Adjust buffers + pbOutBuffer += BlockSize; + pbInBuffer += BlockSize; + cbInBuffer -= BlockSize; + } + + return ERROR_SUCCESS; +} + +static int Decrypt_Salsa20(LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer, LPBYTE pbKey, DWORD cbKeySize, LPBYTE pbVector) +{ + CASC_SALSA20 SalsaState; + + Initialize(&SalsaState, pbKey, cbKeySize, pbVector); + return Decrypt(&SalsaState, pbOutBuffer, pbInBuffer, cbInBuffer); +} + +//----------------------------------------------------------------------------- +// Public functions + +int CascDecrypt(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex) +{ + ULONGLONG KeyName = 0; + LPBYTE pbBufferEnd = pbInBuffer + cbInBuffer; + LPBYTE pbKey; + DWORD KeyNameSize; + DWORD dwShift = 0; + DWORD IVSize; + BYTE Vector[0x08]; + BYTE EncryptionType; + int nError; + + // Verify and retrieve the key name size + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 0 && pbInBuffer[0] != 8) + return ERROR_NOT_SUPPORTED; + KeyNameSize = *pbInBuffer++; + + // Copy the key name + if((pbInBuffer + KeyNameSize) >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + memcpy(&KeyName, pbInBuffer, KeyNameSize); + pbInBuffer += KeyNameSize; + + // Verify and retrieve the Vector size + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 4 && pbInBuffer[0] != 8) + return ERROR_NOT_SUPPORTED; + IVSize = *pbInBuffer++; + + // Copy the initialization vector + if((pbInBuffer + IVSize) >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + memset(Vector, 0, sizeof(Vector)); + memcpy(Vector, pbInBuffer, IVSize); + pbInBuffer += IVSize; + + // Verify and retrieve the encryption type + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 'S' && pbInBuffer[0] != 'A') + return ERROR_NOT_SUPPORTED; + EncryptionType = *pbInBuffer++; + + // Do we have enough space in the output buffer? + if((DWORD)(pbBufferEnd - pbInBuffer) > pcbOutBuffer[0]) + return ERROR_INSUFFICIENT_BUFFER; + + // Check if we know the key + pbKey = FindCascKey(KeyName); + if(pbKey == NULL) + return ERROR_UNKNOWN_FILE_KEY; + + // Shuffle the Vector with the block index + // Note that there's no point to go beyond 32 bits, unless the file has + // more than 0xFFFFFFFF frames. + for(int i = 0; i < sizeof(dwFrameIndex); i++) + { + Vector[i] = Vector[i] ^ (BYTE)((dwFrameIndex >> dwShift) & 0xFF); + dwShift += 8; + } + + // Perform the decryption-specific action + switch(EncryptionType) + { + case 'S': // Salsa20 + nError = Decrypt_Salsa20(pbOutBuffer, pbInBuffer, (pbBufferEnd - pbInBuffer), pbKey, 0x10, Vector); + if(nError != ERROR_SUCCESS) + return nError; + + // Supply the size of the output buffer + pcbOutBuffer[0] = (DWORD)(pbBufferEnd - pbInBuffer); + return ERROR_SUCCESS; + +// case 'A': +// return ERROR_NOT_SUPPORTED; + } + + assert(false); + return ERROR_NOT_SUPPORTED; +} + +int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) +{ + // Check the buffer size + if((cbInBuffer - 1) > pcbOutBuffer[0]) + return ERROR_INSUFFICIENT_BUFFER; + + // Copy the data + memcpy(pbOutBuffer, pbInBuffer, cbInBuffer); + pcbOutBuffer[0] = cbInBuffer; + return ERROR_SUCCESS; +} + diff --git a/dep/CascLib/src/CascDumpData.cpp b/dep/CascLib/src/CascDumpData.cpp index 5dc9110b6cd..3c0e385ac07 100644 --- a/dep/CascLib/src/CascDumpData.cpp +++ b/dep/CascLib/src/CascDumpData.cpp @@ -11,14 +11,14 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" +#include "CascMndx.h" -#ifdef _DEBUG // The entire file is only valid for debug purposes +#ifdef _DEBUG // The entire feature is only valid for debug purposes //----------------------------------------------------------------------------- // Forward definitions -LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd); +//LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd); //----------------------------------------------------------------------------- // Sort compare functions @@ -49,160 +49,6 @@ static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, return 0; } -//----------------------------------------------------------------------------- -// Local functions - -static char * StringFromMD5(LPBYTE md5, char * szBuffer) -{ - return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer); -} - -static char * FormatFileName(const char * szFormat, TCascStorage * hs) -{ - char * szFileName; - char * szSrc; - char * szTrg; - - // Create copy of the file name - szFileName = szSrc = szTrg = NewStr(szFormat, 0); - if(szFileName != NULL) - { - // Format the file name - while(szSrc[0] != 0) - { - if(szSrc[0] == '%') - { - // Replace "%build%" with a build number - if(!strncmp(szSrc, "%build%", 7)) - { - szTrg += sprintf(szTrg, "%u", hs->dwBuildNumber); - szSrc += 7; - continue; - } - } - - // Just copy the character - *szTrg++ = *szSrc++; - } - - // Terminate the target file name - szTrg[0] = 0; - } - - return szFileName; -} - -FILE * CreateDumpFile(const char * szFormat, TCascStorage * hs) -{ - FILE * fp = NULL; - char * szFileName; - - // Validate the storage handle - if(hs != NULL) - { - // Format the real file name - szFileName = FormatFileName(szFormat, hs); - if(szFileName != NULL) - { - // Create the dump file - fp = fopen(szFileName, "wt"); - CASC_FREE(szFileName); - } - } - - return fp; -} - -static void DumpIndexKey( - FILE * fp, - TCascStorage * hs, - LPBYTE pbIndexKey, - int nDumpLevel) -{ - PCASC_INDEX_ENTRY pIndexEntry; - TCascFile * hf; - QUERY_KEY QueryKey; - HANDLE hFile; - BYTE HeaderArea[MAX_HEADER_AREA_SIZE]; - char szBuffer[0x20]; - - QueryKey.pbData = pbIndexKey; - QueryKey.cbData = MD5_HASH_SIZE; - pIndexEntry = FindIndexEntry(hs, &QueryKey); - if(pIndexEntry != NULL) - { - ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); - DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); - DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); - - // Mask the file offset - FileOffset &= 0x3FFFFFFF; - fprintf(fp, " data.%03u at 0x%08x (0x%lx bytes)\n", - ArchIndex, - (DWORD)FileOffset, - FileSize); - - if(nDumpLevel > 2) - { - QueryKey.pbData = pIndexEntry->IndexKey; - QueryKey.cbData = MD5_HASH_SIZE; - if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) - { - // Make sure that the data file is open and frame header loaded - CascGetFileSize(hFile, NULL); - hf = IsValidFileHandle(hFile); - assert(hf->pStream != NULL); - - // Read the header area - FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; - FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); - CascCloseFile(hFile); - - // Dump the header area - fprintf(fp, " FileSize: %X Rest: %s\n", - ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), - StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); - } - } - } - else - { - fprintf(fp, " NO INDEX ENTRY\n"); - } -} - -static void DumpEncodingEntry( - FILE * fp, - TCascStorage * hs, - PCASC_ENCODING_ENTRY pEncodingEntry, - int nDumpLevel) -{ - LPBYTE pbIndexKey; - char szMd5[MD5_STRING_SIZE]; - - // If the encoding key exists - if(pEncodingEntry != NULL) - { - fprintf(fp, " Size %lx Key Count: %u\n", - ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE), - pEncodingEntry->KeyCount); - - // Dump all index keys - pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; - for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++) - { - fprintf(fp, " %s\n", StringFromMD5(pbIndexKey, szMd5)); - DumpIndexKey(fp, hs, pbIndexKey, nDumpLevel); - pbIndexKey += MD5_HASH_SIZE; - } - - } - else - { - fprintf(fp, " NO ENCODING KEYS\n"); - } -} - //----------------------------------------------------------------------------- // Public functions @@ -323,27 +169,92 @@ void CascDumpFileNames(const char * szFileName, void * pvMarFile) Struct1C.FreeStruct40(); } -void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo) +void CascDumpIndexEntry( + TCascStorage * /* hs */, + TDumpContext * dc, + PCASC_INDEX_ENTRY pIndexEntry, + int /* nDumpLevel */) { - PCASC_ROOT_ENTRY_MNDX pRootEntry; - FILE * fp; - char szMd5[MD5_STRING_SIZE]; - - // Create the dump file - fp = fopen(szFileName, "wt"); - if(fp != NULL) + if(pIndexEntry != NULL) { - fprintf(fp, "Indx Fl+Asset EncodingKey FileSize\n==== ======== ================================ ========\n"); - for(DWORD i = 0; i < pMndxInfo->MndxEntriesValid; i++) - { - pRootEntry = pMndxInfo->ppValidEntries[i]; + ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); + DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); + DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); - fprintf(fp, "%04X %08X %s %08X\n", i, - pRootEntry->Flags, - StringFromMD5(pRootEntry->EncodingKey, szMd5), - pRootEntry->FileSize); + // Mask the file offset + FileOffset &= 0x3FFFFFFF; + dump_print(dc, " data.%03u at 0x%08x (0x%lx bytes)\n", + ArchIndex, + (DWORD)FileOffset, + FileSize); + + //if(nDumpLevel > 2) + //{ + // QueryKey.pbData = pIndexEntry->IndexKey; + // QueryKey.cbData = MD5_HASH_SIZE; + // if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) + // { + // // Make sure that the data file is open and frame header loaded + // CascGetFileSize(hFile, NULL); + // hf = IsValidFileHandle(hFile); + // assert(hf->pStream != NULL); + + // // Read the header area + // FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; + // FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); + // CascCloseFile(hFile); + + // // Dump the header area + // dump_print(dc, " FileSize: %X Rest: %s\n", + // ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), + // StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); + // } + //} + } + else + { + dump_print(dc, " NO INDEX ENTRY\n"); + } +} + +void CascDumpEncodingEntry( + TCascStorage * hs, + TDumpContext * dc, + PCASC_ENCODING_ENTRY pEncodingEntry, + int nDumpLevel) +{ + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY QueryKey; + LPBYTE pbIndexKey; + char szMd5[MD5_STRING_SIZE+1]; + + // If the encoding key exists + if(pEncodingEntry != NULL) + { + dump_print(dc, " Size %lx Key Count: %u\n", + ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE), + pEncodingEntry->KeyCount); + + // Dump all index keys + pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; + for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++, pbIndexKey += MD5_HASH_SIZE) + { + // Dump the index key + dump_print(dc, " %s\n", StringFromMD5(pbIndexKey, szMd5)); + + // Dump the index entry as well + if(nDumpLevel >= DUMP_LEVEL_INDEX_ENTRIES) + { + QueryKey.pbData = pbIndexKey; + QueryKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(hs, &QueryKey); + CascDumpIndexEntry(hs, dc, pIndexEntry, nDumpLevel); + } } - fclose(fp); + } + else + { + dump_print(dc, " NO ENCODING KEYS\n"); } } @@ -380,7 +291,7 @@ void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs) FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); ArchOffset &= 0x3FFFFFFF; - fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey)); + fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, (DWORD)ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey)); } CASC_FREE(ppIndexEntries); @@ -390,81 +301,6 @@ void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs) } } -void CascDumpRootFile( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - const char * szFormat, - const TCHAR * szListFile, - int nDumpLevel) -{ - PCASC_ENCODING_ENTRY pEncodingEntry; - ROOT_BLOCK_INFO BlockInfo; - PLISTFILE_MAP pListMap; - QUERY_KEY EncodingKey; - LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; - LPBYTE pbFilePointer; - FILE * fp; - char szOneLine[0x100]; - DWORD i; - - // This function only dumps WoW-style root file - assert(*(PDWORD)pbRootFile != CASC_MNDX_SIGNATURE); - - // Create the dump file - fp = CreateDumpFile(szFormat, hs); - if(fp != NULL) - { - // Create the listfile map -// DWORD dwTickCount = GetTickCount(); - pListMap = ListFile_CreateMap(szListFile); -// dwTickCount = GetTickCount() - dwTickCount; - - // Dump the root entries as-is - for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) - { - // Validate the root block - pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); - if(pbFilePointer == NULL) - break; - - // Dump the locale block - fprintf(fp, "Flags: %08X Locales: %08X NumberOfFiles: %u\n" - "=========================================================\n", - BlockInfo.pLocaleBlockHdr->Flags, - BlockInfo.pLocaleBlockHdr->Locales, - BlockInfo.pLocaleBlockHdr->NumberOfFiles); - - // Dump the hashes and encoding keys - for(i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) - { - // Dump the entry - fprintf(fp, "%08X %08X-%08X %s %s\n", - (DWORD)(BlockInfo.pInt32Array[i]), - (DWORD)(BlockInfo.pRootEntries[i].FileNameHash >> 0x20), - (DWORD)(BlockInfo.pRootEntries[i].FileNameHash), - StringFromMD5((LPBYTE)BlockInfo.pRootEntries[i].EncodingKey, szOneLine), - ListFile_FindName(pListMap, BlockInfo.pRootEntries[i].FileNameHash)); - - // Find the encoding entry in the encoding table - if(nDumpLevel > 1) - { - EncodingKey.pbData = (LPBYTE)BlockInfo.pRootEntries[i].EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - pEncodingEntry = FindEncodingEntry(hs, &EncodingKey, NULL); - DumpEncodingEntry(fp, hs, pEncodingEntry, nDumpLevel); - } - } - - // Put extra newline - fprintf(fp, "\n"); - } - - ListFile_FreeMap(pListMap); - fclose(fp); - } -} - void CascDumpFile(const char * szFileName, HANDLE hFile) { FILE * fp; diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp new file mode 100644 index 00000000000..8709ea09e36 --- /dev/null +++ b/dep/CascLib/src/CascFiles.cpp @@ -0,0 +1,981 @@ +/*****************************************************************************/ +/* CascFiles.cpp Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Various text file parsers */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.04.14 1.00 Lad The first version of CascBuildCfg.cpp */ +/* 30.10.15 1.00 Lad Renamed to CascFiles.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +typedef int (*PARSEINFOFILE)(TCascStorage * hs, void * pvListFile); + +//----------------------------------------------------------------------------- +// Local structures + +struct TBuildFileInfo +{ + const TCHAR * szFileName; + CBLD_TYPE BuildFileType; +}; + +struct TGameIdString +{ + const char * szGameInfo; + size_t cchGameInfo; + DWORD dwGameInfo; +}; + +static const TBuildFileInfo BuildTypes[] = +{ + {_T(".build.info"), CascBuildInfo}, // Since HOTS build 30027, the game uses .build.info file for storage info + {_T(".build.db"), CascBuildDb}, // Older CASC storages + {NULL, CascBuildNone} +}; + +static const TCHAR * DataDirs[] = +{ + _T("SC2Data"), // Starcraft II (Legacy of the Void) build 38749 + _T("Data\\Casc"), // Overwatch + _T("Data"), // World of Warcraft, Diablo + _T("HeroesData"), // Heroes of the Storm + _T("BNTData"), // Heroes of the Storm, until build 30414 + NULL, +}; + +static const TGameIdString GameIds[] = +{ + {"Hero", 0x04, CASC_GAME_HOTS}, // Alpha build of Heroes of the Storm + {"WoW", 0x03, CASC_GAME_WOW6}, // Alpha build of World of Warcraft - Warlords of Draenor + {"Diablo3", 0x07, CASC_GAME_DIABLO3}, // Diablo III BETA 2.2.0 + {"Prometheus", 0x0A, CASC_GAME_OVERWATCH}, // Overwatch BETA since build 24919 + {"SC2", 0x03, CASC_GAME_STARCRAFT2}, // Starcraft II - Legacy of the Void + {NULL, 0, 0}, +}; + +//----------------------------------------------------------------------------- +// Local functions + +static bool inline IsValueSeparator(const char * szVarValue) +{ + return ((0 <= szVarValue[0] && szVarValue[0] <= 0x20) || (szVarValue[0] == '|')); +} + +static bool IsCharDigit(BYTE OneByte) +{ + return ('0' <= OneByte && OneByte <= '9'); +} + +static DWORD GetLocaleMask(const char * szTag) +{ + if(!strcmp(szTag, "enUS")) + return CASC_LOCALE_ENUS; + + if(!strcmp(szTag, "koKR")) + return CASC_LOCALE_KOKR; + + if(!strcmp(szTag, "frFR")) + return CASC_LOCALE_FRFR; + + if(!strcmp(szTag, "deDE")) + return CASC_LOCALE_DEDE; + + if(!strcmp(szTag, "zhCN")) + return CASC_LOCALE_ZHCN; + + if(!strcmp(szTag, "esES")) + return CASC_LOCALE_ESES; + + if(!strcmp(szTag, "zhTW")) + return CASC_LOCALE_ZHTW; + + if(!strcmp(szTag, "enGB")) + return CASC_LOCALE_ENGB; + + if(!strcmp(szTag, "enCN")) + return CASC_LOCALE_ENCN; + + if(!strcmp(szTag, "enTW")) + return CASC_LOCALE_ENTW; + + if(!strcmp(szTag, "esMX")) + return CASC_LOCALE_ESMX; + + if(!strcmp(szTag, "ruRU")) + return CASC_LOCALE_RURU; + + if(!strcmp(szTag, "ptBR")) + return CASC_LOCALE_PTBR; + + if(!strcmp(szTag, "itIT")) + return CASC_LOCALE_ITIT; + + if(!strcmp(szTag, "ptPT")) + return CASC_LOCALE_PTPT; + + return 0; +} + +static bool IsInfoVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName, const char * szVarType) +{ + size_t nLength; + + // Check the variable name + nLength = strlen(szVarName); + if((size_t)(szLineEnd - szLineBegin) > nLength) + { + // Check the variable name + if(!_strnicmp(szLineBegin, szVarName, nLength)) + { + // Skip variable name and the exclamation mark + szLineBegin += nLength; + if(szLineBegin < szLineEnd && szLineBegin[0] == '!') + { + // Skip the exclamation mark + szLineBegin++; + + // Check the variable type + nLength = strlen(szVarType); + if((size_t)(szLineEnd - szLineBegin) > nLength) + { + // Check the variable name + if(!_strnicmp(szLineBegin, szVarType, nLength)) + { + // Skip variable type and the doublecolon + szLineBegin += nLength; + return (szLineBegin < szLineEnd && szLineBegin[0] == ':'); + } + } + } + } + } + + return false; +} + +static const char * SkipInfoVariable(const char * szLineBegin, const char * szLineEnd) +{ + while(szLineBegin < szLineEnd) + { + if(szLineBegin[0] == '|') + return szLineBegin + 1; + + szLineBegin++; + } + + return NULL; +} + +static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir) +{ + TCHAR * szIndexPath; + + // Cpmbine the index path + szIndexPath = CombinePath(hs->szDataPath, szSubDir); + if(DirectoryExists(szIndexPath)) + { + hs->szIndexPath = szIndexPath; + return hs->szIndexPath; + } + + CASC_FREE(szIndexPath); + return NULL; +} + +TCHAR * AppendBlobText(TCHAR * szBuffer, LPBYTE pbData, DWORD cbData, TCHAR chSeparator) +{ + // Put the separator, if any + if(chSeparator != 0) + *szBuffer++ = chSeparator; + + // Copy the blob data as text + for(DWORD i = 0; i < cbData; i++) + { + *szBuffer++ = IntToHexChar[pbData[0] >> 0x04]; + *szBuffer++ = IntToHexChar[pbData[0] & 0x0F]; + pbData++; + } + + // Terminate the string + *szBuffer = 0; + + // Return new buffer position + return szBuffer; +} + +static const char * CheckLineVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName) +{ + size_t nLineLength = (size_t)(szLineEnd - szLineBegin); + size_t nNameLength = strlen(szVarName); + + // If the line longer than the variable name? + if(nLineLength > nNameLength) + { + if(!_strnicmp((const char *)szLineBegin, szVarName, nNameLength)) + { + // Skip the variable name + szLineBegin += nNameLength; + + // Skip the separator(s) + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + + // Check if there is "=" + if(szLineBegin >= szLineEnd || szLineBegin[0] != '=') + return NULL; + szLineBegin++; + + // Skip the separator(s) + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + + // Check if there is "=" + if(szLineBegin >= szLineEnd) + return NULL; + + // Return the begin of the variable + return szLineBegin; + } + } + + return NULL; +} + +static int LoadInfoVariable(PQUERY_KEY pVarBlob, const char * szLineBegin, const char * szLineEnd, bool bHexaValue) +{ + const char * szLinePtr = szLineBegin; + + // Sanity checks + assert(pVarBlob->pbData == NULL); + assert(pVarBlob->cbData == 0); + + // Check length of the variable + while(szLinePtr < szLineEnd && szLinePtr[0] != '|') + szLinePtr++; + + // Allocate space for the blob + if(bHexaValue) + { + // Initialize the blob + pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) / 2); + pVarBlob->cbData = (DWORD)((szLinePtr - szLineBegin) / 2); + return ConvertStringToBinary(szLineBegin, (size_t)(szLinePtr - szLineBegin), pVarBlob->pbData); + } + + // Initialize the blob + pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1); + pVarBlob->cbData = (DWORD)(szLinePtr - szLineBegin); + + // Check for success + if(pVarBlob->pbData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Copy the string + memcpy(pVarBlob->pbData, szLineBegin, pVarBlob->cbData); + pVarBlob->pbData[pVarBlob->cbData] = 0; + return ERROR_SUCCESS; +} + +static void AppendConfigFilePath(TCHAR * szFileName, PQUERY_KEY pFileKey) +{ + size_t nLength = _tcslen(szFileName); + + // If there is no slash, append if + if(nLength > 0 && szFileName[nLength - 1] != '\\' && szFileName[nLength - 1] != '/') + szFileName[nLength++] = _T('/'); + + // Get to the end of the file name + szFileName = szFileName + nLength; + + // Append the "config" directory + _tcscpy(szFileName, _T("config")); + szFileName += 6; + + // Append the first level directory + szFileName = AppendBlobText(szFileName, pFileKey->pbData, 1, _T('/')); + szFileName = AppendBlobText(szFileName, pFileKey->pbData + 1, 1, _T('/')); + szFileName = AppendBlobText(szFileName, pFileKey->pbData, pFileKey->cbData, _T('/')); +} + +static DWORD GetBlobCount(const char * szLineBegin, const char * szLineEnd) +{ + DWORD dwBlobCount = 0; + + // Until we find an end of the line + while(szLineBegin < szLineEnd) + { + // Skip the blob + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin) == false) + szLineBegin++; + + // Increment the number of blobs + dwBlobCount++; + + // Skip the separator + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + } + + return dwBlobCount; +} + +static int LoadBlobArray( + PQUERY_KEY pBlob, + const char * szLineBegin, + const char * szLineEnd, + DWORD dwMaxBlobs) +{ + LPBYTE pbBufferEnd = pBlob->pbData + pBlob->cbData; + LPBYTE pbBuffer = pBlob->pbData; + int nError = ERROR_SUCCESS; + + // Sanity check + assert(pBlob->pbData != NULL); + assert(pBlob->cbData != 0); + + // Until we find an end of the line + while(szLineBegin < szLineEnd && dwMaxBlobs > 0) + { + const char * szBlobEnd = szLineBegin; + + // Find the end of the text blob + while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd) == false) + szBlobEnd++; + + // Verify the length of the found blob + if((szBlobEnd - szLineBegin) != MD5_STRING_SIZE) + return ERROR_BAD_FORMAT; + + // Verify if there is enough space in the buffer + if((pbBufferEnd - pbBuffer) < MD5_HASH_SIZE) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the conversion + nError = ConvertStringToBinary(szLineBegin, MD5_STRING_SIZE, pbBuffer); + if(nError != ERROR_SUCCESS) + return nError; + + // Move pointers + pbBuffer += MD5_HASH_SIZE; + dwMaxBlobs--; + + // Skip the separator + while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd)) + szBlobEnd++; + szLineBegin = szBlobEnd; + } + + return nError; +} + +static int LoadMultipleBlobs(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd, DWORD dwBlobCount) +{ + size_t nLength = (szLineEnd - szLineBegin); + + // We expect each blob to have length of the encoding key and one space between + if(nLength > (dwBlobCount * MD5_STRING_SIZE) + ((dwBlobCount - 1) * sizeof(char))) + return ERROR_INVALID_PARAMETER; + + // Allocate the blob buffer + pBlob->pbData = CASC_ALLOC(BYTE, dwBlobCount * MD5_HASH_SIZE); + if(pBlob->pbData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Set the buffer size and load the blob array + pBlob->cbData = dwBlobCount * MD5_HASH_SIZE; + return LoadBlobArray(pBlob, szLineBegin, szLineEnd, dwBlobCount); +} + +static int LoadMultipleBlobs(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd) +{ + return LoadMultipleBlobs(pBlob, szLineBegin, szLineEnd, GetBlobCount(szLineBegin, szLineEnd)); +} + +static int LoadSingleBlob(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd) +{ + return LoadMultipleBlobs(pBlob, szLineBegin, szLineEnd, 1); +} + +static int GetGameType(TCascStorage * hs, const char * szVarBegin, const char * szLineEnd) +{ + // Go through all games that we support + for(size_t i = 0; GameIds[i].szGameInfo != NULL; i++) + { + // Check the length of the variable + if((size_t)(szLineEnd - szVarBegin) == GameIds[i].cchGameInfo) + { + // Check the string + if(!_strnicmp(szVarBegin, GameIds[i].szGameInfo, GameIds[i].cchGameInfo)) + { + hs->dwGameInfo = GameIds[i].dwGameInfo; + return ERROR_SUCCESS; + } + } + } + + // Unknown/unsupported game + assert(false); + return ERROR_BAD_FORMAT; +} + +// "B29049" +// "WOW-18125patch6.0.1" +// "30013_Win32_2_2_0_Ptr_ptr" +// "prometheus-0_8_0_0-24919" +static int GetBuildNumber(TCascStorage * hs, const char * szVarBegin, const char * szLineEnd) +{ + DWORD dwBuildNumber = 0; + + // Skip all non-digit characters + while(szVarBegin < szLineEnd) + { + // There must be at least three digits (build 99 anyone?) + if(IsCharDigit(szVarBegin[0]) && IsCharDigit(szVarBegin[1]) && IsCharDigit(szVarBegin[2])) + { + // Convert the build number string to value + while(szVarBegin < szLineEnd && IsCharDigit(szVarBegin[0])) + dwBuildNumber = (dwBuildNumber * 10) + (*szVarBegin++ - '0'); + break; + } + + // Move to the next + szVarBegin++; + } + + assert(dwBuildNumber != 0); + hs->dwBuildNumber = dwBuildNumber; + return (dwBuildNumber != 0) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; +} + +static int GetDefaultLocaleMask(TCascStorage * hs, PQUERY_KEY pTagsString) +{ + char * szTagEnd = (char *)pTagsString->pbData + pTagsString->cbData; + char * szTagPtr = (char *)pTagsString->pbData; + char * szNext; + DWORD dwLocaleMask = 0; + + while(szTagPtr < szTagEnd) + { + // Get the next part + szNext = strchr(szTagPtr, ' '); + if(szNext != NULL) + *szNext++ = 0; + + // Check whether the current tag is a language identifier + dwLocaleMask = dwLocaleMask | GetLocaleMask(szTagPtr); + + // Get the next part + if(szNext == NULL) + break; + + // Skip spaces + while(szNext < szTagEnd && szNext[0] == ' ') + szNext++; + szTagPtr = szNext; + } + + hs->dwDefaultLocale = dwLocaleMask; + return ERROR_SUCCESS; +} + +static void * FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey) +{ + TCHAR * szFileName; + void * pvListFile = NULL; + + // Construct the local file name + szFileName = CascNewStr(hs->szDataPath, 8 + 3 + 3 + 32); + if(szFileName != NULL) + { + // Add the part where the config file path is + AppendConfigFilePath(szFileName, pFileKey); + + // Load and verify the external listfile + pvListFile = ListFile_OpenExternal(szFileName); + if(pvListFile != NULL) + { + if(!ListFile_VerifyMD5(pvListFile, pFileKey->pbData)) + { + ListFile_Free(pvListFile); + pvListFile = NULL; + } + } + + // Free the file name + CASC_FREE(szFileName); + } + + return pvListFile; +} + +static int ParseFile_BuildInfo(TCascStorage * hs, void * pvListFile) +{ + QUERY_KEY Active = {NULL, 0}; + QUERY_KEY TagString = {NULL, 0}; + QUERY_KEY CdnHost = {NULL, 0}; + QUERY_KEY CdnPath = {NULL, 0}; + char szOneLine1[0x200]; + char szOneLine2[0x200]; + size_t nLength1; + size_t nLength2; + int nError = ERROR_BAD_FORMAT; + + // Extract the first line, cotaining the headers + nLength1 = ListFile_GetNextLine(pvListFile, szOneLine1, _maxchars(szOneLine1)); + if(nLength1 == 0) + return ERROR_BAD_FORMAT; + + // Now parse the second and the next lines. We are looking for line + // with "Active" set to 1 + for(;;) + { + const char * szLinePtr1 = szOneLine1; + const char * szLineEnd1 = szOneLine1 + nLength1; + const char * szLinePtr2 = szOneLine2; + const char * szLineEnd2; + + // Read the next line + nLength2 = ListFile_GetNextLine(pvListFile, szOneLine2, _maxchars(szOneLine2)); + if(nLength2 == 0) + break; + szLineEnd2 = szLinePtr2 + nLength2; + + // Parse all variables + while(szLinePtr1 < szLineEnd1) + { + // Check for variables we need + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC")) + LoadInfoVariable(&Active, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX")) + LoadInfoVariable(&hs->CdnBuildKey, szLinePtr2, szLineEnd2, true); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX")) + LoadInfoVariable(&hs->CdnConfigKey, szLinePtr2, szLineEnd2, true); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING")) + LoadInfoVariable(&CdnHost, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING")) + LoadInfoVariable(&CdnPath, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING")) + LoadInfoVariable(&TagString, szLinePtr2, szLineEnd2, false); + + // Move both line pointers + szLinePtr1 = SkipInfoVariable(szLinePtr1, szLineEnd1); + if(szLinePtr1 == NULL) + break; + + szLinePtr2 = SkipInfoVariable(szLinePtr2, szLineEnd2); + if(szLinePtr2 == NULL) + break; + } + + // Stop parsing if found active config + if(Active.pbData != NULL && *Active.pbData == '1') + break; + + // Free the blobs + FreeCascBlob(&Active); + FreeCascBlob(&hs->CdnBuildKey); + FreeCascBlob(&hs->CdnConfigKey); + FreeCascBlob(&CdnHost); + FreeCascBlob(&CdnPath); + FreeCascBlob(&TagString); + } + + // All four must be present + if(hs->CdnBuildKey.pbData != NULL && + hs->CdnConfigKey.pbData != NULL && + CdnHost.pbData != NULL && + CdnPath.pbData != NULL) + { + // Merge the CDN host and CDN path + hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1); + if(hs->szUrlPath != NULL) + { + CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData); + CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData); + nError = ERROR_SUCCESS; + } + } + + // If we found tags, we can extract language build from it + if(TagString.pbData != NULL) + GetDefaultLocaleMask(hs, &TagString); + + FreeCascBlob(&CdnHost); + FreeCascBlob(&CdnPath); + FreeCascBlob(&TagString); + FreeCascBlob(&Active); + return nError; +} + +static int ParseFile_BuildDb(TCascStorage * hs, void * pvListFile) +{ + const char * szLinePtr; + const char * szLineEnd; + char szOneLine[0x200]; + size_t nLength; + int nError; + + // Load the single line from the text file + nLength = ListFile_GetNextLine(pvListFile, szOneLine, _maxchars(szOneLine)); + if(nLength == 0) + return ERROR_BAD_FORMAT; + + // Set the line range + szLinePtr = szOneLine; + szLineEnd = szOneLine + nLength; + + // Extract the CDN build key + nError = LoadInfoVariable(&hs->CdnBuildKey, szLinePtr, szLineEnd, true); + if(nError == ERROR_SUCCESS) + { + // Skip the variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Load the CDN config hash + nError = LoadInfoVariable(&hs->CdnConfigKey, szLinePtr, szLineEnd, true); + if(nError == ERROR_SUCCESS) + { + // Skip the variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Skip the Locale/OS/code variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Load the URL + hs->szUrlPath = CascNewStrFromAnsi(szLinePtr, szLineEnd); + if(hs->szUrlPath == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Verify all variables + if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL) + nError = ERROR_BAD_FORMAT; + return nError; +} + +static int LoadCdnConfigFile(TCascStorage * hs, void * pvListFile) +{ + const char * szLineBegin; + const char * szVarBegin; + const char * szLineEnd; + int nError = ERROR_SUCCESS; + + // Keep parsing the listfile while there is something in there + for(;;) + { + // Get the next line + if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd)) + break; + + // Archive group + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archive-group"); + if(szVarBegin != NULL) + { + nError = LoadSingleBlob(&hs->ArchivesGroup, szVarBegin, szLineEnd); + continue; + } + + // Archives + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archives"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->ArchivesKey, szVarBegin, szLineEnd); + continue; + } + + // Patch archive group + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archive-group"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->PatchArchivesKey, szVarBegin, szLineEnd); + continue; + } + + // Patch archives + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archives"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->PatchArchivesKey, szVarBegin, szLineEnd); + continue; + } + } + + // Check if all required fields are present + if(hs->ArchivesKey.pbData == NULL || hs->ArchivesKey.cbData == 0) + return ERROR_BAD_FORMAT; + + return nError; +} + +static int LoadCdnBuildFile(TCascStorage * hs, void * pvListFile) +{ + const char * szLineBegin; + const char * szVarBegin; + const char * szLineEnd = NULL; + int nError = ERROR_SUCCESS; + + for(;;) + { + // Get the next line + if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd)) + break; + + // Game name + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-product"); + if(szVarBegin != NULL) + { + GetGameType(hs, szVarBegin, szLineEnd); + continue; + } + + // Game build number + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-name"); + if(szVarBegin != NULL) + { + GetBuildNumber(hs, szVarBegin, szLineEnd); + continue; + } + + // Root + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "root"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->RootKey, szVarBegin, szLineEnd); + continue; + } + + // Patch + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->PatchKey, szVarBegin, szLineEnd); + continue; + } + + // Download + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "download"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->DownloadKey, szVarBegin, szLineEnd); + continue; + } + + // Install + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "install"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->InstallKey, szVarBegin, szLineEnd); + continue; + } + + // Encoding keys + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "encoding"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->EncodingKey, szVarBegin, szLineEnd, 2); + continue; + } + } + + // Check the encoding keys + if(hs->EncodingKey.pbData == NULL || hs->EncodingKey.cbData != MD5_HASH_SIZE * 2) + return ERROR_BAD_FORMAT; + return nError; +} + +static int CheckDataDirectory(TCascStorage * hs, TCHAR * szDirectory) +{ + TCHAR * szDataPath; + int nError = ERROR_FILE_NOT_FOUND; + + // Try all known subdirectories + for(size_t i = 0; DataDirs[i] != NULL; i++) + { + // Create the eventual data path + szDataPath = CombinePath(szDirectory, DataDirs[i]); + if(szDataPath != NULL) + { + // Does that directory exist? + if(DirectoryExists(szDataPath)) + { + hs->szDataPath = szDataPath; + return ERROR_SUCCESS; + } + + // Free the data path + CASC_FREE(szDataPath); + } + } + + return nError; +} + + +//----------------------------------------------------------------------------- +// Public functions + +int LoadBuildInfo(TCascStorage * hs) +{ + PARSEINFOFILE PfnParseProc = NULL; + void * pvListFile; + int nError = ERROR_SUCCESS; + + switch(hs->BuildFileType) + { + case CascBuildInfo: + PfnParseProc = ParseFile_BuildInfo; + break; + + case CascBuildDb: + PfnParseProc = ParseFile_BuildDb; + break; + + default: + nError = ERROR_NOT_SUPPORTED; + break; + } + + // Parse the appropriate build file + if(nError == ERROR_SUCCESS) + { + pvListFile = ListFile_OpenExternal(hs->szBuildFile); + if(pvListFile != NULL) + { + // Parse the info file + nError = PfnParseProc(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // If the .build.info OR .build.db file has been loaded, + // proceed with loading the CDN config file and CDN build file + if(nError == ERROR_SUCCESS) + { + // Load the configuration file + pvListFile = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey); + if(pvListFile != NULL) + { + nError = LoadCdnConfigFile(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // Load the build file + if(nError == ERROR_SUCCESS) + { + pvListFile = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey); + if(pvListFile != NULL) + { + nError = LoadCdnBuildFile(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // Fill the index directory + if(nError == ERROR_SUCCESS) + { + // First, check for more common "data" subdirectory + if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL) + return ERROR_SUCCESS; + + // Second, try the "darch" subdirectory (older builds of HOTS - Alpha) + if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL) + return ERROR_SUCCESS; + + nError = ERROR_FILE_NOT_FOUND; + } + + return nError; +} + +// Checks whether there is a ".agent.db". If yes, the function +// sets "szRootPath" and "szDataPath" in the storage structure +// and returns ERROR_SUCCESS +int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory) +{ + TFileStream * pStream; + TCHAR * szBuildFile; + int nError = ERROR_FILE_NOT_FOUND; + + // Try to find any of the root files used in the history + for(size_t i = 0; BuildTypes[i].szFileName != NULL; i++) + { + // Create the full name of the .agent.db file + szBuildFile = CombinePath(szDirectory, BuildTypes[i].szFileName); + if(szBuildFile != NULL) + { + // Attempt to open the file + pStream = FileStream_OpenFile(szBuildFile, 0); + if(pStream != NULL) + { + // Free the stream + FileStream_Close(pStream); + + // Check for the data directory + nError = CheckDataDirectory(hs, szDirectory); + if(nError == ERROR_SUCCESS) + { + hs->szBuildFile = szBuildFile; + hs->BuildFileType = BuildTypes[i].BuildFileType; + return ERROR_SUCCESS; + } + } + + CASC_FREE(szBuildFile); + } + } + + return nError; +} + +// Parses single line from Overwatch. +// The line structure is: "#MD5|CHUNK_ID|FILENAME|INSTALLPATH" +// The line has all preceding spaces removed +int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, PQUERY_KEY PtrEncodingKey, char * szFileName, size_t nMaxChars) +{ + size_t nLength; + int nError; + + // Check the MD5 (aka encoding key) + if(szLinePtr[MD5_STRING_SIZE] != '|') + return ERROR_BAD_FORMAT; + + // Convert the encoding key to binary + PtrEncodingKey->cbData = MD5_HASH_SIZE; + nError = ConvertStringToBinary(szLinePtr, MD5_STRING_SIZE, PtrEncodingKey->pbData); + if(nError != ERROR_SUCCESS) + return nError; + + // Skip the MD5 + szLinePtr += MD5_STRING_SIZE+1; + + // Skip the chunk ID + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Get the archived file name + szLineEnd = SkipInfoVariable(szLinePtr, szLineEnd); + nLength = (size_t)(szLineEnd - szLinePtr - 1); + + // Get the file name + if(nLength > nMaxChars) + return ERROR_INSUFFICIENT_BUFFER; + + memcpy(szFileName, szLinePtr, nLength); + szFileName[nLength] = 0; + return ERROR_SUCCESS; +} diff --git a/dep/CascLib/src/CascFindFile.cpp b/dep/CascLib/src/CascFindFile.cpp index 0bfe16cae1d..bea2e308747 100644 --- a/dep/CascLib/src/CascFindFile.cpp +++ b/dep/CascLib/src/CascFindFile.cpp @@ -11,7 +11,6 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" //----------------------------------------------------------------------------- // Local functions @@ -30,16 +29,22 @@ static void FreeSearchHandle(TCascSearch * pSearch) // Close (dereference) the archive handle if(pSearch->hs != NULL) + { + // Give root handler chance to free their stuff + RootHandler_EndSearch(pSearch->hs->pRootHandler, pSearch); + + // Dereference the storage handle CascCloseStorage((HANDLE)pSearch->hs); - pSearch->hs = NULL; + pSearch->hs = NULL; + } // Free the file cache and frame array if(pSearch->szMask != NULL) CASC_FREE(pSearch->szMask); if(pSearch->szListFile != NULL) CASC_FREE(pSearch->szListFile); - if(pSearch->pStruct1C != NULL) - delete pSearch->pStruct1C; +// if(pSearch->pStruct1C != NULL) +// delete pSearch->pStruct1C; if(pSearch->pCache != NULL) ListFile_Free(pSearch->pCache); @@ -47,58 +52,6 @@ static void FreeSearchHandle(TCascSearch * pSearch) pSearch->szClassName = NULL; CASC_FREE(pSearch); } -/* -DWORD dwRootEntries = 0; -DWORD dwEncoEntries = 0; -DWORD dwIndexEntries = 0; -*/ -static bool VerifyRootEntry(TCascSearch * pSearch, PCASC_ROOT_ENTRY pRootEntry, PCASC_FIND_DATA pFindData, size_t nRootIndex) -{ - PCASC_ENCODING_ENTRY pEncodingEntry; - PCASC_INDEX_ENTRY pIndexEntry; - TCascStorage * hs = pSearch->hs; - QUERY_KEY QueryKey; - DWORD dwByteIndex = (DWORD)(nRootIndex / 0x08); - DWORD dwBitIndex = (DWORD)(nRootIndex & 0x07); - - // First of all, check if that entry has been reported before - // If the bit is set, then the file has already been reported - // by a previous search iteration - if(pSearch->BitArray[dwByteIndex] & (1 << dwBitIndex)) - return false; - pSearch->BitArray[dwByteIndex] |= (1 << dwBitIndex); - - // Increment the number of root entries -// dwRootEntries++; - - // Now try to find that encoding key in the array of encoding keys - QueryKey.pbData = (LPBYTE)pRootEntry->EncodingKey; - QueryKey.cbData = MD5_HASH_SIZE; - pEncodingEntry = FindEncodingEntry(hs, &QueryKey, NULL); - if(pEncodingEntry == NULL) - return false; - -// dwEncoEntries++; - - // Now try to find the index entry. Note that we take the first key - QueryKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; - QueryKey.cbData = MD5_HASH_SIZE; - pIndexEntry = FindIndexEntry(hs, &QueryKey); - if(pIndexEntry == NULL) - return false; - -// dwIndexEntries++; - - // Fill the name hash and the MD5 - memcpy(pFindData->EncodingKey, pRootEntry->EncodingKey, MD5_HASH_SIZE); - pFindData->FileNameHash = pRootEntry->FileNameHash; - pFindData->dwPackageIndex = 0; - pFindData->dwLocaleFlags = pRootEntry->Locales; - - // Fill-in the file size - pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); - return true; -} static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szListFile, const char * szMask) { @@ -106,7 +59,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis size_t cbToAllocate; // When using the MNDX info, do not allocate the extra bit array - cbToAllocate = sizeof(TCascSearch) + ((hs->pMndxInfo == NULL) ? (hs->RootTable.TableSize / 8) : 0); + cbToAllocate = sizeof(TCascSearch) + ((hs->pEncodingMap->TableSize + 7) / 8); pSearch = (TCascSearch *)CASC_ALLOC(BYTE, cbToAllocate); if(pSearch != NULL) { @@ -125,7 +78,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis // Save the other variables if(szListFile != NULL) { - pSearch->szListFile = NewStr(szListFile, 0); + pSearch->szListFile = CascNewStr(szListFile, 0); if(pSearch->szListFile == NULL) { FreeSearchHandle(pSearch); @@ -134,7 +87,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis } // Allocate the search mask - pSearch->szMask = NewStr(szMask, 0); + pSearch->szMask = CascNewStr(szMask, 0); if(pSearch->szMask == NULL) { FreeSearchHandle(pSearch); @@ -145,64 +98,106 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis return pSearch; } -static bool DoStorageSearch_ListFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) +// Perform searching using root-specific provider. +// The provider may need the listfile +static bool DoStorageSearch_RootFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) { - PCASC_ROOT_ENTRY pRootEntry; - TCascStorage * hs = pSearch->hs; - char szFileName2[MAX_PATH + 1]; - DWORD TableIndex = 0; + PCASC_ENCODING_ENTRY pEncodingEntry; + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY EncodingKey; + QUERY_KEY IndexKey; + LPBYTE pbEncodingKey; + DWORD EncodingIndex = 0; + DWORD LocaleFlags = 0; + DWORD FileSize = CASC_INVALID_SIZE; + DWORD ByteIndex; + DWORD BitMask; - // Get next file from the listfile - while(ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH)) + for(;;) { -#ifdef _DEBUG -// if(!_stricmp(pSearch->szFileName, "Character\\BloodElf\\Female\\DeathKnightEyeGlow.blp")) -// DebugBreak(); -#endif + // Attempt to find (the next) file from the root entry + pbEncodingKey = RootHandler_Search(pSearch->hs->pRootHandler, pSearch, &FileSize, &LocaleFlags); + if(pbEncodingKey == NULL) + return false; - // Normalize the file name found in the list file - NormalizeFileName_UpperBkSlash(szFileName2, pSearch->szFileName, MAX_PATH); - - // Find the root entry - pRootEntry = FindRootEntry(hs, szFileName2, &TableIndex); - if(pRootEntry != NULL) + // Verify whether the encoding key exists in the encoding table + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; + pEncodingEntry = FindEncodingEntry(pSearch->hs, &EncodingKey, &EncodingIndex); + if(pEncodingEntry != NULL) { - // Verify whether the file exists in the storage - if(VerifyRootEntry(pSearch, pRootEntry, pFindData, TableIndex)) - { - strcpy(pFindData->szFileName, pSearch->szFileName); - pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); - return true; - } - } - } + // Mark the item as already found + // Note: Duplicate items are allowed while we are searching using file names + // Do not exclude items from search if they were found before + ByteIndex = (DWORD)(EncodingIndex / 8); + BitMask = 1 << (EncodingIndex & 0x07); + pSearch->BitArray[ByteIndex] |= BitMask; + + // Locate the index entry + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey); + if(pIndexEntry == NULL) + continue; - // Listfile search ended - return false; -} + // If we retrieved the file size directly from the root provider, use it + // Otherwise, we need to retrieve it from the encoding entry + if(FileSize == CASC_INVALID_SIZE) + FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); -static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) -{ - PCASC_ROOT_ENTRY pRootEntry; - TCascStorage * hs = pSearch->hs; - - // Check if there is more files with the same name hash - while(pSearch->RootIndex < hs->RootTable.TableSize) - { - // Get the pointer to the root entry - pRootEntry = hs->RootTable.TablePtr + pSearch->RootIndex; - - // Verify if that root entry exists in the CASC storage - // and was not found before - if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex)) - { - pFindData->szFileName[0] = 0; - pFindData->szPlainName = NULL; + // Fill-in the found file + strcpy(pFindData->szFileName, pSearch->szFileName); + memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); + pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); + pFindData->dwLocaleFlags = LocaleFlags; + pFindData->dwFileSize = FileSize; return true; } + } +} - // Move to the next entry - pSearch->RootIndex++; +static bool DoStorageSearch_EncodingKey(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) +{ + PCASC_ENCODING_ENTRY pEncodingEntry; + PCASC_INDEX_ENTRY pIndexEntry; + TCascStorage * hs = pSearch->hs; + QUERY_KEY IndexKey; + DWORD ByteIndex; + DWORD BitMask; + + // Check for encoding keys that haven't been found yet + while(pSearch->IndexLevel1 < hs->pEncodingMap->TableSize) + { + // Check if that entry has been reported before + ByteIndex = (DWORD)(pSearch->IndexLevel1 / 8); + BitMask = 1 << (pSearch->IndexLevel1 & 0x07); + if((pSearch->BitArray[ByteIndex] & BitMask) == 0) + { + // Locate the index entry + pEncodingEntry = (PCASC_ENCODING_ENTRY)hs->pEncodingMap->HashTable[pSearch->IndexLevel1]; + if(pEncodingEntry != NULL) + { + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey); + if(pIndexEntry != NULL) + { + // Fill-in the found file + memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); + pFindData->szFileName[0] = 0; + pFindData->szPlainName = NULL; + pFindData->dwLocaleFlags = CASC_LOCALE_NONE; + pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); + + // Mark the entry as already-found + pSearch->BitArray[ByteIndex] |= BitMask; + return true; + } + } + } + + // Go to the next encoding entry + pSearch->IndexLevel1++; } // Nameless search ended @@ -211,10 +206,6 @@ static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindDat static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) { - // Are we searching using the MNDX ? - if(pSearch->hs->pMndxInfo != NULL) - return DoStorageSearch_MNDX(pSearch, pFindData); - // State 0: No search done yet if(pSearch->dwState == 0) { @@ -223,30 +214,25 @@ static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile); // Move the search phase to the listfile searching - pSearch->RootIndex = 0; + pSearch->IndexLevel1 = 0; pSearch->dwState++; - - // If either file stream or listfile cache are invalid, - // move to the next phase - if(pSearch->pCache == NULL) - pSearch->dwState++; } // State 1: Searching the list file if(pSearch->dwState == 1) { - if(DoStorageSearch_ListFile(pSearch, pFindData)) + if(DoStorageSearch_RootFile(pSearch, pFindData)) return true; // Move to the nameless search state - assert(pSearch->RootIndex == 0); + pSearch->IndexLevel1 = 0; pSearch->dwState++; } // State 2: Searching the remaining entries if(pSearch->dwState == 2) { - if(DoStorageSearch_Hash(pSearch, pFindData)) + if(DoStorageSearch_EncodingKey(pSearch, pFindData)) return true; // Move to the final search state @@ -275,19 +261,12 @@ HANDLE WINAPI CascFindFirstFile( if(szMask == NULL || pFindData == NULL) nError = ERROR_INVALID_PARAMETER; - // Allocate the structure for archive search + // Init the search structure and search handle if(nError == ERROR_SUCCESS) { // Clear the entire search structure memset(pFindData, 0, sizeof(CASC_FIND_DATA)); - // We must have listfile for non-MNDX storages - if(hs->pMndxInfo == NULL && szListFile == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; - } - // Allocate the search handle pSearch = AllocateSearchHandle(hs, szListFile, szMask); if(pSearch == NULL) diff --git a/dep/CascLib/src/CascLib.def b/dep/CascLib/src/CascLib.def new file mode 100644 index 00000000000..cb5f9166e49 --- /dev/null +++ b/dep/CascLib/src/CascLib.def @@ -0,0 +1,29 @@ +; +; Export file for Windows +; Copyright (c) 2015 Ladislav Zezula +; ladik@zezula.net +; + +LIBRARY CascLib.dll + +EXPORTS + + CascOpenStorage + CascGetStorageInfo + CascCloseStorage + + CascOpenFileByIndexKey + CascOpenFileByEncodingKey + CascOpenFile + CascGetFileSize + CascSetFilePointer + CascReadFile + CascCloseFile + + CascFindFirstFile + CascFindNextFile + CascFindClose + + GetLastError=Kernel32.GetLastError + SetLastError=Kernel32.SetLastError + \ No newline at end of file diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h index 330a4b2bb49..bad32eb2dba 100644 --- a/dep/CascLib/src/CascLib.h +++ b/dep/CascLib/src/CascLib.h @@ -39,7 +39,7 @@ extern "C" { #define CASC_STOR_XXXXX 0x00000001 // Not used // Values for CascOpenFile -#define CASC_FILE_XXXXX 0x00000001 // Not used +#define CASC_OPEN_BY_ENCODING_KEY 0x00000001 // The name is just the encoding key; skip ROOT file processing // Flags for file stream #define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file @@ -103,7 +103,7 @@ extern "C" { #ifndef MD5_HASH_SIZE #define MD5_HASH_SIZE 0x10 -#define MD5_STRING_SIZE 0x21 +#define MD5_STRING_SIZE 0x20 #endif #ifndef SHA1_DIGEST_SIZE @@ -146,9 +146,7 @@ typedef struct _CASC_FIND_DATA { char szFileName[MAX_PATH]; // Full name of the found file char * szPlainName; // Plain name of the found file - ULONGLONG FileNameHash; // File name hash BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key - DWORD dwPackageIndex; // File package index (HOTS only) DWORD dwLocaleFlags; // Locale flags (WoW only) DWORD dwFileSize; // Size of the file @@ -184,6 +182,16 @@ HANDLE WINAPI CascFindFirstFile(HANDLE hStorage, const char * szMask, PCASC_FIND bool WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData); bool WINAPI CascFindClose(HANDLE hFind); +//----------------------------------------------------------------------------- +// GetLastError/SetLastError support for non-Windows platform + +#ifndef PLATFORM_WINDOWS + +int GetLastError(); +void SetLastError(int nError); + +#endif // PLATFORM_WINDOWS + #ifdef __cplusplus } // extern "C" #endif diff --git a/dep/CascLib/src/CascMndxRoot.h b/dep/CascLib/src/CascMndx.h similarity index 95% rename from dep/CascLib/src/CascMndxRoot.h rename to dep/CascLib/src/CascMndx.h index bd93f230845..d1b6653d4fe 100644 --- a/dep/CascLib/src/CascMndxRoot.h +++ b/dep/CascLib/src/CascMndx.h @@ -13,6 +13,9 @@ class TFileNameDatabase; +#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported +#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX' + #define CASC_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type)) #define CASC_SEARCH_INITIALIZING 0 @@ -353,13 +356,4 @@ inline bool IS_SINGLE_CHAR_MATCH(TGenericArray & Table, DWORD ItemIndex) return ((Table.NameFragArray[ItemIndex].FragOffs & 0xFFFFFF00) == 0xFFFFFF00); } -//----------------------------------------------------------------------------- -// CASC functions related to MNDX - -int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); -PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName); -int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppFoundInfo); -bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData); -void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo); - #endif // __CASC_MNDX_ROOT__ diff --git a/dep/CascLib/src/CascOpenFile.cpp b/dep/CascLib/src/CascOpenFile.cpp index 2b8c3d3c4ad..c4c27a3f6a6 100644 --- a/dep/CascLib/src/CascOpenFile.cpp +++ b/dep/CascLib/src/CascOpenFile.cpp @@ -11,10 +11,6 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" - -//----------------------------------------------------------------------------- -// Local structures //----------------------------------------------------------------------------- // Local functions @@ -31,79 +27,19 @@ PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey) PCASC_INDEX_ENTRY pIndexEntry = NULL; if(hs->pIndexEntryMap != NULL) - pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData); + pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData, NULL); return pIndexEntry; } -PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex) +PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex) { - PCASC_ENCODING_ENTRY pEncodingEntry; - size_t StartEntry = 0; - size_t MidlEntry; - size_t EndEntry = hs->nEncodingEntries; - int nResult; + PCASC_ENCODING_ENTRY pEncodingEntry = NULL; - // Perform binary search - while(StartEntry < EndEntry) - { - // Calculate the middle of the interval - MidlEntry = StartEntry + ((EndEntry - StartEntry) / 2); - pEncodingEntry = hs->ppEncodingEntries[MidlEntry]; + if(hs->pEncodingMap != NULL) + pEncodingEntry = (PCASC_ENCODING_ENTRY)Map_FindObject(hs->pEncodingMap, pEncodingKey->pbData, PtrIndex); - // Did we find it? - nResult = memcmp(pEncodingKey->pbData, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); - if(nResult == 0) - { - if(PtrIndex != NULL) - PtrIndex[0] = MidlEntry; - return pEncodingEntry; - } - - // Move the interval to the left or right - (nResult < 0) ? EndEntry = MidlEntry : StartEntry = MidlEntry + 1; - } - - // Not found, sorry - return NULL; -} - -// Also used in CascSearchFile -PCASC_ROOT_ENTRY FindRootEntry(TCascStorage * hs, const char * szFileName, DWORD * PtrTableIndex) -{ - PCASC_ROOT_ENTRY pRootEntry; - ULONGLONG FileNameHash; - DWORD TableIndex; - uint32_t dwHashHigh = 0; - uint32_t dwHashLow = 0; - - // Calculate the HASH value of the normalized file name - hashlittle2(szFileName, strlen(szFileName), &dwHashHigh, &dwHashLow); - FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; - - // Get the first table index - TableIndex = (DWORD)(FileNameHash & (hs->RootTable.TableSize - 1)); - assert(hs->RootTable.ItemCount < hs->RootTable.TableSize); - - // Search the proper entry - for(;;) - { - // Does the has match? - pRootEntry = hs->RootTable.TablePtr + TableIndex; - if(pRootEntry->FileNameHash == FileNameHash) - { - if(PtrTableIndex != NULL) - PtrTableIndex[0] = TableIndex; - return pRootEntry; - } - - // If the entry is free, the file is not there - if(pRootEntry->FileNameHash == 0 && pRootEntry->SumValue == 0) - return NULL; - - // Move to the next entry - TableIndex = (DWORD)((TableIndex + 1) & (hs->RootTable.TableSize - 1)); - } + return pEncodingEntry; } static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry) @@ -187,7 +123,7 @@ static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DW // Prepare the file index and open the file by index // Note: We don't know what to do if there is more than just one index key // We always take the first file present. Is that correct? - IndexKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); IndexKey.cbData = MD5_HASH_SIZE; if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, ppCascFile)) { @@ -259,13 +195,10 @@ bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile) { - PCASC_ROOT_ENTRY_MNDX pRootEntryMndx = NULL; - PCASC_ROOT_ENTRY pRootEntry; - PCASC_PACKAGE pPackage; TCascStorage * hs; QUERY_KEY EncodingKey; - char * szStrippedName; - char szFileName2[MAX_PATH+1]; + LPBYTE pbEncodingKey; + BYTE KeyBuffer[MD5_HASH_SIZE]; int nError = ERROR_SUCCESS; CASCLIB_UNUSED(dwLocale); @@ -285,55 +218,37 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal return false; } - // If the storage has a MNDX root directory, use it to search the entry - if(hs->pMndxInfo != NULL) + // If the user is opening the file via encoding key, skip the ROOT file processing + if((dwFlags & CASC_OPEN_BY_ENCODING_KEY) == 0) { - // Convert the file name to lowercase + slashes - NormalizeFileName_LowerSlash(szFileName2, szFileName, MAX_PATH); - - // Find the package number - pPackage = FindMndxPackage(hs, szFileName2); - if(pPackage != NULL) + // Let the root directory provider get us the encoding key + pbEncodingKey = RootHandler_GetKey(hs->pRootHandler, szFileName); + if(pbEncodingKey == NULL) { - // Cut the package name off the full path - szStrippedName = szFileName2 + pPackage->nLength; - while(szStrippedName[0] == '/') - szStrippedName++; + SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } - nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &pRootEntryMndx); - if(nError == ERROR_SUCCESS) - { - // Prepare the encoding key - EncodingKey.pbData = pRootEntryMndx->EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - } - } - else - { - nError = ERROR_FILE_NOT_FOUND; - } + // Setup the encoding key + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; } else { - // Convert the file name to lowercase + slashes - NormalizeFileName_UpperBkSlash(szFileName2, szFileName, MAX_PATH); + // Check the length of the file name + if(strlen(szFileName) < MD5_STRING_SIZE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } - // Check the root directory for that hash - pRootEntry = FindRootEntry(hs, szFileName2, NULL); - if(pRootEntry != NULL) - { - // Prepare the root key - EncodingKey.pbData = (LPBYTE)pRootEntry->EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - nError = ERROR_SUCCESS; - } - else - { - nError = ERROR_FILE_NOT_FOUND; - } + // Convert the file name to binary blob + EncodingKey.pbData = KeyBuffer; + EncodingKey.cbData = MD5_HASH_SIZE; + nError = ConvertStringToBinary(szFileName, MD5_STRING_SIZE, KeyBuffer); } - // Use the root key to find the file in the encoding table entry + // Use the encoding key to find the file in the encoding table entry if(nError == ERROR_SUCCESS) { if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, (TCascFile **)phFile)) @@ -344,10 +259,10 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal } #ifdef CASCLIB_TEST - if(phFile[0] != NULL && pRootEntryMndx != NULL) - { - ((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize; - } +// if(phFile[0] != NULL && pRootEntryMndx != NULL) +// { +// ((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize; +// } #endif if(nError != ERROR_SUCCESS) diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp index 6a8d83ee903..c3d623df9f0 100644 --- a/dep/CascLib/src/CascOpenStorage.cpp +++ b/dep/CascLib/src/CascOpenStorage.cpp @@ -13,19 +13,12 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" - -//----------------------------------------------------------------------------- -// Dumping options - -#ifdef _DEBUG -#define CASC_DUMP_ROOT_FILE 2 // The root file will be dumped (level 2) -#endif //----------------------------------------------------------------------------- // Local structures -#define CASC_INITIAL_ROOT_TABLE_SIZE 0x00100000 +// Size of one segment in the ENCODING table +// The segment is filled by entries of type #define CASC_ENCODING_SEGMENT_SIZE 0x1000 typedef struct _BLOCK_SIZE_AND_HASH @@ -67,25 +60,10 @@ typedef struct _FILE_INDEX_HEADER_V2 } FILE_INDEX_HEADER_V2, *PFILE_INDEX_HEADER_V2; -typedef struct _FILE_ENCODING_HEADER -{ - BYTE Magic[2]; // "EN" - BYTE field_2; - BYTE field_3; - BYTE field_4; - BYTE field_5[2]; - BYTE field_7[2]; - BYTE NumSegments[4]; // Number of entries (big endian) - BYTE field_D[4]; - BYTE field_11; - BYTE SegmentsPos[4]; // Offset of encoding segments - -} FILE_ENCODING_HEADER, *PFILE_ENCODING_HEADER; - typedef struct _FILE_ENCODING_SEGMENT { - BYTE FirstEncodingKey[MD5_HASH_SIZE]; // The first encoding key in the segment - BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment + BYTE FirstEncodingKey[MD5_HASH_SIZE]; // The first encoding key in the segment + BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment } FILE_ENCODING_SEGMENT, *PFILE_ENCODING_SEGMENT; @@ -143,28 +121,6 @@ static bool IsIndexFileName_V2(const TCHAR * szFileName) _tcsicmp(szFileName + 0x0A, _T(".idx")) == 0); } -static void QUERY_KEY_Free(PQUERY_KEY pBlob) -{ - if(pBlob != NULL) - { - if(pBlob->pbData != NULL) - CASC_FREE(pBlob->pbData); - - pBlob->pbData = NULL; - pBlob->cbData = 0; - } -} - -static void QUERY_KEY_FreeArray(PQUERY_KEY pBlobArray) -{ - // Free the buffer in the first blob - // (will also free all buffers in the array) - QUERY_KEY_Free(pBlobArray); - - // Free the array itself - CASC_FREE(pBlobArray); -} - static bool IsCascIndexHeader_V1(LPBYTE pbFileData, DWORD cbFileData) { PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData; @@ -206,52 +162,99 @@ static bool IsCascIndexHeader_V2(LPBYTE pbFileData, DWORD cbFileData) return (HashHigh == pSizeAndHash->dwBlockHash); } -LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd) +static bool CutLastPathPart(TCHAR * szWorkPath) { - // Validate the file locale block - pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pLocaleBlockHdr + 1); - if(pbFilePointer > pbFileEnd) - return NULL; + size_t nLength = _tcslen(szWorkPath); - // Validate the array of 32-bit integers - pBlockInfo->pInt32Array = (PDWORD)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pInt32Array + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); - if(pbFilePointer > pbFileEnd) - return NULL; + for(nLength = _tcslen(szWorkPath); nLength > 0; nLength--) + { + if(szWorkPath[nLength] == '\\' || szWorkPath[nLength] == '/') + { + szWorkPath[nLength] = 0; + return true; + } + } - // Validate the array of root entries - pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); - if(pbFilePointer > pbFileEnd) - return NULL; + return false; +} - // Return the position of the next block - return pbFilePointer; +static int InsertExtraFile( + TCascStorage * hs, + const char * szFileName, + PQUERY_KEY pQueryKey) +{ + // If the given key is not encoding key (aka, it's an index key), + // we need to create a fake encoding entry + if(pQueryKey->cbData == MD5_HASH_SIZE * 2) + { + PCASC_ENCODING_ENTRY pNewEntry; + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY IndexKey; + + // Find the entry in the index table in order to get the file size + IndexKey.pbData = pQueryKey->pbData + MD5_HASH_SIZE; + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(hs, &IndexKey); + if(pIndexEntry == NULL) + return ERROR_FILE_NOT_FOUND; + + // Create a fake entry in the encoding map + pNewEntry = (PCASC_ENCODING_ENTRY)Array_Insert(&hs->ExtraEntries, NULL, 1); + if(pNewEntry == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the encoding entry + pNewEntry->KeyCount = 1; + pNewEntry->FileSizeBE[0] = pIndexEntry->FileSizeLE[3]; + pNewEntry->FileSizeBE[1] = pIndexEntry->FileSizeLE[2]; + pNewEntry->FileSizeBE[2] = pIndexEntry->FileSizeLE[1]; + pNewEntry->FileSizeBE[3] = pIndexEntry->FileSizeLE[0]; + memcpy(pNewEntry->EncodingKey, pQueryKey->pbData, MD5_HASH_SIZE); + memcpy(pNewEntry + 1, pQueryKey->pbData + MD5_HASH_SIZE, MD5_HASH_SIZE); + + // Insert the entry to the map of encoding keys + Map_InsertObject(hs->pEncodingMap, pNewEntry, pNewEntry->EncodingKey); + } + + // Now we need to insert the entry to the root handler in order + // to be able to translate file name to encoding key + return RootHandler_Insert(hs->pRootHandler, szFileName, pQueryKey->pbData); } static int InitializeCascDirectories(TCascStorage * hs, const TCHAR * szDataPath) { - TCHAR * szLastPathPart; + TCHAR * szWorkPath; + int nError = ERROR_NOT_ENOUGH_MEMORY; - // Save the game data directory - hs->szDataPath = NewStr(szDataPath, 0); - - // Save the root game directory - hs->szRootPath = NewStr(szDataPath, 0); - - // Find the last part - szLastPathPart = hs->szRootPath; - for(size_t i = 0; hs->szRootPath[i] != 0; i++) + // Find the root directory of the storage. The root directory + // is the one where ".build.info" is. + szWorkPath = CascNewStr(szDataPath, 0); + if(szWorkPath != NULL) { - if(hs->szRootPath[i] == '\\' || hs->szRootPath[i] == '/') - szLastPathPart = hs->szRootPath + i; - } - - // Cut the last part - if(szLastPathPart != NULL) - szLastPathPart[0] = 0; - return (hs->szRootPath && hs->szDataPath) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; + // Get the length and go up until we find the ".build.info" or ".build.db" + for(;;) + { + // Is this a game directory? + nError = CheckGameDirectory(hs, szWorkPath); + if(nError == ERROR_SUCCESS) + { + nError = ERROR_SUCCESS; + break; + } + + // Cut one path part + if(!CutLastPathPart(szWorkPath)) + { + nError = ERROR_FILE_NOT_FOUND; + break; + } + } + + // Free the work path buffer + CASC_FREE(szWorkPath); + } + + return nError; } static bool IndexDirectory_OnFileFound( @@ -566,7 +569,7 @@ static int CreateArrayOfIndexEntries(TCascStorage * hs) // 9e dc a7 8f e2 09 ad d8 b7 (encoding file) // f3 5e bb fb d1 2b 3f ef 8b // c8 69 9f 18 a2 5e df 7e 52 - Map_InsertObject(pMap, pIndexEntry->IndexKey); + Map_InsertObject(pMap, pIndexEntry, pIndexEntry->IndexKey); // Move to the next entry pIndexEntry++; @@ -581,28 +584,28 @@ static int CreateArrayOfIndexEntries(TCascStorage * hs) return nError; } -static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEncodingSegment, DWORD dwNumberOfSegments) +static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEncodingSegment, DWORD dwNumSegments) { PCASC_ENCODING_ENTRY pEncodingEntry; - size_t nMaxEntries; - size_t nEntries = 0; + DWORD dwMaxEntries; int nError = ERROR_SUCCESS; // Sanity check - assert(hs->ppEncodingEntries == NULL); assert(hs->pIndexEntryMap != NULL); + assert(hs->pEncodingMap == NULL); - // Calculate the largest eventual number of encodign entries - nMaxEntries = (dwNumberOfSegments * CASC_ENCODING_SEGMENT_SIZE) / (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE); + // Calculate the largest eventual number of encoding entries + // Add space for extra entries + dwMaxEntries = (dwNumSegments * CASC_ENCODING_SEGMENT_SIZE) / (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE); - // Allocate the array of pointers to encoding entries - hs->ppEncodingEntries = CASC_ALLOC(PCASC_ENCODING_ENTRY, nMaxEntries); - if(hs->ppEncodingEntries != NULL) + // Create the map of the encoding entries + hs->pEncodingMap = Map_Create(dwMaxEntries + CASC_EXTRA_FILES, MD5_HASH_SIZE, FIELD_OFFSET(CASC_ENCODING_ENTRY, EncodingKey)); + if(hs->pEncodingMap != NULL) { - LPBYTE pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments); + LPBYTE pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumSegments); // Parse all segments - for(DWORD i = 0; i < dwNumberOfSegments; i++) + for(DWORD i = 0; i < dwNumSegments; i++) { LPBYTE pbEncodingEntry = pbStartOfSegment; LPBYTE pbEndOfSegment = pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE - sizeof(CASC_ENCODING_ENTRY) - MD5_HASH_SIZE; @@ -616,7 +619,7 @@ static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEn break; // Insert the pointer the array - hs->ppEncodingEntries[nEntries++] = pEncodingEntry; + Map_InsertObject(hs->pEncodingMap, pEncodingEntry, pEncodingEntry->EncodingKey); // Move to the next encoding entry pbEncodingEntry += sizeof(CASC_ENCODING_ENTRY) + (pEncodingEntry->KeyCount * MD5_HASH_SIZE); @@ -625,9 +628,6 @@ static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEn // Move to the next segment pbStartOfSegment += CASC_ENCODING_SEGMENT_SIZE; } - - // Remember the total number of encoding entries - hs->nEncodingEntries = nEntries; } else nError = ERROR_NOT_ENOUGH_MEMORY; @@ -684,8 +684,16 @@ static LPBYTE LoadEncodingFileToMemory(HANDLE hFile, DWORD * pcbEncodingFile) CascReadFile(hFile, &EncodingHeader, sizeof(CASC_ENCODING_HEADER), &dwBytesRead); if(dwBytesRead == sizeof(CASC_ENCODING_HEADER)) { - dwNumSegments = ConvertBytesToInteger_4(EncodingHeader.NumSegments); - dwSegmentPos = ConvertBytesToInteger_4(EncodingHeader.SegmentsPos); + // Check the version and sizes + if(EncodingHeader.Version != 0x01 || EncodingHeader.ChecksumSizeA != MD5_HASH_SIZE || EncodingHeader.ChecksumSizeB != MD5_HASH_SIZE) + { + assert(false); + return NULL; + } + + // Get the number of segments + dwNumSegments = ConvertBytesToInteger_4(EncodingHeader.Entries_TableA); + dwSegmentPos = ConvertBytesToInteger_4(EncodingHeader.Size_StringTable1); if(EncodingHeader.Magic[0] == 'E' && EncodingHeader.Magic[1] == 'N' && dwSegmentPos != 0 && dwNumSegments != 0) nError = ERROR_SUCCESS; } @@ -721,36 +729,16 @@ static LPBYTE LoadEncodingFileToMemory(HANDLE hFile, DWORD * pcbEncodingFile) static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) { - TCascFile * hf; LPBYTE pbRootFile = NULL; DWORD cbRootFile = 0; DWORD dwBytesRead = 0; - BYTE StartOfFile[0x10]; int nError = ERROR_SUCCESS; - // Dummy read the first 16 bytes - CascReadFile(hFile, &StartOfFile, sizeof(StartOfFile), &dwBytesRead); - if(dwBytesRead != sizeof(StartOfFile)) + // Retrieve the size of the ROOT file + cbRootFile = CascGetFileSize(hFile, NULL); + if(cbRootFile == 0) nError = ERROR_BAD_FORMAT; - // Calculate and allocate space for the entire file - if(nError == ERROR_SUCCESS) - { - // Convert the file handle to pointer to TCascFile - hf = IsValidFileHandle(hFile); - if(hf != NULL) - { - // Parse the frames to get the file size - for(DWORD i = 0; i < hf->FrameCount; i++) - { - cbRootFile += hf->pFrames[i].FrameSize; - } - } - - // Evaluate the error - nError = (cbRootFile != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; - } - // Allocate space for the entire file if(nError == ERROR_SUCCESS) { @@ -762,12 +750,9 @@ static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) // If all went OK, we load the entire file to memory if(nError == ERROR_SUCCESS) { - // Copy the header itself - memcpy(pbRootFile, StartOfFile, sizeof(StartOfFile)); - - // Read the rest of the data - CascReadFile(hFile, pbRootFile + sizeof(StartOfFile), cbRootFile - sizeof(StartOfFile), &dwBytesRead); - if(dwBytesRead != (cbRootFile - sizeof(StartOfFile))) + // Read the entire file to memory + CascReadFile(hFile, pbRootFile, cbRootFile, &dwBytesRead); + if(dwBytesRead != cbRootFile) nError = ERROR_FILE_CORRUPT; } @@ -780,17 +765,19 @@ static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) static int LoadEncodingFile(TCascStorage * hs) { PFILE_ENCODING_SEGMENT pEncodingSegment; - PCASC_ENCODING_ENTRY pEncodingEntry; + QUERY_KEY EncodingKey; LPBYTE pbStartOfSegment; LPBYTE pbEncodingFile = NULL; HANDLE hFile = NULL; DWORD cbEncodingFile = 0; - DWORD dwNumberOfSegments = 0; + DWORD dwNumSegments = 0; DWORD dwSegmentsPos = 0; int nError = ERROR_SUCCESS; // Open the encoding file - if(!CascOpenFileByIndexKey((HANDLE)hs, &hs->EncodingEKey, 0, &hFile)) + EncodingKey.pbData = hs->EncodingKey.pbData + MD5_HASH_SIZE; + EncodingKey.cbData = MD5_HASH_SIZE; + if(!CascOpenFileByIndexKey((HANDLE)hs, &EncodingKey, 0, &hFile)) nError = GetLastError(); // Load the entire ENCODING file to memory @@ -808,20 +795,25 @@ static int LoadEncodingFile(TCascStorage * hs) // Verify all encoding segments if(nError == ERROR_SUCCESS) { - // Save the encoding header - hs->pEncodingHeader = (PCASC_ENCODING_HEADER)pbEncodingFile; + PCASC_ENCODING_HEADER pEncodingHeader = (PCASC_ENCODING_HEADER)pbEncodingFile; // Convert size and offset - dwNumberOfSegments = ConvertBytesToInteger_4(hs->pEncodingHeader->NumSegments); - dwSegmentsPos = ConvertBytesToInteger_4(hs->pEncodingHeader->SegmentsPos); + dwNumSegments = ConvertBytesToInteger_4(pEncodingHeader->Entries_TableA); + dwSegmentsPos = ConvertBytesToInteger_4(pEncodingHeader->Size_StringTable1); + + // Store the encoding file to the CASC storage + hs->EncodingFile.pbData = pbEncodingFile; + hs->EncodingFile.cbData = cbEncodingFile; // Allocate the array of encoding segments pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos); - pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments); + pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumSegments); // Go through all encoding segments and verify them - for(DWORD i = 0; i < dwNumberOfSegments; i++) + for(DWORD i = 0; i < dwNumSegments; i++) { + PCASC_ENCODING_ENTRY pEncodingEntry = (PCASC_ENCODING_ENTRY)pbStartOfSegment; + // Check if there is enough space in the buffer if((pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE) > (pbEncodingFile + cbEncodingFile)) { @@ -837,8 +829,7 @@ static int LoadEncodingFile(TCascStorage * hs) // break; // } - // Check if the encoding key matches - pEncodingEntry = (PCASC_ENCODING_ENTRY)pbStartOfSegment; + // Check if the encoding key matches with the expected first value if(memcmp(pEncodingEntry->EncodingKey, pEncodingSegment->FirstEncodingKey, MD5_HASH_SIZE)) { nError = ERROR_FILE_CORRUPT; @@ -856,241 +847,12 @@ static int LoadEncodingFile(TCascStorage * hs) if(nError == ERROR_SUCCESS) { pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos); - nError = CreateMapOfEncodingKeys(hs, pEncodingSegment, dwNumberOfSegments); + nError = CreateMapOfEncodingKeys(hs, pEncodingSegment, dwNumSegments); } + return nError; } -typedef struct _CHECK_ROOT_ENTRY_INPUT -{ - ULONGLONG FileNameHash; - DWORD SumValue; - DWORD EncodingKey[4]; - -} CHECK_ROOT_ENTRY_INPUT, *PCHECK_ROOT_ENTRY_INPUT; - -typedef struct _CHECK_ROOT_ENTRY_OUTPUT -{ - DWORD field_0; - DWORD field_4; - DWORD field_8; - bool field_C; - -} CHECK_ROOT_ENTRY_OUTPUT, *PCHECK_ROOT_ENTRY_OUTPUT; - - -// WoW6: 00413F61 -static bool EnlargeHashTableIfMoreThan75PercentUsed(PCASC_ROOT_HASH_TABLE pRootTable, DWORD NewItemCount) -{ - // Don't relocate anything, just check - assert((double)NewItemCount / (double)pRootTable->TableSize < .75); - return true; -} - -// WOW6: 00414402 -// Finds an existing root table entry or a free one -PCASC_ROOT_ENTRY CascRootTable_FindFreeEntryWithEnlarge( - PCASC_ROOT_HASH_TABLE pRootTable, - PCASC_ROOT_ENTRY pNewEntry) -{ - PCASC_ROOT_ENTRY pEntry; - DWORD TableIndex; - - // The table size must be a power of two - assert((pRootTable->TableSize & (pRootTable->TableSize - 1)) == 0); - - // Make sure that number of occupied items is never bigger - // than 75% of the table size - if(!EnlargeHashTableIfMoreThan75PercentUsed(pRootTable, pRootTable->ItemCount + 1)) - return NULL; - - // Get the start index of the table - TableIndex = (DWORD)(pNewEntry->FileNameHash) & (pRootTable->TableSize - 1); - - // If that entry is already occupied, move to a next entry - for(;;) - { - // Check that entry if it's free or not - pEntry = pRootTable->TablePtr + TableIndex; - if(pEntry->SumValue == 0) - break; - - // Is the found entry equal to the existing one? - if(pEntry->FileNameHash == pNewEntry->FileNameHash) - break; - - // Move to the next entry - TableIndex = (TableIndex + 1) & (pRootTable->TableSize - 1); - } - - // Either return a free entry or an existing one - return pEntry; -} - -// WOW6: 004145D1 -static void CascRootTable_InsertTableEntry( - PCASC_ROOT_HASH_TABLE pRootTable, - PCASC_ROOT_ENTRY pNewEntry) -{ - PCASC_ROOT_ENTRY pEntry; - - // Find an existing entry or an empty one - pEntry = CascRootTable_FindFreeEntryWithEnlarge(pRootTable, pNewEntry); - assert(pEntry != NULL); - - // If that entry is not used yet, fill it in - if(pEntry->FileNameHash == 0) - { - *pEntry = *pNewEntry; - pRootTable->ItemCount++; - } -} - -static int LoadWowRootFileLocales( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleMask, - bool bLoadBlocksWithFlags80, - BYTE HighestBitValue) -{ - CASC_ROOT_ENTRY NewRootEntry; - ROOT_BLOCK_INFO BlockInfo; - LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; - LPBYTE pbFilePointer; - - // Now parse the root file - for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) - { - // Validate the file locale block - pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); - if(pbFilePointer == NULL) - break; - - // WoW.exe (build 19116): Entries with flag 0x100 set are skipped - if(BlockInfo.pLocaleBlockHdr->Flags & 0x100) - continue; - - // WoW.exe (build 19116): Entries with flag 0x80 set are skipped if arg_4 is set to FALSE (which is by default) - if(bLoadBlocksWithFlags80 == 0 && (BlockInfo.pLocaleBlockHdr->Flags & 0x80)) - continue; - - // WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to arg_8 are skipped - if((BYTE)(BlockInfo.pLocaleBlockHdr->Flags >> 0x1F) != HighestBitValue) - continue; - - // WoW.exe (build 19116): Locales other than defined mask are skipped too - if((BlockInfo.pLocaleBlockHdr->Locales & dwLocaleMask) == 0) - continue; - - // Reset the sum value - NewRootEntry.SumValue = 0; - - // WoW.exe (build 19116): Blocks with zero files are skipped - for(DWORD i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) - { - // (004147A3) Prepare the CASC_ROOT_ENTRY structure - NewRootEntry.FileNameHash = BlockInfo.pRootEntries[i].FileNameHash; - NewRootEntry.SumValue = NewRootEntry.SumValue + BlockInfo.pInt32Array[i]; - NewRootEntry.Locales = BlockInfo.pLocaleBlockHdr->Locales; - NewRootEntry.EncodingKey[0] = BlockInfo.pRootEntries[i].EncodingKey[0]; - NewRootEntry.EncodingKey[1] = BlockInfo.pRootEntries[i].EncodingKey[1]; - NewRootEntry.EncodingKey[2] = BlockInfo.pRootEntries[i].EncodingKey[2]; - NewRootEntry.EncodingKey[3] = BlockInfo.pRootEntries[i].EncodingKey[3]; - - // Insert the root table item to the hash table - CascRootTable_InsertTableEntry(&hs->RootTable, &NewRootEntry); - NewRootEntry.SumValue++; - } - } - - return 1; -} - -// WoW.exe: 004146C7 (BuildManifest::Load) -static int LoadWowRootFileWithParams( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleBits, - BYTE HighestBitValue) -{ - // Load the locale as-is - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, dwLocaleBits, false, HighestBitValue); - - // If we wanted enGB, we also load enUS for the missing files - if(dwLocaleBits == CASC_LOCALE_ENGB) - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); - - if(dwLocaleBits == CASC_LOCALE_PTPT) - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); - - return ERROR_SUCCESS; -} - -/* - // Code from WoW.exe - if(dwLocaleBits == CASC_LOCALE_DUAL_LANG) - { - // Is this english version of WoW? - if(arg_4 == CASC_LOCALE_BIT_ENUS) - { - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENGB, false, HighestBitValue); - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); - return ERROR_SUCCESS; - } - - // Is this portuguese version of WoW? - if(arg_4 == CASC_LOCALE_BIT_PTBR) - { - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTPT, false, HighestBitValue); - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); - } - } - - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, (1 << arg_4), false, HighestBitValue); -*/ - -static int LoadWowRootFile( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleMask) -{ - int nError; - - // Dump the root file, if needed -#ifdef CASC_DUMP_ROOT_FILE - //CascDumpRootFile(hs, - // pbRootFile, - // cbRootFile, - // "\\casc_root_%build%.txt", - // _T("\\Ladik\\Appdir\\CascLib\\listfile\\listfile-wow6.txt"), - // CASC_DUMP_ROOT_FILE); -#endif - - // Allocate root table entries. Note that the initial size - // of the root table is set to 0x00200000 by World of Warcraft 6.x - hs->RootTable.TablePtr = CASC_ALLOC(CASC_ROOT_ENTRY, CASC_INITIAL_ROOT_TABLE_SIZE); - hs->RootTable.TableSize = CASC_INITIAL_ROOT_TABLE_SIZE; - if(hs->RootTable.TablePtr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Clear the entire table - memset(hs->RootTable.TablePtr, 0, CASC_INITIAL_ROOT_TABLE_SIZE * sizeof(CASC_ROOT_ENTRY)); - - // Load the root file - nError = LoadWowRootFileWithParams(hs, pbRootFile, cbRootFile, dwLocaleMask, 0); - if(nError != ERROR_SUCCESS) - return nError; - - nError = LoadWowRootFileWithParams(hs, pbRootFile, cbRootFile, dwLocaleMask, 1); - if(nError != ERROR_SUCCESS) - return nError; - - return ERROR_SUCCESS; -} - static int LoadRootFile(TCascStorage * hs, DWORD dwLocaleMask) { PDWORD FileSignature; @@ -1100,49 +862,70 @@ static int LoadRootFile(TCascStorage * hs, DWORD dwLocaleMask) int nError = ERROR_SUCCESS; // Sanity checks - assert(hs->RootTable.TablePtr == NULL); - assert(hs->RootTable.ItemCount == 0); - assert(hs->ppEncodingEntries != NULL); + assert(hs->pEncodingMap != NULL); + assert(hs->pRootHandler == NULL); // Locale: The default parameter is 0 - in that case, // we assign the default locale, loaded from the .build.info file if(dwLocaleMask == 0) dwLocaleMask = hs->dwDefaultLocale; - // The root file is either MNDX file (Heroes of the Storm) - // or a file containing an array of root entries (World of Warcraft 6.0+) - // Note: The "root" key file's MD5 hash is equal to its name - // in the configuration + // Load the entire ROOT file to memory if(!CascOpenFileByEncodingKey((HANDLE)hs, &hs->RootKey, 0, &hFile)) nError = GetLastError(); - // Load the entire ROOT file to memory + // Load the entire file to memory if(nError == ERROR_SUCCESS) { - // Load the necessary part of the ENCODING file to memory pbRootFile = LoadRootFileToMemory(hFile, &cbRootFile); - if(pbRootFile == NULL || cbRootFile <= sizeof(PFILE_LOCALE_BLOCK)) - nError = ERROR_FILE_CORRUPT; - - // Close the encoding file CascCloseFile(hFile); } - // Check if the file is a MNDX file - if(nError == ERROR_SUCCESS) + // Check if the version of the ROOT file + if(nError == ERROR_SUCCESS && pbRootFile != NULL) { FileSignature = (PDWORD)pbRootFile; - if(FileSignature[0] == CASC_MNDX_SIGNATURE) + switch(FileSignature[0]) { - nError = LoadMndxRootFile(hs, pbRootFile, cbRootFile); - } - else - { - // WOW6: 00415000 - nError = LoadWowRootFile(hs, pbRootFile, cbRootFile, dwLocaleMask); + case CASC_MNDX_ROOT_SIGNATURE: + nError = RootHandler_CreateMNDX(hs, pbRootFile, cbRootFile); + break; + + case CASC_DIABLO3_ROOT_SIGNATURE: + nError = RootHandler_CreateDiablo3(hs, pbRootFile, cbRootFile); + break; + + case CASC_OVERWATCH_ROOT_SIGNATURE: + nError = RootHandler_CreateOverwatch(hs, pbRootFile, cbRootFile); + break; + + default: + nError = RootHandler_CreateWoW6(hs, pbRootFile, cbRootFile, dwLocaleMask); + break; } } + // Insert entry for the + if(nError == ERROR_SUCCESS) + { + InsertExtraFile(hs, "ENCODING", &hs->EncodingKey); + InsertExtraFile(hs, "ROOT", &hs->RootKey); + InsertExtraFile(hs, "DOWNLOAD", &hs->DownloadKey); + InsertExtraFile(hs, "INSTALL", &hs->InstallKey); + } + +#ifdef _DEBUG + if(nError == ERROR_SUCCESS) + { + //RootFile_Dump(hs, + // pbRootFile, + // cbRootFile, + // _T("\\casc_root_%build%.txt"), + // _T("\\Ladik\\Appdir\\CascLib\\listfile\\listfile-wow6.txt"), + // DUMP_LEVEL_INDEX_ENTRIES); + } +#endif + // Free the root file CASC_FREE(pbRootFile); return nError; @@ -1154,19 +937,19 @@ static TCascStorage * FreeCascStorage(TCascStorage * hs) if(hs != NULL) { - // Free the MNDX info - if(hs->pPackages != NULL) - CASC_FREE(hs->pPackages); - if(hs->pMndxInfo != NULL) - FreeMndxInfo(hs->pMndxInfo); + // Free the root handler + if(hs->pRootHandler != NULL) + RootHandler_Close(hs->pRootHandler); + hs->pRootHandler = NULL; + + // Free the extra encoding entries + Array_Free(&hs->ExtraEntries); // Free the pointers to file entries - if(hs->RootTable.TablePtr != NULL) - CASC_FREE(hs->RootTable.TablePtr); - if(hs->ppEncodingEntries != NULL) - CASC_FREE(hs->ppEncodingEntries); - if(hs->pEncodingHeader != NULL) - CASC_FREE(hs->pEncodingHeader); + if(hs->pEncodingMap != NULL) + Map_Free(hs->pEncodingMap); + if(hs->EncodingFile.pbData != NULL) + CASC_FREE(hs->EncodingFile.pbData); if(hs->pIndexEntryMap != NULL) Map_Free(hs->pIndexEntryMap); @@ -1195,25 +978,24 @@ static TCascStorage * FreeCascStorage(TCascStorage * hs) CASC_FREE(hs->szRootPath); if(hs->szDataPath != NULL) CASC_FREE(hs->szDataPath); + if(hs->szBuildFile != NULL) + CASC_FREE(hs->szBuildFile); if(hs->szIndexPath != NULL) CASC_FREE(hs->szIndexPath); if(hs->szUrlPath != NULL) CASC_FREE(hs->szUrlPath); - // Fre the blob arrays - QUERY_KEY_FreeArray(hs->pArchiveArray); - QUERY_KEY_FreeArray(hs->pPatchArchiveArray); - QUERY_KEY_FreeArray(hs->pEncodingKeys); - // Free the blobs - QUERY_KEY_Free(&hs->CdnConfigKey); - QUERY_KEY_Free(&hs->CdnBuildKey); - QUERY_KEY_Free(&hs->ArchiveGroup); - QUERY_KEY_Free(&hs->PatchArchiveGroup); - QUERY_KEY_Free(&hs->RootKey); - QUERY_KEY_Free(&hs->PatchKey); - QUERY_KEY_Free(&hs->DownloadKey); - QUERY_KEY_Free(&hs->InstallKey); + FreeCascBlob(&hs->CdnConfigKey); + FreeCascBlob(&hs->CdnBuildKey); + FreeCascBlob(&hs->ArchivesGroup); + FreeCascBlob(&hs->ArchivesKey); + FreeCascBlob(&hs->PatchArchivesKey); + FreeCascBlob(&hs->RootKey); + FreeCascBlob(&hs->PatchKey); + FreeCascBlob(&hs->DownloadKey); + FreeCascBlob(&hs->InstallKey); + FreeCascBlob(&hs->EncodingKey); // Free the storage structure hs->szClassName = NULL; @@ -1266,6 +1048,13 @@ bool WINAPI CascOpenStorage(const TCHAR * szDataPath, DWORD dwLocaleMask, HANDLE nError = LoadEncodingFile(hs); } + // Initialize the dynamic array for extra files + // Reserve space for 0x20 encoding entries + if(nError == ERROR_SUCCESS) + { + nError = Array_Create(&hs->ExtraEntries, CASC_ENCODING_ENTRY_1, CASC_EXTRA_FILES); + } + // Load the index files if(nError == ERROR_SUCCESS) { @@ -1309,8 +1098,7 @@ bool WINAPI CascGetStorageInfo( break; case CascStorageFeatures: - if(hs->pMndxInfo != NULL) - dwInfoValue |= CASC_FEATURE_LISTFILE; + dwInfoValue |= (hs->pRootHandler->dwRootFlags & ROOT_FLAG_HAS_NAMES) ? CASC_FEATURE_LISTFILE : 0; break; case CascStorageGameInfo: @@ -1342,8 +1130,6 @@ bool WINAPI CascGetStorageInfo( return true; } - - bool WINAPI CascCloseStorage(HANDLE hStorage) { TCascStorage * hs; diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h index 3bf1efde4b8..5d0190e07cc 100644 --- a/dep/CascLib/src/CascPort.h +++ b/dep/CascLib/src/CascPort.h @@ -176,6 +176,7 @@ #define _tcsrchr strrchr #define _tcsstr strstr #define _tcsspn strspn + #define _tcsncmp strncmp #define _tprintf printf #define _stprintf sprintf #define _tremove remove diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp index 83fdd0d2096..72eb2c4b647 100644 --- a/dep/CascLib/src/CascReadFile.cpp +++ b/dep/CascLib/src/CascReadFile.cpp @@ -98,9 +98,10 @@ static int LoadFileFrames(TCascFile * hf) else nError = GetLastError(); - // Note: Do not take the FileSize from the sum of frames. - // This value is invalid when loading the ENCODING file. -// hf->FileSize = FileSize; + // Note: on ENCODING file, this value is almost always bigger + // then the real size of ENCODING. We handle this problem + // by calculating size of the ENCODIG file from its header. + hf->FileSize = FileSize; #ifdef CASCLIB_TEST hf->FileSize_FrameSum = FileSize; @@ -264,6 +265,85 @@ static PCASC_FILE_FRAME FindFileFrame(TCascFile * hf, DWORD FilePointer) return NULL; } +static int ProcessFileFrame( + LPBYTE pbOutBuffer, + DWORD cbOutBuffer, + LPBYTE pbInBuffer, + DWORD cbInBuffer, + DWORD dwFrameIndex) +{ + LPBYTE pbTempBuffer; + LPBYTE pbWorkBuffer; + DWORD cbTempBuffer = CASCLIB_MAX(cbInBuffer, cbOutBuffer); + DWORD cbWorkBuffer = cbOutBuffer + 1; + DWORD dwStepCount = 0; + bool bWorkComplete = false; + int nError = ERROR_SUCCESS; + + // Allocate the temporary buffer that will serve as output + pbWorkBuffer = pbTempBuffer = CASC_ALLOC(BYTE, cbTempBuffer); + if(pbWorkBuffer == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the loop + for(;;) + { + // Set the output buffer. + // Even operations: extract to temporary buffer + // Odd operations: extract to output buffer + pbWorkBuffer = (dwStepCount & 0x01) ? pbOutBuffer : pbTempBuffer; + cbWorkBuffer = (dwStepCount & 0x01) ? cbOutBuffer : cbTempBuffer; + + // Perform the operation specific to the operation ID + switch(pbInBuffer[0]) + { + case 'E': // Encrypted files + nError = CascDecrypt(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1, dwFrameIndex); + bWorkComplete = (nError != ERROR_SUCCESS); + break; + + case 'Z': // ZLIB compressed files + nError = CascDecompress(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1); + bWorkComplete = true; + break; + + case 'N': // Normal stored files + nError = CascDirectCopy(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1); + bWorkComplete = true; + break; + + case 'F': // Recursive frames - not supported + default: // Unrecognized - if we unpacked something, we consider it done + nError = ERROR_NOT_SUPPORTED; + bWorkComplete = true; + assert(false); + break; + } + + // Are we done? + if(bWorkComplete) + break; + + // Set the input buffer to the work buffer + pbInBuffer = pbWorkBuffer; + cbInBuffer = cbWorkBuffer; + dwStepCount++; + } + + // If the data are currently in the temporary buffer, + // we need to copy them to output buffer + if(nError == ERROR_SUCCESS && pbWorkBuffer != pbOutBuffer) + { + if(cbWorkBuffer != cbOutBuffer) + nError = ERROR_INSUFFICIENT_BUFFER; + memcpy(pbOutBuffer, pbWorkBuffer, cbOutBuffer); + } + + // Free the temporary buffer + CASC_FREE(pbTempBuffer); + return nError; +} + //----------------------------------------------------------------------------- // Public functions @@ -299,7 +379,7 @@ DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh) } // Make sure that the file header area is loaded - nError = EnsureHeaderAreaIsLoaded(hf); + nError = EnsureFrameHeadersLoaded(hf); if(nError != ERROR_SUCCESS) { SetLastError(nError); @@ -387,7 +467,6 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW DWORD dwFilePointer = 0; DWORD dwEndPointer = 0; DWORD dwFrameSize; - DWORD cbOutBuffer; bool bReadResult; int nError = ERROR_SUCCESS; @@ -423,7 +502,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW { // Get the frame pFrame = FindFileFrame(hf, hf->FilePointer); - if(pFrame == NULL) + if(pFrame == NULL || pFrame->CompressedSize < 1) nError = ERROR_FILE_CORRUPT; } @@ -439,7 +518,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // Perform block read from each file frame while(dwFilePointer < dwEndPointer) { - LPBYTE pbRawData = NULL; + LPBYTE pbFrameData = NULL; DWORD dwFrameStart = pFrame->FrameFileOffset; DWORD dwFrameEnd = pFrame->FrameFileOffset + pFrame->FrameSize; @@ -457,8 +536,8 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW } // We also need to allocate buffer for the raw data - pbRawData = CASC_ALLOC(BYTE, pFrame->CompressedSize); - if(pbRawData == NULL) + pbFrameData = CASC_ALLOC(BYTE, pFrame->CompressedSize); + if(pbFrameData == NULL) { nError = ERROR_NOT_ENOUGH_MEMORY; break; @@ -466,7 +545,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // Load the raw file data to memory FileOffset = pFrame->FrameArchiveOffset; - bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbRawData, pFrame->CompressedSize); + bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbFrameData, pFrame->CompressedSize); // Note: The raw file data size could be less than expected // Happened in WoW build 19342 with the ROOT file. MD5 in the frame header @@ -484,43 +563,34 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // If the frame offset is before EOF and frame end is beyond EOF, correct it if(FileOffset < StreamSize && dwFrameSize < pFrame->CompressedSize) { - memset(pbRawData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize)); + memset(pbFrameData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize)); bReadResult = true; } } // If the read result failed, we cannot finish reading it - if(bReadResult == false) + if(bReadResult && VerifyDataBlockHash(pbFrameData, pFrame->CompressedSize, pFrame->md5)) { - CASC_FREE(pbRawData); - nError = GetLastError(); - break; + // Convert the source frame to the file cache + nError = ProcessFileFrame(hf->pbFileCache, + pFrame->FrameSize, + pbFrameData, + pFrame->CompressedSize, + (DWORD)(pFrame - hf->pFrames)); + if(nError == ERROR_SUCCESS) + { + // Set the start and end of the cache + hf->CacheStart = dwFrameStart; + hf->CacheEnd = dwFrameEnd; + } } - - // Verify the block MD5 - if(!VerifyDataBlockHash(pbRawData, pFrame->CompressedSize, pFrame->md5)) + else { - CASC_FREE(pbRawData); nError = ERROR_FILE_CORRUPT; - break; } - // Decompress the file frame - cbOutBuffer = pFrame->FrameSize; - nError = CascDecompress(hf->pbFileCache, &cbOutBuffer, pbRawData, pFrame->CompressedSize); - if(nError != ERROR_SUCCESS || cbOutBuffer != pFrame->FrameSize) - { - CASC_FREE(pbRawData); - nError = ERROR_FILE_CORRUPT; - break; - } - - // Set the start and end of the cache - hf->CacheStart = dwFrameStart; - hf->CacheEnd = dwFrameEnd; - - // Free the decompress buffer, if needed - CASC_FREE(pbRawData); + // Free the raw frame data + CASC_FREE(pbFrameData); } // Copy the decompressed data diff --git a/dep/CascLib/src/CascRootFile_Diablo3.cpp b/dep/CascLib/src/CascRootFile_Diablo3.cpp new file mode 100644 index 00000000000..98a42cc3226 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Diablo3.cpp @@ -0,0 +1,1189 @@ +/*****************************************************************************/ +/* CascRootFile_Diablo3.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Support for loading Diablo 3 ROOT file */ +/* Note: D3 offsets refer to Diablo III.exe 2.2.0.30013 (32-bit) */ +/* SHA1: e4f17eca8aad8dde70870bf932ac3f5b85f17a1f */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 04.03.15 1.00 Lad The first version of CascRootFile_Diablo3.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +#define DIABLO3_SUBDIR_SIGNATURE 0xEAF1FE87 +#define DIABLO3_PACKAGES_SIGNATURE 0xAABB0002 +#define DIABLO3_MAX_SUBDIRS 0x20 + +#define DIABLO3_INVALID_INDEX 0xFFFFFFFF +#define DIABLO3_INVALID_FILE 0xFFFFFFFF +#define DIABLO3_MAX_ASSETS 70 // Maximum possible number of assets +#define DIABLO3_MAX_LEVEL0_LENGTH 0x10 // Maximum length of the level-0 directory name + +#define INVALID_FILE_INDEX 0xFFFFFFFF +#define INVALID_ASSET_INDEX 0xFF + +#define ENTRY_FLAG_DIRECTORY_ENTRY 0x80 // The file is actually a directory entry +#define ENTRY_FLAG_PLAIN_NAME 0x01 // If set, the file entry contains offset of the plain file name +#define ENTRY_FLAG_FULL_NAME 0x02 // If set, the file entry contains offset of the full name +#define ENTRY_FLAG_FLAGS_MASK 0xF0 // Mask for the entry flags +#define ENTRY_FLAG_NAME_MASK 0x0F // Mask for the entry file name type + +// Values for CASC_FILE_ENTRY::dwFlags +#define CASC_ENTRY_SHORT_NAME 0x000000001 // If set, the name is in format XXYYplain-name[\sub-index].ext +#define CASC_ENTRY_HAS_SUBINDEX 0x000000002 // If set, the subitem is present in the file name (i.e. XXYYplain-name\sub-index.ext) + +#define SEARCH_PHASE_NAMES 0 // Searching named entry +#define SEARCH_PHASE_FILE_IDS 1 // Searching filed by ID + +// Macro for constructing 64-bit integer from root-index, file-index and sub-index +// The result value is RRAAAAAAAASSSSSS +#define MAKE_INDEX64(ri, fi, si) (((ULONGLONG)ri << 0x38) | ((ULONGLONG)fi << 0x18) | ((ULONGLONG)si)) +#define INDEX64_ROOT_INDEX(hash) (DWORD)((hash >> 0x38) & 0x000000FF) +#define INDEX64_FILE_INDEX(hash) (DWORD)((hash >> 0x18) & 0xFFFFFFFF) +#define INDEX64_SUB_INDEX(hash) (DWORD)((hash >> 0x00) & 0x00FFFFFF) + +// On-disk structure for a file given by file number +typedef struct _DIABLO3_FILEID1_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + DWORD FileIndex; // File index +} DIABLO3_FILEID1_ENTRY, *PDIABLO3_FILEID1_ENTRY; + +// On-disk structure for a file given by file number and suffix +typedef struct _DIABLO3_FILEID2_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + DWORD FileIndex; // File index + DWORD SubIndex; // File subindex, like "SoundBank\3D Ambience\0000.smp" +} DIABLO3_FILEID2_ENTRY, *PDIABLO3_FILEID2_ENTRY; + +// On-disk structure of the named entry +typedef struct _DIABLO3_NAMED_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + BYTE szFileName[1]; // ASCIIZ file name (variable length) +} DIABLO3_NAMED_ENTRY, *PDIABLO3_NAMED_ENTRY; + +// On-disk structure of CoreToc.dat header +typedef struct _DIABLO3_CORE_TOC_HEADER +{ + DWORD EntryCounts[DIABLO3_MAX_ASSETS]; // Array of number of entries (files) for each asset (level-1 directory) + DWORD EntryOffsets[DIABLO3_MAX_ASSETS]; // Array of offsets of each DIABLO3_CORE_TOC_ENTRY, relative to data after header + DWORD Unknowns[DIABLO3_MAX_ASSETS]; // Unknown + DWORD Alignment; +} DIABLO3_CORE_TOC_HEADER, *PDIABLO3_CORE_TOC_HEADER; + +// On-disk structure of the entry in CoreToc.dat +typedef struct _DIABLO3_CORE_TOC_ENTRY +{ + DWORD AssetIndex; // Index of the Diablo3 asset (aka directory) + DWORD FileIndex; // File index + DWORD NameOffset; // Offset of the plain file name + +} DIABLO3_CORE_TOC_ENTRY, *PDIABLO3_CORE_TOC_ENTRY; + +// In-memory structure of parsed directory header +typedef struct _DIABLO3_DIR_HEADER +{ + LPBYTE pbEntries1; + LPBYTE pbEntries2; + LPBYTE pbEntries3; + DWORD dwEntries1; + DWORD dwEntries2; + DWORD dwEntries3; +} DIABLO3_DIR_HEADER, *PDIABLO3_DIR_HEADER; + +// In-memory structure of loaded CoreTOC.dat +typedef struct _DIABLO3_CORE_TOC +{ + DIABLO3_CORE_TOC_HEADER Hdr; // Header of CoreTOC.dat + + LPBYTE pbCoreToc; // Content of the CoreTOC.dat file + DIABLO3_CORE_TOC_ENTRY Entries[1]; // Buffer for storing the entries (variable length) + +} DIABLO3_CORE_TOC, *PDIABLO3_CORE_TOC; + +// On-disk structure of Packages.dat header +typedef struct _DIABLO3_PACKAGES_DAT_HEADER +{ + DWORD Signature; + DWORD NumberOfNames; +} DIABLO3_PACKAGES_DAT_HEADER, *PDIABLO3_PACKAGES_DAT_HEADER; + +// Structure for conversion DirectoryID -> Directory name +typedef struct _DIABLO3_ASSET_INFO +{ + const char * szDirectoryName; // Directory name + const char * szExtension; + +} DIABLO3_ASSET_INFO; +typedef const DIABLO3_ASSET_INFO * PDIABLO3_ASSET_INFO; + +// In-memory structure of a file entry in the linear file list +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key + ULONGLONG FileNameHash; // Hash of the full file name + DWORD dwFileName; // Offset of the name (in name's dynamic array) + DWORD dwFlags; // Entry flags (see CASC_ENTRY_XXXX) + + DWORD NameOffset; // Offset of the name (in name's dynamic array) + USHORT SubIndex; // File\SubFile index + BYTE AssetIndex; // Asset index (aka directory index) + BYTE EntryFlags; // Entry flags +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +//----------------------------------------------------------------------------- +// Structure definitions for Diablo3 root file + +struct TRootHandler_Diablo3 : public TRootHandler +{ + // Linear global list of all files + DYNAMIC_ARRAY FileTable; + + // Linear global list of names + DYNAMIC_ARRAY FileNames; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; +}; + +//----------------------------------------------------------------------------- +// Local variables + +static const DIABLO3_ASSET_INFO Assets[] = +{ +// DIR-NAME EXTENSION +// ========== ========= + {NULL, NULL}, // 0x00 + {"Actor", "acr"}, // 0x01 + {"Adventure", "adv"}, // 0x02 + {NULL, NULL}, // 0x03 + {NULL, NULL}, // 0x04 + {"AmbientSound", "ams"}, // 0x05 + {"Anim", "ani"}, // 0x06 + {"Anim2D", "an2"}, // 0x07 + {"AnimSet", "ans"}, // 0x08 + {"Appearance", "app"}, // 0x09 + {NULL, NULL}, // 0x0A + {"Cloth", "clt"}, // 0x0B + {"Conversation", "cnv"}, // 0x0C + {NULL, NULL}, // 0x0D + {"EffectGroup", "efg"}, // 0x0E + {"Encounter", "enc"}, // 0x0F + {NULL, NULL}, // 0x10 + {"Explosion", "xpl"}, // 0x11 + {NULL, NULL}, // 0x12 + {"Font", "fnt"}, // 0x13 + {"GameBalance", "gam"}, // 0x14 + {"Globals", "glo"}, // 0x15 + {"LevelArea", "lvl"}, // 0x16 + {"Light", "lit"}, // 0x17 + {"MarkerSet", "mrk"}, // 0x18 + {"Monster", "mon"}, // 0x19 + {"Observer", "obs"}, // 0x1A + {"Particle", "prt"}, // 0x1B + {"Physics", "phy"}, // 0x1C + {"Power", "pow"}, // 0x1D + {NULL, NULL}, // 0x1E + {"Quest", "qst"}, // 0x1F + {"Rope", "rop"}, // 0x20 + {"Scene", "scn"}, // 0x21 + {"SceneGroup", "scg"}, // 0x22 + {NULL, NULL}, // 0x23 + {"ShaderMap", "shm"}, // 0x24 + {"Shaders", "shd"}, // 0x25 + {"Shakes", "shk"}, // 0x26 + {"SkillKit", "skl"}, // 0x27 + {"Sound", "snd"}, // 0x28 + {"SoundBank", "sbk"}, // 0x29 + {"StringList", "stl"}, // 0x2A + {"Surface", "srf"}, // 0x2B + {"Textures", "tex"}, // 0x2C + {"Trail", "trl"}, // 0x2D + {"UI", "ui"}, // 0x2E + {"Weather", "wth"}, // 0x2F + {"Worlds", "wrl"}, // 0x30 + {"Recipe", "rcp"}, // 0x31 + {NULL, NULL}, // 0x32 + {"Condition", "cnd"}, // 0x33 + {NULL, NULL}, // 0x34 + {NULL, NULL}, // 0x35 + {NULL, NULL}, // 0x36 + {NULL, NULL}, // 0x37 + {"Act", "act"}, // 0x38 + {"Material", "mat"}, // 0x39 + {"QuestRange", "qsr"}, // 0x3A + {"Lore", "lor"}, // 0x3B + {"Reverb", "rev"}, // 0x3C + {"PhysMesh", "phm"}, // 0x3D + {"Music", "mus"}, // 0x3E + {"Tutorial", "tut"}, // 0x3F + {"BossEncounter", "bos"}, // 0x40 + {NULL, NULL}, // 0x41 + {"Accolade", "aco"}, // 0x42 +}; + +static const DIABLO3_ASSET_INFO UnknownAsset = {"Unknown", "xxx"}; + +#define DIABLO3_ASSET_COUNT (sizeof(Assets) / sizeof(Assets[0])) + +//----------------------------------------------------------------------------- +// Local functions + +static PDIABLO3_ASSET_INFO GetAssetInfo(DWORD dwAssetIndex) +{ + if(dwAssetIndex < DIABLO3_ASSET_COUNT && Assets[dwAssetIndex].szDirectoryName != NULL) + return &Assets[dwAssetIndex]; + return &UnknownAsset; +} + +static DWORD VerifyNamedFileEntry(LPBYTE pbNamedEntry, LPBYTE pbFileEnd) +{ + LPBYTE pbFileName = ((PDIABLO3_NAMED_ENTRY)pbNamedEntry)->szFileName; + + // Find the end of the name + while(pbFileName < pbFileEnd && pbFileName[0] != 0) + pbFileName++; + + // Did we get past the end of the root file? + if(pbFileName >= pbFileEnd) + return 0; + pbFileName++; + + // Return the length of the structure + return (DWORD)(pbFileName - pbNamedEntry); +} + +static char * FindPackageName( + PCASC_MAP pPackageMap, + const char * szAssetName, + const char * szPlainName) +{ + char szFileName[MAX_PATH+1]; + size_t nLength; + + // Construct the name without extension and find it in the map + nLength = sprintf(szFileName, "%s\\%s", szAssetName, szPlainName); + return (char *)Map_FindString(pPackageMap, szFileName, szFileName + nLength); +} + +static size_t CreateShortName( + PCASC_MAP pPackageMap, + DWORD dwRootIndex, // Level-0-dir: Index of the root subdirectory + DWORD dwAssetIndex, // Level-1-dir: Index of the asset name + const char * szPlainName, // Plain name of the file, without extension + DWORD dwSubIndex, + char * szBuffer) +{ + PDIABLO3_ASSET_INFO pAssetInfo = GetAssetInfo(dwAssetIndex); + const char * szPackageName = NULL; + const char * szFormat; + size_t nLength; + + // Write the level-0 directory index as 2-digit hexa number + assert(dwRootIndex < 0x100); + *szBuffer++ = IntToHexChar[dwRootIndex >> 0x04]; + *szBuffer++ = IntToHexChar[dwRootIndex & 0x0F]; + + // Write the level-1 directory index as 2-digit hexa number + assert(dwAssetIndex < 0x100); + *szBuffer++ = IntToHexChar[dwAssetIndex >> 0x04]; + *szBuffer++ = IntToHexChar[dwAssetIndex & 0x0F]; + + // Construct the file name with ending "." for extension + szFormat = (dwSubIndex != DIABLO3_INVALID_INDEX) ? "%s\\%04u." : "%s."; + nLength = sprintf(szBuffer, szFormat, szPlainName, dwSubIndex); + + // Try to fixup the file extension from the package name. + // File extensions are not predictable because for subitems, + // they are not always equal to the main items: + // + // SoundBank\3D Ambience.sbk + // SoundBank\3D Ambience\0000.smp + // SoundBank\3D Ambience\0002.smp + // ... + // SoundBank\Angel.sbk + // SoundBank\Angel\0000.fsb + // SoundBank\Angel\0002.fsb + // + // We use the Base\Data_D3\PC\Misc\Packages.dat for real file extensions, where possible + // + if(pPackageMap != NULL) + { + // Retrieve the asset name + szPackageName = FindPackageName(pPackageMap, pAssetInfo->szDirectoryName, szBuffer); + if(szPackageName != NULL) + { + strcpy(szBuffer, szPackageName + strlen(pAssetInfo->szDirectoryName) + 1); + nLength = strlen(szBuffer); + } + } + + // If we havent't found the package, we either use the default asset extension or "xxx" + if(szPackageName == NULL) + { + if(dwSubIndex == DIABLO3_INVALID_INDEX) + { + strcpy(szBuffer + nLength, pAssetInfo->szExtension); + nLength += strlen(pAssetInfo->szExtension); + } + else + { + strcpy(szBuffer + nLength, "xxx"); + nLength += 3; + } + } + + // Return the length of the short file name + return nLength + 4; +} + +static size_t CreateFileName( + TRootHandler_Diablo3 * pRootHandler, + const char * szShortName, // Short file name of the file + char * szBuffer) +{ + PCASC_FILE_ENTRY pRootEntry; + const char * szNameLevel0; + const char * szNameLevel1 = NULL; + DWORD dwRootIndex0 = 0; + DWORD dwAssetIndex = 0; + + // Retrieve the level-0 and level-1 directory indexes + ConvertStringToInt08(szShortName+0, &dwRootIndex0); + ConvertStringToInt08(szShortName+2, &dwAssetIndex); + + // Retrieve the name of the level-0 directory (aka root subdirectory) + pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, dwRootIndex0); + szNameLevel0 = (char *)Array_ItemAt(&pRootHandler->FileNames, pRootEntry->dwFileName); + + // Retrieve the name of the level-1 directory (aka asset name) + if(dwAssetIndex < DIABLO3_ASSET_COUNT) + szNameLevel1 = Assets[dwAssetIndex].szDirectoryName; + if(szNameLevel1 == NULL) + szNameLevel1 = UnknownAsset.szDirectoryName; + + // Copy the rest of the name as-is + return sprintf(szBuffer, "%s\\%s\\%s", szNameLevel0, szNameLevel1, szShortName + 4); +} + + +// Creates a map of String -> Pointer +static PCASC_MAP CreatePackageMap( + LPBYTE pbPackagesDat, + LPBYTE pbPackagesEnd) +{ + PDIABLO3_PACKAGES_DAT_HEADER pDatHeader = (PDIABLO3_PACKAGES_DAT_HEADER)pbPackagesDat; + PCASC_MAP pPackageMap; + + // Get the header + if((pbPackagesDat + sizeof(DIABLO3_PACKAGES_DAT_HEADER)) >= pbPackagesEnd) + return NULL; + pbPackagesDat += sizeof(DIABLO3_PACKAGES_DAT_HEADER); + + // Check the signature and name count + if(pDatHeader->Signature != DIABLO3_PACKAGES_SIGNATURE) + return NULL; + + // Create the map for fast search of the file name + pPackageMap = Map_Create(pDatHeader->NumberOfNames, KEY_LENGTH_STRING, 0); + if(pPackageMap != NULL) + { + char * szFileName = (char *)pbPackagesDat; + + // Go as long as there is something + for(DWORD i = 0; i < pDatHeader->NumberOfNames; i++) + { + // Get the file extension + if((LPBYTE)szFileName >= pbPackagesEnd) + break; + + // Insert the file name to the map. The file extension is not included + Map_InsertString(pPackageMap, szFileName, true); + szFileName = szFileName + strlen(szFileName) + 1; + } + } + + return pPackageMap; +} + +// Insert an entry with file name as-is +static int InsertFileEntry( + TRootHandler_Diablo3 * pRootHandler, + ENCODING_KEY & EncodingKey, + const char * szFileName, + size_t cchFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + + // We must not allow the file name array to be reallocated. + // Reallocating the array would cause pointers in TRootHandler_Diablo3::pRootMap + // become invalid + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Insert the plain name to the root handler's global name list + szFileName = (const char *)Array_Insert(&pRootHandler->FileNames, szFileName, cchFileName); + if(szFileName == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Make sure that we don't exceed the file limit at this phase + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Store the info into the file entry + pFileEntry->EncodingKey = EncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName); + pFileEntry->dwFlags = 0; + + // Verify collisions (debug version only) + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + + // Calculate the file name hash + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + + // Success + return ERROR_SUCCESS; +} + +static int ParseDirEntries_FileId1( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + PDIABLO3_FILEID1_ENTRY pEntry = (PDIABLO3_FILEID1_ENTRY)pbFileEntries; + PCASC_FILE_ENTRY pFileEntry; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Parse the all ID1 entries in the file + for(DWORD i = 0; i < dwFileEntries; i++, pEntry++) + { + // Insert the file entry to the global list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Fill the index entry + pFileEntry->EncodingKey = pEntry->EncodingKey; + pFileEntry->FileNameHash = MAKE_INDEX64(dwRootDirIndex, pEntry->FileIndex, 0); + pFileEntry->dwFlags = CASC_ENTRY_SHORT_NAME; + } + + return ERROR_SUCCESS; +} + +static int ParseDirEntries_FileId2( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + PDIABLO3_FILEID2_ENTRY pEntry = (PDIABLO3_FILEID2_ENTRY)pbFileEntries; + PCASC_FILE_ENTRY pFileEntry; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Parse the all ID1 entries in the file + for(DWORD i = 0; i < dwFileEntries; i++, pEntry++) + { + // Insert the file entry to the global list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Fill the index entry + pFileEntry->EncodingKey = pEntry->EncodingKey; + pFileEntry->FileNameHash = MAKE_INDEX64(dwRootDirIndex, pEntry->FileIndex, pEntry->SubIndex); + pFileEntry->dwFlags = CASC_ENTRY_SHORT_NAME | CASC_ENTRY_HAS_SUBINDEX; + } + + return ERROR_SUCCESS; +} + +static int ParseDirEntries_Named( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + LPBYTE pbFileEnd, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + char szFileName[MAX_PATH+1]; + char * szNamePtr = szFileName; + DWORD cbFileEntry; + int nError = ERROR_SUCCESS; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // If we the file is not in the root directory itself, + // prepare the prefix for the root directory. + if(dwRootDirIndex != DIABLO3_INVALID_INDEX) + { + PCASC_FILE_ENTRY pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, dwRootDirIndex); + const char * szRootName = (const char *)Array_ItemAt(&pRootHandler->FileNames, pRootEntry->dwFileName); + + // Copy the root directory name + while(szRootName[0] != 0) + *szNamePtr++ = *szRootName++; + + // Append the backslash + *szNamePtr++ = '\\'; + } + + // Parse the file entry + while(pbFileEntries < pbFileEnd) + { + PDIABLO3_NAMED_ENTRY pNamedEntry = (PDIABLO3_NAMED_ENTRY)pbFileEntries; + DWORD cchFileName; + + // Verify the named entry whether it does not go beyond the EOF + cbFileEntry = VerifyNamedFileEntry(pbFileEntries, pbFileEnd); + if(cbFileEntry == 0) + return ERROR_FILE_CORRUPT; + + // Append the file name to the prepared file name + // This way we obtain the full name and the name lookup + // will be fully operational + memcpy(szNamePtr, pNamedEntry->szFileName, (cbFileEntry - sizeof(ENCODING_KEY))); + cchFileName = (DWORD)((szNamePtr - szFileName) + (cbFileEntry - sizeof(ENCODING_KEY))); + + // Insert the named entry to the global file table + nError = InsertFileEntry(pRootHandler, + pNamedEntry->EncodingKey, + szFileName, + cchFileName); + if(nError != ERROR_SUCCESS) + return nError; + + // Move the pointer to the next entry + pbFileEntries += cbFileEntry; + } + + return ERROR_SUCCESS; +} + +static void ResolveFullFileNames( + TRootHandler_Diablo3 * pRootHandler, + PDIABLO3_CORE_TOC_ENTRY pCoreTocEntries, + PCASC_MAP pPackageMap, + LPBYTE pbCoreTocFile, + DWORD dwFileIndexes) +{ + PCASC_FILE_ENTRY pFileEntry; + char * szPlainName; + char * szNamePtr; + size_t nLength; + DWORD dwRootIndex; + DWORD dwFileIndex; + DWORD dwSubIndex; + char szShortName[MAX_PATH+1]; + char szFullName[MAX_PATH+1]; + + // Parse the entire file table + for(size_t i = 0; i < pRootHandler->FileTable.ItemCount; i++) + { + // Retrieve the file entry at n-th position + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, i); + + // Skip the items that already have full name + if(pFileEntry->dwFlags & CASC_ENTRY_SHORT_NAME) + { + // Retrieve the file index of that file + dwRootIndex = INDEX64_ROOT_INDEX(pFileEntry->FileNameHash); + dwFileIndex = INDEX64_FILE_INDEX(pFileEntry->FileNameHash); + dwSubIndex = (pFileEntry->dwFlags & CASC_ENTRY_HAS_SUBINDEX) ? INDEX64_SUB_INDEX(pFileEntry->FileNameHash) : DIABLO3_INVALID_INDEX; + assert(dwFileIndex < dwFileIndexes); + + // Get the plain name of the file + szPlainName = (char *)(pbCoreTocFile + pCoreTocEntries[dwFileIndex].NameOffset); + + // Create the short file name + nLength = CreateShortName(pPackageMap, + dwRootIndex, + pCoreTocEntries[dwFileIndex].AssetIndex, + szPlainName, + dwSubIndex, + szShortName); + + // Insert the short name to the list of the names + szNamePtr = (char *)Array_Insert(&pRootHandler->FileNames, szShortName, nLength + 1); + pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szNamePtr); + + // Create the full file name + nLength = CreateFileName(pRootHandler, szShortName, szFullName); + pFileEntry->FileNameHash = CalcFileNameHash(szFullName); + + // Insert the entry to the name map. Use the mapping of FullName -> FileHash + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + } + } +} + +static LPBYTE LoadFileToMemory(TCascStorage * hs, LPBYTE pbEncodingKey, DWORD * pcbFileData) +{ + QUERY_KEY EncodingKey; + LPBYTE pbFileData = NULL; + HANDLE hFile; + DWORD cbBytesRead = 0; + DWORD cbFileData = 0; + + // Open the file by encoding key + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; + if(CascOpenFileByEncodingKey((HANDLE)hs, &EncodingKey, 0, &hFile)) + { + // Retrieve the file size + cbFileData = CascGetFileSize(hFile, NULL); + if(cbFileData > 0) + { + pbFileData = CASC_ALLOC(BYTE, cbFileData); + if(pbFileData != NULL) + { + CascReadFile(hFile, pbFileData, cbFileData, &cbBytesRead); + } + } + + // Close the file + CascCloseFile(hFile); + } + + // Give the file to the caller + if(pcbFileData != NULL) + pcbFileData[0] = cbBytesRead; + return pbFileData; +} + +static LPBYTE LoadFileToMemory(TCascStorage * hs, const char * szFileName, DWORD * pcbFileData) +{ + LPBYTE pbEncodingKey = NULL; + LPBYTE pbFileData = NULL; + + // Try to find encoding key for the file + pbEncodingKey = RootHandler_GetKey(hs->pRootHandler, szFileName); + if(pbEncodingKey != NULL) + pbFileData = LoadFileToMemory(hs, pbEncodingKey, pcbFileData); + + return pbFileData; +} + +static int ParseDirectoryHeader( + PDIABLO3_DIR_HEADER pDirHeader, + LPBYTE pbDirFile, + LPBYTE pbFileEnd) +{ + DWORD dwSignature = 0; + + // + // Structure of a Diablo3 directory file + // 1) Signature (4 bytes) + // 2) Number of DIABLO3_FILEID1_ENTRY entries (4 bytes) + // 3) Array of DIABLO3_FILEID1_ENTRY entries + // 4) Number of DIABLO3_FILEID2_ENTRY entries (4 bytes) + // 5) Array of DIABLO3_FILEID2_ENTRY entries + // 6) Number of DIABLO3_NAMED_ENTRY entries (4 bytes) + // 7) Array of DIABLO3_NAMED_ENTRY entries + // + + // Prepare the header signature + memset(pDirHeader, 0, sizeof(DIABLO3_DIR_HEADER)); + + // Get the signature + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + dwSignature = *(PDWORD)pbDirFile; + + // Check the signature + if(dwSignature != CASC_DIABLO3_ROOT_SIGNATURE && dwSignature != DIABLO3_SUBDIR_SIGNATURE) + return ERROR_BAD_FORMAT; + pbDirFile += sizeof(DWORD); + + // Subdirectories have extra two arrays + if(dwSignature == DIABLO3_SUBDIR_SIGNATURE) + { + // Get the number of DIABLO3_FILEID1_ENTRY items + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries1 = *(PDWORD)pbDirFile; + + // Get the array of DIABLO3_FILEID1_ENTRY + pDirHeader->pbEntries1 = (pbDirFile + sizeof(DWORD)); + pbDirFile = pbDirFile + sizeof(DWORD) + pDirHeader->dwEntries1 * sizeof(DIABLO3_FILEID1_ENTRY); + + // Get the number of DIABLO3_FILEID2_ENTRY items + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries2 = *(PDWORD)pbDirFile; + + // Get the array of DIABLO3_FILEID2_ENTRY + pDirHeader->pbEntries2 = (pbDirFile + sizeof(DWORD)); + pbDirFile = pbDirFile + sizeof(DWORD) + pDirHeader->dwEntries2 * sizeof(DIABLO3_FILEID2_ENTRY); + } + + // Get the pointer and length DIABLO3_NAMED_ENTRY array + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries3 = *(PDWORD)pbDirFile; + pDirHeader->pbEntries3 = (pbDirFile + sizeof(DWORD)); + return ERROR_SUCCESS; +} + +static DWORD ScanDirectoryFile( + TCascStorage * hs, + LPBYTE pbRootFile, + LPBYTE pbFileEnd) +{ + PDIABLO3_NAMED_ENTRY pNamedEntry; + DIABLO3_DIR_HEADER RootHeader; + DIABLO3_DIR_HEADER DirHeader; + LPBYTE pbSubDir; + DWORD dwTotalFileCount; + DWORD cbNamedEntry; + DWORD cbSubDir; + int nError; + + // Parse the directory header in order to retrieve the items + nError = ParseDirectoryHeader(&RootHeader, pbRootFile, pbFileEnd); + if(nError != ERROR_SUCCESS) + return 0; + + // Add the root directory's entries + dwTotalFileCount = RootHeader.dwEntries1 + RootHeader.dwEntries2 + RootHeader.dwEntries3; + + // Parse the named entries + for(DWORD i = 0; i < RootHeader.dwEntries3; i++) + { + // Get the this named entry + if((cbNamedEntry = VerifyNamedFileEntry(RootHeader.pbEntries3, pbFileEnd)) == 0) + return 0; + pNamedEntry = (PDIABLO3_NAMED_ENTRY)RootHeader.pbEntries3; + RootHeader.pbEntries3 += cbNamedEntry; + + // Load the subdirectory to memory + pbSubDir = LoadFileToMemory(hs, pNamedEntry->EncodingKey.Value, &cbSubDir); + if(pbSubDir != NULL) + { + // Count the files in the subdirectory + if(ParseDirectoryHeader(&DirHeader, pbSubDir, pbSubDir + cbSubDir) == ERROR_SUCCESS) + { + dwTotalFileCount += DirHeader.dwEntries1 + DirHeader.dwEntries2 + DirHeader.dwEntries3; + } + + // Free the subdirectory + CASC_FREE(pbSubDir); + } + } + + // Return the total number of entries + return dwTotalFileCount; +} + +static int ParseDirectoryFile( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbDirFile, + LPBYTE pbFileEnd, + DWORD dwRootDirIndex) +{ + DIABLO3_DIR_HEADER DirHeader; + int nError; + + // Sanity checks + assert(pRootHandler->FileTable.ItemArray != NULL); + assert(pRootHandler->FileTable.ItemCount < pRootHandler->FileTable.ItemCountMax); + + // Parse the directory header in order to retrieve the items + nError = ParseDirectoryHeader(&DirHeader, pbDirFile, pbFileEnd); + if(nError != ERROR_SUCCESS) + return nError; + + // Process all DIABLO3_FILEID1_ENTRY entries. These are for files + // belonging to an asset group, without subitem number. + // Example: "SoundBank\SoundFile.smp" + // We skip inserting them to the name map, because the names are not known yet + if(DirHeader.pbEntries1 && DirHeader.dwEntries1) + { + assert(dwRootDirIndex != DIABLO3_INVALID_INDEX); + nError = ParseDirEntries_FileId1(pRootHandler, DirHeader.pbEntries1, DirHeader.dwEntries1, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Parse all DIABLO3_FILEID2_ENTRY entries. These are for files + // belonging to an asset group, with a subitem number. + // Example: "SoundBank\SoundFile\0001.smp" + // We skip inserting them to the name map, because the names are not known yet + if(DirHeader.pbEntries2 && DirHeader.dwEntries2) + { + assert(dwRootDirIndex != DIABLO3_INVALID_INDEX); + nError = ParseDirEntries_FileId2(pRootHandler, DirHeader.pbEntries2, DirHeader.dwEntries2, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + + // Parse all named entries. These are for files with arbitrary names, + // and they do not belong to an asset. + if(DirHeader.pbEntries3 && DirHeader.dwEntries3) + { + nError = ParseDirEntries_Named(pRootHandler, DirHeader.pbEntries3, pbFileEnd, DirHeader.dwEntries3, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Give the directory to the caller + return nError; +} + +static int ParseCoreTOC( + TRootHandler_Diablo3 * pRootHandler, + PCASC_MAP pPackageMap, + LPBYTE pbCoreTocFile, + LPBYTE pbCoreTocEnd) +{ + PDIABLO3_CORE_TOC_HEADER pTocHeader; + PDIABLO3_CORE_TOC_ENTRY pSortedEntries; + PDIABLO3_CORE_TOC_ENTRY pTocEntry; + LPBYTE pbCoreTocNames; + DWORD dwFileIndexes = 0; + DWORD i; + + // Check the space for header + if((pbCoreTocFile + sizeof(DIABLO3_CORE_TOC_HEADER)) > pbCoreTocEnd) + return ERROR_FILE_CORRUPT; + pTocHeader = (PDIABLO3_CORE_TOC_HEADER)pbCoreTocFile; + pbCoreTocFile += sizeof(DIABLO3_CORE_TOC_HEADER); + + // Calculate space needed for allocation + for(i = 0; i < DIABLO3_MAX_ASSETS; i++) + { + // Get the first entry + pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbCoreTocFile + pTocHeader->EntryOffsets[i]); + + // Find out the entry with the maximum index + for(DWORD n = 0; n < pTocHeader->EntryCounts[i]; n++) + { + if(pTocEntry->FileIndex > dwFileIndexes) + dwFileIndexes = pTocEntry->FileIndex + 1; + pTocEntry++; + } + } + + // Allocate and populate the array of DIABLO3_CORE_TOC_ENTRYs + pSortedEntries = CASC_ALLOC(DIABLO3_CORE_TOC_ENTRY, dwFileIndexes); + if(pSortedEntries != NULL) + { + // Initialize all entries to invalid + memset(pSortedEntries, 0xFF, dwFileIndexes * sizeof(DIABLO3_CORE_TOC_ENTRY)); + + // Populate the linear array with the entries + for(i = 0; i < DIABLO3_MAX_ASSETS; i++) + { + // Set the pointers + pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbCoreTocFile + pTocHeader->EntryOffsets[i]); + pbCoreTocNames = (LPBYTE)(pTocEntry + pTocHeader->EntryCounts[i]); + + // Setup the entries + for(DWORD n = 0; n < pTocHeader->EntryCounts[i]; n++) + { + pSortedEntries[pTocEntry->FileIndex].AssetIndex = pTocEntry->AssetIndex; + pSortedEntries[pTocEntry->FileIndex].FileIndex = pTocEntry->FileIndex; + pSortedEntries[pTocEntry->FileIndex].NameOffset = (DWORD)(pbCoreTocNames - pbCoreTocFile) + pTocEntry->NameOffset; + pTocEntry++; + } + } + + // Now use the linear array to resolve the asset indexes and plain names + ResolveFullFileNames(pRootHandler, pSortedEntries, pPackageMap, pbCoreTocFile, dwFileIndexes); + CASC_FREE(pSortedEntries); + } + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of Diablo III root file + +static int D3Handler_Insert(TRootHandler_Diablo3 * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey) +{ + ENCODING_KEY EncodingKey; + DWORD dwFileIndex; + + // Don't let the number of items to overflow + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_NOT_ENOUGH_MEMORY; + + // Insert the item + EncodingKey = *(PENCODING_KEY)pbEncodingKey; + dwFileIndex = InsertFileEntry(pRootHandler, + EncodingKey, + szFileName, + strlen(szFileName) + 1); + return (dwFileIndex != INVALID_FILE_INDEX) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; +} + +static LPBYTE D3Handler_Search(TRootHandler_Diablo3 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */) +{ + PCASC_FILE_ENTRY pFileEntry; + const char * szSrcName = NULL; + + // Are we still inside the root directory range? + while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount) + { + // Get the n-th directory and the file name + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1); + szSrcName = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName); + + // This is either a full file name or an abbreviated name + if(pFileEntry->dwFlags & CASC_ENTRY_SHORT_NAME) + { + CreateFileName(pRootHandler, szSrcName, pSearch->szFileName); + } + else + { + strcpy(pSearch->szFileName, szSrcName); + } + + // Prepare for the next search + pSearch->IndexLevel1++; + return pFileEntry->EncodingKey.Value; + } + + // No more entries + return NULL; +} + +static void D3Handler_EndSearch(TRootHandler_Diablo3 * /* pRootHandler */, TCascSearch * /* pSearch */) +{ + // Do nothing +} + +static LPBYTE D3Handler_GetKey(TRootHandler_Diablo3 * pRootHandler, const char * szFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + // Find the file in the name table + pFileEntry = (PCASC_FILE_ENTRY)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL); + return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL; +} + +static void D3Handler_Close(TRootHandler_Diablo3 * pRootHandler) +{ + if(pRootHandler != NULL) + { + // Free the file map + Map_Free(pRootHandler->pRootMap); + + // Free the array of the file entries and file names + Array_Free(&pRootHandler->FileTable); + Array_Free(&pRootHandler->FileNames); + + // Free the root file itself + CASC_FREE(pRootHandler); + } +} + +/* +static void DumpRootFile(TDumpContext * dc, LPBYTE pbFileData, LPBYTE pbFileDataEnd) +{ + char szMD5Buffer[MD5_STRING_SIZE+1]; + DWORD dwSignature; + DWORD dwItemCount; + DWORD i; + + dwSignature = *(PDWORD)pbFileData; + if(dwSignature != CASC_DIABLO3_SUBDIR_SIGNATURE) + return; + pbFileData += sizeof(DWORD); + + // Dump items that contain EncodingKey + AssetId + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PCASC_DIABLO3_ASSET_ENTRY pEntry = (PCASC_DIABLO3_ASSET_ENTRY)pbFileData; + + if((pbFileData + sizeof(*pEntry)) > pbFileDataEnd) + return; + pbFileData += sizeof(*pEntry); + + dump_print(dc, "%s %08X\n", StringFromMD5(pEntry->EncodingKey, szMD5Buffer), pEntry->AssetId); + } + + // Terminate with two newlines + dump_print(dc, "\n"); + + // Dump items that contain EncodingKey + AssetId + FileNumber + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PCASC_DIABLO3_ASSET_ENTRY2 pEntry = (PCASC_DIABLO3_ASSET_ENTRY2)pbFileData; + + if((pbFileData + sizeof(*pEntry)) > pbFileDataEnd) + return; + pbFileData += sizeof(*pEntry); + + dump_print(dc, "%s %08X %08X\n", StringFromMD5((LPBYTE)pEntry->EncodingKey, szMD5Buffer), pEntry->AssetId, pEntry->FileNumber); + } + + // Terminate with two newlines + dump_print(dc, "\n"); + + // Dump items that contain EncodingKey + FileName + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PDIABLO3_NAMED_ENTRY pEntry = (PDIABLO3_NAMED_ENTRY)pbFileData; + DWORD dwEntrySize = VerifyNamedFileEntry(pbFileData, pbFileDataEnd); + + if((pbFileData + dwEntrySize) > pbFileDataEnd) + return; + pbFileData += dwEntrySize; + + dump_print(dc, "%s %s\n", StringFromMD5((LPBYTE)pEntry->EncodingKey, szMD5Buffer), pEntry->szFileName); + } + + dump_print(dc, "\n\n"); +} +*/ +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + TRootHandler_Diablo3 * pRootHandler; + PCASC_MAP pPackageMap = NULL; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + LPBYTE pbPackagesDat = NULL; + DWORD dwTotalFileCount; + DWORD cbPackagesDat = 0; + int nError; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_Diablo3, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_Diablo3)); + pRootHandler->Insert = (ROOT_INSERT)D3Handler_Insert; + pRootHandler->Search = (ROOT_SEARCH)D3Handler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)D3Handler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)D3Handler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)D3Handler_Close; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + + // Scan the total number of files in the root directories + // Reserve space for extra files + dwTotalFileCount = ScanDirectoryFile(hs, pbRootFile, pbRootFileEnd); + if(dwTotalFileCount == 0) + return ERROR_FILE_CORRUPT; + dwTotalFileCount += CASC_EXTRA_FILES; + + // Allocate the global linear file table + // Note: This is about 18 MB of memory for Diablo III PTR build 30013 + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, dwTotalFileCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Allocate global buffer for file names. + // The size of the buffer was taken from Diablo III build 30013 + nError = Array_Create(&pRootHandler->FileNames, char, 0x01000000); + if(nError != ERROR_SUCCESS) + return nError; + + // Create map of ROOT_ENTRY -> FileEntry + pRootHandler->pRootMap = Map_Create(dwTotalFileCount, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the ROOT file and insert all entries in the file table + nError = ParseDirectoryFile(pRootHandler, pbRootFile, pbRootFileEnd, DIABLO3_INVALID_INDEX); + if(nError == ERROR_SUCCESS) + { + size_t dwRootEntries = pRootHandler->FileTable.ItemCount; + + // We expect the number of level-0 to be less than maximum + assert(dwRootEntries < DIABLO3_MAX_SUBDIRS); + + // Now parse the all root items and load them + for(size_t i = 0; i < dwRootEntries; i++) + { + PCASC_FILE_ENTRY pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, i); + + // Load the entire file to memory + pbRootFile = LoadFileToMemory(hs, pRootEntry->EncodingKey.Value, &cbRootFile); + if(pbRootFile != NULL) + { + nError = ParseDirectoryFile(pRootHandler, pbRootFile, pbRootFile + cbRootFile, i); + CASC_FREE(pbRootFile); + } + } + } + + // Note: The file "Base\Data_D3\PC\Misc\Packages.dat" contains the names + // of the files (without level-0 and level-1 directory). We can use these + // names for supplying the missing extensions + if(nError == ERROR_SUCCESS) + { + // Load the entire file to memory + pbPackagesDat = LoadFileToMemory(hs, "Base\\Data_D3\\PC\\Misc\\Packages.dat", &cbPackagesDat); + if(pbPackagesDat != NULL) + { + pPackageMap = CreatePackageMap(pbPackagesDat, pbPackagesDat + cbPackagesDat); + } + } + + // Vast majorify of files at this moment don't have names. + // We can load the Base\CoreTOC.dat file in order + // to get directory asset indexes, file names and extensions + if(nError == ERROR_SUCCESS) + { + LPBYTE pbCoreTOC; + DWORD cbCoreTOC = 0; + + // Load the entire file to memory + pbCoreTOC = LoadFileToMemory(hs, "Base\\CoreTOC.dat", &cbCoreTOC); + if(pbCoreTOC != NULL) + { + ParseCoreTOC(pRootHandler, pPackageMap, pbCoreTOC, pbCoreTOC + cbCoreTOC); + CASC_FREE(pbCoreTOC); + } + } + + // Free the packages map + if(pPackageMap != NULL) + Map_Free(pPackageMap); + if(pbPackagesDat != NULL) + CASC_FREE(pbPackagesDat); + return nError; +} diff --git a/dep/CascLib/src/CascMndxRoot.cpp b/dep/CascLib/src/CascRootFile_Mndx.cpp similarity index 91% rename from dep/CascLib/src/CascMndxRoot.cpp rename to dep/CascLib/src/CascRootFile_Mndx.cpp index 328afee8ba5..bf17290a0af 100644 --- a/dep/CascLib/src/CascMndxRoot.cpp +++ b/dep/CascLib/src/CascRootFile_Mndx.cpp @@ -12,20 +12,20 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" +#include "CascMndx.h" //----------------------------------------------------------------------------- // Local defines -#define CASC_MAR_SIGNATURE 0x0052414d // 'MAR\0' +#define CASC_MAR_SIGNATURE 0x0052414d // 'MAR\0' //----------------------------------------------------------------------------- // Local structures typedef struct _FILE_MNDX_HEADER { - DWORD Signature; // 'MNDX' - DWORD HeaderVersion; // Must be <= 2 + DWORD Signature; // 'MNDX' + DWORD HeaderVersion; // Must be <= 2 DWORD FormatVersion; } FILE_MNDX_HEADER, *PFILE_MNDX_HEADER; @@ -39,6 +39,57 @@ typedef struct _FILE_MAR_INFO DWORD MarDataOffsetHi; } FILE_MAR_INFO, *PFILE_MAR_INFO; +typedef struct _CASC_MNDX_INFO +{ + BYTE RootFileName[MD5_HASH_SIZE]; // Name (aka MD5) of the root file + DWORD HeaderVersion; // Must be <= 2 + DWORD FormatVersion; + DWORD field_1C; + DWORD field_20; + DWORD MarInfoOffset; // Offset of the first MAR entry info + DWORD MarInfoCount; // Number of the MAR info entries + DWORD MarInfoSize; // Size of the MAR info entry + DWORD MndxEntriesOffset; + DWORD MndxEntriesTotal; // Total number of MNDX root entries + DWORD MndxEntriesValid; // Number of valid MNDX root entries + DWORD MndxEntrySize; // Size of one MNDX root entry + struct _MAR_FILE * pMarFile1; // File name list for the packages + struct _MAR_FILE * pMarFile2; // File name list for names stripped of package names + struct _MAR_FILE * pMarFile3; // File name list for complete names +// PCASC_ROOT_ENTRY_MNDX pMndxEntries; +// PCASC_ROOT_ENTRY_MNDX * ppValidEntries; + bool bRootFileLoaded; // true if the root info file was properly loaded + +} CASC_MNDX_INFO, *PCASC_MNDX_INFO; + +typedef struct _CASC_MNDX_PACKAGE +{ + char * szFileName; // Pointer to file name + size_t nLength; // Length of the file name + +} CASC_MNDX_PACKAGE, *PCASC_MNDX_PACKAGE; + +typedef struct _CASC_MNDX_PACKAGES +{ + char * szNameBuffer; // Pointer to the buffer for file names + size_t NameEntries; // Number of name entries in Names + size_t NameBufferUsed; // Number of bytes used in the name buffer + size_t NameBufferMax; // Total size of the name buffer + + CASC_MNDX_PACKAGE Packages[1]; // List of packages + +} CASC_MNDX_PACKAGES, *PCASC_MNDX_PACKAGES; + +// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) +// Corresponds to the in-file structure +typedef struct _CASC_ROOT_ENTRY_MNDX +{ + DWORD Flags; // High 8 bits: Flags, low 24 bits: package index + BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file + DWORD FileSize; // Uncompressed file size, in bytes + +} CASC_ROOT_ENTRY_MNDX, *PCASC_ROOT_ENTRY_MNDX; + //----------------------------------------------------------------------------- // Testing functions prototypes @@ -2734,14 +2785,14 @@ static void MAR_FILE_Destructor(PMAR_FILE pMarFile) #define CASC_PACKAGES_INIT 0x10 #define CASC_PACKAGES_DELTA 0x10 -static PCASC_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMax) +static PCASC_MNDX_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMax) { - PCASC_PACKAGES pPackages; + PCASC_MNDX_PACKAGES pPackages; size_t cbToAllocate; // Allocate space - cbToAllocate = sizeof(CASC_PACKAGES) + (nNameEntries * sizeof(CASC_PACKAGE)) + nNameBufferMax; - pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); + cbToAllocate = sizeof(CASC_MNDX_PACKAGES) + (nNameEntries * sizeof(CASC_MNDX_PACKAGE)) + nNameBufferMax; + pPackages = (PCASC_MNDX_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); if(pPackages != NULL) { // Fill the structure @@ -2757,8 +2808,8 @@ static PCASC_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMa return pPackages; } -static PCASC_PACKAGES InsertToPackageList( - PCASC_PACKAGES pPackages, +static PCASC_MNDX_PACKAGES InsertToPackageList( + PCASC_MNDX_PACKAGES pPackages, const char * szFileName, size_t cchFileName, size_t nPackageIndex) @@ -2777,11 +2828,11 @@ static PCASC_PACKAGES InsertToPackageList( // If any of the two variables overflowed, we need to reallocate the name list if(nNewNameEntries > pPackages->NameEntries || nNewNameBufferMax > pPackages->NameBufferMax) { - PCASC_PACKAGES pOldPackages = pPackages; + PCASC_MNDX_PACKAGES pOldPackages = pPackages; // Allocate new name list - cbToAllocate = sizeof(CASC_PACKAGES) + (nNewNameEntries * sizeof(CASC_PACKAGE)) + nNewNameBufferMax; - pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); + cbToAllocate = sizeof(CASC_MNDX_PACKAGES) + (nNewNameEntries * sizeof(CASC_MNDX_PACKAGE)) + nNewNameBufferMax; + pPackages = (PCASC_MNDX_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); if(pPackages == NULL) return NULL; @@ -2822,17 +2873,17 @@ static PCASC_PACKAGES InsertToPackageList( return pPackages; } -static int LoadPackageNames(TCascStorage * hs) +static int LoadPackageNames(PCASC_MNDX_INFO pMndxInfo, PCASC_MNDX_PACKAGES * ppPackages) { TMndxFindResult Struct1C; - PCASC_PACKAGES pPackages = NULL; + PCASC_MNDX_PACKAGES pPackages = NULL; PMAR_FILE pMarFile; // Sanity checks - assert(hs->pMndxInfo != NULL); + assert(pMndxInfo != NULL); // Prepare the file name search in the top level directory - pMarFile = hs->pMndxInfo->pMarFile1; + pMarFile = pMndxInfo->pMarFile1; Struct1C.SetSearchPath("", 0); // Allocate initial name list structure @@ -2856,21 +2907,34 @@ static int LoadPackageNames(TCascStorage * hs) return ERROR_NOT_ENOUGH_MEMORY; } - // Set the name list to the CASC storage structure - hs->pPackages = pPackages; + // Give the packages to the caller + if(ppPackages != NULL) + ppPackages[0] = pPackages; return ERROR_SUCCESS; } -PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName) +//----------------------------------------------------------------------------- +// Implementation of root file functions + +struct TRootHandler_MNDX : public TRootHandler { - PCASC_PACKAGE pMatching = NULL; - PCASC_PACKAGE pPackage; + CASC_MNDX_INFO MndxInfo; + + PCASC_ROOT_ENTRY_MNDX * ppValidEntries; + PCASC_ROOT_ENTRY_MNDX pMndxEntries; + PCASC_MNDX_PACKAGES pPackages; // Linear list of present packages +}; + +PCASC_MNDX_PACKAGE FindMndxPackage(TRootHandler_MNDX * pRootHandler, const char * szFileName) +{ + PCASC_MNDX_PACKAGE pMatching = NULL; + PCASC_MNDX_PACKAGE pPackage; size_t nMaxLength = 0; size_t nLength = strlen(szFileName); // Packages must be loaded - assert(hs->pPackages != NULL); - pPackage = hs->pPackages->Packages; + assert(pRootHandler->pPackages != NULL); + pPackage = pRootHandler->pPackages->Packages; //FILE * fp = fopen("E:\\packages.txt", "wt"); //for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++) @@ -2881,7 +2945,7 @@ PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName) //fclose(fp); // Find the longest matching name - for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++) + for(size_t i = 0; i < pRootHandler->pPackages->NameEntries; i++, pPackage++) { if(pPackage->szFileName != NULL && pPackage->nLength < nLength && pPackage->nLength > nMaxLength) { @@ -2898,11 +2962,49 @@ PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName) return pMatching; } -static bool FillFindData(TCascSearch * pSearch, PCASC_FIND_DATA pFindData, TMndxFindResult * pStruct1C) +int SearchMndxInfo(TRootHandler_MNDX * pRootHandler, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppRootEntry) +{ + PCASC_ROOT_ENTRY_MNDX pRootEntry; + PCASC_MNDX_INFO pMndxInfo = &pRootHandler->MndxInfo; + TMndxFindResult Struct1C; + + // Search the database for the file name + if(pMndxInfo->bRootFileLoaded) + { + Struct1C.SetSearchPath(szFileName, strlen(szFileName)); + + // Search the file name in the second MAR info (the one with stripped package names) + if(MAR_FILE_SearchFile(pMndxInfo->pMarFile2, &Struct1C) != ERROR_SUCCESS) + return ERROR_FILE_NOT_FOUND; + + // The found MNDX index must fall into range of valid MNDX entries + if(Struct1C.FileNameIndex < pMndxInfo->MndxEntriesValid) + { + // HOTS: E945F4 + pRootEntry = pRootHandler->ppValidEntries[Struct1C.FileNameIndex]; + while((pRootEntry->Flags & 0x00FFFFFF) != dwPackage) + { + // The highest bit serves as a terminator if set + if(pRootEntry->Flags & 0x80000000) + return ERROR_FILE_NOT_FOUND; + + pRootEntry++; + } + + // Give the root entry pointer to the caller + if(ppRootEntry != NULL) + ppRootEntry[0] = pRootEntry; + return ERROR_SUCCESS; + } + } + + return ERROR_FILE_NOT_FOUND; +} + +static LPBYTE FillFindData(TRootHandler_MNDX * pRootHandler, TCascSearch * pSearch, TMndxFindResult * pStruct1C, PDWORD PtrFileSize) { PCASC_ROOT_ENTRY_MNDX pRootEntry = NULL; - TCascStorage * hs = pSearch->hs; - PCASC_PACKAGE pPackage; + PCASC_MNDX_PACKAGE pPackage; char * szStrippedPtr; char szStrippedName[MAX_PATH+1]; int nError; @@ -2911,40 +3013,134 @@ static bool FillFindData(TCascSearch * pSearch, PCASC_FIND_DATA pFindData, TMndx assert(pStruct1C->cchFoundPath < MAX_PATH); // Fill the file name - memcpy(pFindData->szFileName, pStruct1C->szFoundPath, pStruct1C->cchFoundPath); - pFindData->szFileName[pStruct1C->cchFoundPath] = 0; - pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); - pFindData->dwFileSize = CASC_INVALID_SIZE; + memcpy(pSearch->szFileName, pStruct1C->szFoundPath, pStruct1C->cchFoundPath); + pSearch->szFileName[pStruct1C->cchFoundPath] = 0; // Fill the file size - pPackage = FindMndxPackage(hs, pFindData->szFileName); - if(pPackage != NULL) + pPackage = FindMndxPackage(pRootHandler, pSearch->szFileName); + if(pPackage == NULL) + return NULL; + + // Cut the package name off the full path + szStrippedPtr = pSearch->szFileName + pPackage->nLength; + while(szStrippedPtr[0] == '/') + szStrippedPtr++; + + // We need to convert the stripped name to lowercase, replacing backslashes with slashes + NormalizeFileName_LowerSlash(szStrippedName, szStrippedPtr, MAX_PATH); + + // Search the package + nError = SearchMndxInfo(pRootHandler, szStrippedName, (DWORD)(pPackage - pRootHandler->pPackages->Packages), &pRootEntry); + if(nError != ERROR_SUCCESS) + return NULL; + + // Give the file size + if(PtrFileSize != NULL) + PtrFileSize[0] = pRootEntry->FileSize; + return pRootEntry->EncodingKey; +} + +static int MndxHandler_Insert(TRootHandler_MNDX *, const char *, LPBYTE) +{ + return ERROR_NOT_SUPPORTED; +} + +static LPBYTE MndxHandler_Search(TRootHandler_MNDX * pRootHandler, TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD /* PtrLocaleFlags */) +{ + TMndxFindResult * pStruct1C = NULL; + PCASC_MNDX_INFO pMndxInfo = &pRootHandler->MndxInfo; + PMAR_FILE pMarFile = pMndxInfo->pMarFile3; + bool bFindResult = false; + + // If the first time, allocate the structure for the search result + if(pSearch->pRootContext == NULL) { - // Cut the package name off the full path - szStrippedPtr = pFindData->szFileName + pPackage->nLength; - while(szStrippedPtr[0] == '/') - szStrippedPtr++; + // Create the new search structure + pStruct1C = new TMndxFindResult; + if(pStruct1C == NULL) + return NULL; - // We need to convert the stripped name to lowercase, replacing backslashes with slashes - NormalizeFileName_LowerSlash(szStrippedName, szStrippedPtr, MAX_PATH); - - // Search the package - nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &pRootEntry); - if(nError == ERROR_SUCCESS) - { - pFindData->dwFileSize = pRootEntry->FileSize; - } + // Setup the search mask + pStruct1C->SetSearchPath("", 0); + pSearch->pRootContext = pStruct1C; } - return true; + + // Make shortcut for the search structure + assert(pSearch->pRootContext != NULL); + pStruct1C = (TMndxFindResult *)pSearch->pRootContext; + + // Search the next file name (our code) + pMarFile->pDatabasePtr->sub_1956CE0(pStruct1C, &bFindResult); + if(bFindResult == false) + return NULL; + + // Give the file size and encoding key + return FillFindData(pRootHandler, pSearch, pStruct1C, PtrFileSize); +} + +static void MndxHandler_EndSearch(TRootHandler_MNDX * /* pRootHandler */, TCascSearch * pSearch) +{ + if(pSearch != NULL) + delete (TMndxFindResult *)pSearch->pRootContext; + pSearch->pRootContext = NULL; +} + +static LPBYTE MndxHandler_GetKey(TRootHandler_MNDX * pRootHandler, const char * szFileName) +{ + PCASC_ROOT_ENTRY_MNDX pRootEntry = NULL; + PCASC_MNDX_PACKAGE pPackage; + char * szStrippedName; + char szNormName[MAX_PATH+1]; + int nError; + + // Convert the file name to lowercase + slashes + NormalizeFileName_LowerSlash(szNormName, szFileName, MAX_PATH); + + // Find the package number + pPackage = FindMndxPackage(pRootHandler, szNormName); + if(pPackage == NULL) + return NULL; + + // Cut the package name off the full path + szStrippedName = szNormName + pPackage->nLength; + while(szStrippedName[0] == '/') + szStrippedName++; + + // Find the root entry + nError = SearchMndxInfo(pRootHandler, szStrippedName, (DWORD)(pPackage - pRootHandler->pPackages->Packages), &pRootEntry); + if(nError != ERROR_SUCCESS || pRootEntry == NULL) + return NULL; + + // Return the encoding key + return pRootEntry->EncodingKey; +} + +static void MndxHandler_Close(TRootHandler_MNDX * pRootHandler) +{ + if(pRootHandler->MndxInfo.pMarFile1 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile1); + if(pRootHandler->MndxInfo.pMarFile2 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile2); + if(pRootHandler->MndxInfo.pMarFile3 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile3); + if(pRootHandler->ppValidEntries != NULL) + CASC_FREE(pRootHandler->ppValidEntries); + if(pRootHandler->pMndxEntries != NULL) + CASC_FREE(pRootHandler->pMndxEntries); + if(pRootHandler->pPackages != NULL) + CASC_FREE(pRootHandler->pPackages); + + CASC_FREE(pRootHandler); } //----------------------------------------------------------------------------- // Public functions - MNDX info -int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) { PFILE_MNDX_HEADER pMndxHeader = (PFILE_MNDX_HEADER)pbRootFile; PCASC_MNDX_INFO pMndxInfo; + TRootHandler_MNDX * pRootHandler; FILE_MAR_INFO MarInfo; PMAR_FILE pMarFile; LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; @@ -2957,13 +3153,24 @@ int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) if(pMndxHeader->Signature != CASC_MNDX_SIGNATURE || pMndxHeader->FormatVersion > 2 || pMndxHeader->FormatVersion < 1) return ERROR_BAD_FORMAT; - // Allocate space for the CASC_MNDX_INFO structure - pMndxInfo = CASC_ALLOC(CASC_MNDX_INFO, 1); - if(pMndxInfo == NULL) + // Allocate the structure for the MNDX root file + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_MNDX, 1); + if(pRootHandler == NULL) return ERROR_NOT_ENOUGH_MEMORY; + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_MNDX)); + pRootHandler->Insert = (ROOT_INSERT)MndxHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)MndxHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)MndxHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)MndxHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE) MndxHandler_Close; + pMndxInfo = &pRootHandler->MndxInfo; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + // Copy the header into the MNDX info - memset(pMndxInfo, 0, sizeof(CASC_MNDX_INFO)); pMndxInfo->HeaderVersion = pMndxHeader->HeaderVersion; pMndxInfo->FormatVersion = pMndxHeader->FormatVersion; dwFilePointer += sizeof(FILE_MNDX_HEADER); @@ -3047,10 +3254,10 @@ int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) if(nError == ERROR_SUCCESS && FileNameCount == pMndxInfo->MndxEntriesValid) { cbToAllocate = pMndxInfo->MndxEntriesTotal * pMndxInfo->MndxEntrySize; - pMndxInfo->pMndxEntries = (PCASC_ROOT_ENTRY_MNDX)CASC_ALLOC(BYTE, cbToAllocate); - if(pMndxInfo->pMndxEntries != NULL) + pRootHandler->pMndxEntries = (PCASC_ROOT_ENTRY_MNDX)CASC_ALLOC(BYTE, cbToAllocate); + if(pRootHandler->pMndxEntries != NULL) { - if(!RootFileRead(pbRootFile + pMndxInfo->MndxEntriesOffset, pbRootFileEnd, pMndxInfo->pMndxEntries, cbToAllocate)) + if(!RootFileRead(pbRootFile + pMndxInfo->MndxEntriesOffset, pbRootFileEnd, pRootHandler->pMndxEntries, cbToAllocate)) nError = ERROR_FILE_CORRUPT; } else @@ -3064,15 +3271,15 @@ int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) if(nError == ERROR_SUCCESS) { assert(pMndxInfo->MndxEntriesValid <= pMndxInfo->MndxEntriesTotal); - pMndxInfo->ppValidEntries = CASC_ALLOC(PCASC_ROOT_ENTRY_MNDX, pMndxInfo->MndxEntriesValid + 1); - if(pMndxInfo->ppValidEntries != NULL) + pRootHandler->ppValidEntries = CASC_ALLOC(PCASC_ROOT_ENTRY_MNDX, pMndxInfo->MndxEntriesValid + 1); + if(pRootHandler->ppValidEntries != NULL) { - PCASC_ROOT_ENTRY_MNDX pRootEntry = pMndxInfo->pMndxEntries; + PCASC_ROOT_ENTRY_MNDX pRootEntry = pRootHandler->pMndxEntries; DWORD ValidEntryCount = 1; // edx DWORD nIndex1 = 0; // The first entry is always valid - pMndxInfo->ppValidEntries[nIndex1++] = pMndxInfo->pMndxEntries; + pRootHandler->ppValidEntries[nIndex1++] = pRootHandler->pMndxEntries; // Put the remaining entries for(i = 0; i < pMndxInfo->MndxEntriesTotal; i++, pRootEntry++) @@ -3082,7 +3289,7 @@ int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) if(pRootEntry->Flags & 0x80000000) { - pMndxInfo->ppValidEntries[nIndex1++] = pRootEntry + 1; + pRootHandler->ppValidEntries[nIndex1++] = pRootEntry + 1; ValidEntryCount++; } } @@ -3090,131 +3297,28 @@ int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) // Verify the final number of valid entries if((ValidEntryCount - 1) != pMndxInfo->MndxEntriesValid) nError = ERROR_BAD_FORMAT; - - // Mark the MNDX info as fully loaded - pMndxInfo->bRootFileLoaded = true; } else nError = ERROR_NOT_ENOUGH_MEMORY; } - // Save the MNDX info to the archive storage + // Load the MNDX packages if(nError == ERROR_SUCCESS) { - // Store the MNDX database into the archive - hs->pMndxInfo = pMndxInfo; - pMndxInfo = NULL; + nError = LoadPackageNames(pMndxInfo, &pRootHandler->pPackages); + pMndxInfo->bRootFileLoaded = (nError == ERROR_SUCCESS); + } #if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) -// CascDumpNameFragTable("E:\\casc-name-fragment-table.txt", hs->pMndxInfo->pMarFile1); -// CascDumpFileNames("E:\\casc-listfile.txt", hs->pMndxInfo->pMarFile1); - TestMndxRootFile(hs->pMndxInfo); +// CascDumpNameFragTable("E:\\casc-name-fragment-table.txt", pMndxInfo->pMarFile1); +// CascDumpFileNames("E:\\casc-listfile.txt", pMndxInfo->pMarFile1); +// TestMndxRootFile(pRootHandler); #endif - // Load the top level entries - nError = LoadPackageNames(hs); - } - - // If anything failed, free the memory remaining allocated - if(nError != ERROR_SUCCESS) - { - if(pMndxInfo != NULL) - FreeMndxInfo(pMndxInfo); - pMndxInfo = NULL; - } + // Return the result return nError; } -int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppRootEntry) -{ - PCASC_ROOT_ENTRY_MNDX pRootEntry; - TMndxFindResult Struct1C; - - // Search the database for the file name - if(pMndxInfo->bRootFileLoaded) - { - Struct1C.SetSearchPath(szFileName, strlen(szFileName)); - - // Search the file name in the second MAR info (the one with stripped package names) - if(MAR_FILE_SearchFile(pMndxInfo->pMarFile2, &Struct1C) != ERROR_SUCCESS) - return ERROR_FILE_NOT_FOUND; - - // The found MNDX index must fall into range of valid MNDX entries - if(Struct1C.FileNameIndex < pMndxInfo->MndxEntriesValid) - { - // HOTS: E945F4 - pRootEntry = pMndxInfo->ppValidEntries[Struct1C.FileNameIndex]; - while((pRootEntry->Flags & 0x00FFFFFF) != dwPackage) - { - // The highest bit serves as a terminator if set - if(pRootEntry->Flags & 0x80000000) - return ERROR_FILE_NOT_FOUND; - - pRootEntry++; - } - - // Give the root entry pointer to the caller - if(ppRootEntry != NULL) - ppRootEntry[0] = pRootEntry; - return ERROR_SUCCESS; - } - } - - return ERROR_FILE_NOT_FOUND; -} - -bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) -{ - TMndxFindResult * pStruct1C = NULL; - PCASC_MNDX_INFO pMndxInfo = pSearch->hs->pMndxInfo; - PMAR_FILE pMarFile = pMndxInfo->pMarFile3; - bool bFindResult = false; - - // Sanity checks - assert(pMndxInfo != NULL); - - // If the first time, allocate the structure for the search result - if(pSearch->pStruct1C == NULL) - { - // Create the new search structure - pSearch->pStruct1C = pStruct1C = new TMndxFindResult; - if(pSearch->pStruct1C == NULL) - return false; - - // Setup the search mask - pStruct1C->SetSearchPath("", 0); - } - - // Make shortcut for the search structure - assert(pSearch->pStruct1C != NULL); - pStruct1C = (TMndxFindResult *)pSearch->pStruct1C; - - // Search the next file name (our code) - pMarFile->pDatabasePtr->sub_1956CE0(pStruct1C, &bFindResult); - if(bFindResult) - return FillFindData(pSearch, pFindData, pStruct1C); - - return false; -} - -void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo) -{ - if(pMndxInfo != NULL) - { - if(pMndxInfo->pMarFile1 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile1); - if(pMndxInfo->pMarFile2 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile2); - if(pMndxInfo->pMarFile3 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile3); - if(pMndxInfo->ppValidEntries != NULL) - CASC_FREE(pMndxInfo->ppValidEntries); - if(pMndxInfo->pMndxEntries != NULL) - CASC_FREE(pMndxInfo->pMndxEntries); - CASC_FREE(pMndxInfo); - } -} - //---------------------------------------------------------------------------- // Unit tests diff --git a/dep/CascLib/src/CascMndxRoot_x86.asm b/dep/CascLib/src/CascRootFile_Mndx_x86.asm similarity index 98% rename from dep/CascLib/src/CascMndxRoot_x86.asm rename to dep/CascLib/src/CascRootFile_Mndx_x86.asm index c0e787d0872..bf6d6d0b489 100644 --- a/dep/CascLib/src/CascMndxRoot_x86.asm +++ b/dep/CascLib/src/CascRootFile_Mndx_x86.asm @@ -6,9 +6,9 @@ ASSUME FS: NOTHING TMndxFindResult struc ; (sizeof=0x1C) ; XREF: GAME_OBJECT_03F7E848::sub_E94500_r szSearchMask dd ? ; XREF: TMndxFindResult__SetPath+2D_w - ; TMndxFindResult__Constructor+4_w ... + ; TMndxFindResult__Constructor+4_w cchSearchMask dd ? ; XREF: TMndxFindResult__SetPath:loc_1956E9A_w - ; TMndxFindResult__Constructor+6_w ... + ; TMndxFindResult__Constructor+6_w field_8 dd ? ; XREF: TMndxFindResult__Constructor+9_w szFoundPath dd ? ; XREF: TMndxFindResult__Constructor+C_w ; TFileNameDatabase__FindFileInDatabase+55_w @@ -17,7 +17,7 @@ cchFoundPath dd ? ; XREF: TMndxFindResult__Constructor+F_w FileNameIndex dd ? ; XREF: TMndxFindResult__Constructor+12_w ; TFileNameDatabase__FindFileInDatabase+6B_w pStruct40 dd ? ; XREF: MAR_FILE__FindFileInDatabase+19_r - ; TMndxFindResult__SetPath:loc_1956E8C_r ... + ; TMndxFindResult__SetPath:loc_1956E8C_r TMndxFindResult ends ; --------------------------------------------------------------------------- @@ -25,9 +25,9 @@ TMndxFindResult ends TRIPLET struc ; (sizeof=0xC) BitIndex dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+39_r NextKey dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+8C_r - ; TSparseArray__GetItemValue:loc_1959B8F_r ... + ; TSparseArray__GetItemValue:loc_1959B8F_r Distance dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+3E_r - ; TSparseArray__GetItemValue:loc_1959BBE_r ... + ; TSparseArray__GetItemValue:loc_1959BBE_r TRIPLET ends ; --------------------------------------------------------------------------- @@ -44,33 +44,33 @@ NAME_ENTRY ends TStruct14 struc ; (sizeof=0x14) ; XREF: TFileNameDatabase::sub_1959460r HashValue dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+44r - ; TGenericArray__InsertItem_STRUCT14+46w ... + ; TGenericArray__InsertItem_STRUCT14+46w field_4 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+48r - ; TGenericArray__InsertItem_STRUCT14+4Bw ... + ; TGenericArray__InsertItem_STRUCT14+4Bw field_8 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+4Er - ; TGenericArray__InsertItem_STRUCT14+51w ... + ; TGenericArray__InsertItem_STRUCT14+51w field_C dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+54r - ; TGenericArray__InsertItem_STRUCT14+57w ... + ; TGenericArray__InsertItem_STRUCT14+57w field_10 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+5Ar - ; TGenericArray__InsertItem_STRUCT14+5Dw ... + ; TGenericArray__InsertItem_STRUCT14+5Dw TStruct14 ends ; --------------------------------------------------------------------------- TGenericArray struc ; (sizeof=0x15) ; XREF: TGenericArray::LoadDwordsArrayWithCopyr - ; TFileNameDatabase::LoadBytesr ... + ; TFileNameDatabase::LoadBytesr DataBuffer dd ? ; XREF: TMndxFindResult__CreateStruct40+24w - ; TMndxFindResult__CreateStruct40+35w ... + ; TMndxFindResult__CreateStruct40+35w field_4 dd ? ; XREF: TMndxFindResult__CreateStruct40+26w - ; TMndxFindResult__CreateStruct40+38w ... + ; TMndxFindResult__CreateStruct40+38w ItemArray dd ? ; XREF: TMndxFindResult__CreateStruct40+29w - ; TMndxFindResult__CreateStruct40+3Bw ... + ; TMndxFindResult__CreateStruct40+3Bw ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+2Cw - ; TMndxFindResult__CreateStruct40+3Ew ... + ; TMndxFindResult__CreateStruct40+3Ew MaxItemCount dd ? ; XREF: TFileNameDatabasePtr__CreateDatabase+27o - ; TMndxFindResult__CreateStruct40+2Fw ... + ; TMndxFindResult__CreateStruct40+2Fw bIsValidArray db ? ; XREF: LoadAndVerifyIndexFileHeader+31w - ; TMndxFindResult__CreateStruct40+32w ... + ; TMndxFindResult__CreateStruct40+32w TGenericArray ends ; --------------------------------------------------------------------------- @@ -81,7 +81,7 @@ DataBuffer dd ? ; XREF: TArchiveDatabase__Destructor+64 ; TArchiveDatabase__Constructor+1A3w field_4 dd ? ; XREF: TArchiveDatabase__Constructor+1A9w ItemArray dd ? ; XREF: sub_1957350+31r - ; sub_19573D0+1Fr ... + ; sub_19573D0+1Fr ItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1B5w MaxItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1BBw bIsValidArray db ? ; XREF: TArchiveDatabase__Constructor+1C1w @@ -89,9 +89,9 @@ bIsValidArray db ? ; XREF: TArchiveDatabase__Constructor+1C db ? ; undefined db ? ; undefined BitsPerEntry dd ? ; XREF: sub_1957350+1Fr - ; sub_19573D0+6r ... + ; sub_19573D0+6r EntryBitMask dd ? ; XREF: sub_1957350:loc_19573B1r - ; sub_19573D0:loc_1957419r ... + ; sub_19573D0:loc_1957419r TotalEntries dd ? ; XREF: TGenericArrayEx__LoadFromStream:loc_195861Bw ; TArchiveDatabase__Constructor+1D3w TBitEntryArray ends @@ -100,50 +100,50 @@ TBitEntryArray ends TStruct40 struc ; (sizeof=0x40) array_00 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+24w - ; TMndxFindResult__CreateStruct40+26w ... + ; TMndxFindResult__CreateStruct40+26w db ? ; undefined db ? ; undefined db ? ; undefined array_18 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+35w - ; TMndxFindResult__CreateStruct40+38w ... + ; TMndxFindResult__CreateStruct40+38w db ? ; undefined db ? ; undefined db ? ; undefined HashValue dd ? ; XREF: TMndxFindResult__CreateStruct40+47w - ; TFileNameDatabase__CheckNextPathFragment+1Ar ... + ; TFileNameDatabase__CheckNextPathFragment+1Ar CharIndex dd ? ; XREF: TMndxFindResult__CreateStruct40+4Aw - ; TFileNameDatabase__CheckNextPathFragment+11r ... + ; TFileNameDatabase__CheckNextPathFragment+11r ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+4Dw - ; TStruct40__InitSearchBuffers+6Bw ... + ; TStruct40__InitSearchBuffers+6Bw SearchPhase dd ? ; XREF: TMndxFindResult__CreateStruct40+50w - ; TFileNameDatabase__FindFileInDatabase+17w ... + ; TFileNameDatabase__FindFileInDatabase+17w TStruct40 ends ; --------------------------------------------------------------------------- TSparseArray struc ; (sizeof=0x65) ; XREF: TSparseArray::LoadFromStream_Exchange_r - ; TNameIndexStruct_r ... + ; TNameIndexStruct_r ItemIsPresent TGenericArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w - ; TFileNameDatabase__Destructor+4C_r ... + ; TFileNameDatabase__Destructor+4C_r db ? ; undefined db ? ; undefined db ? ; undefined TotalItemCount dd ? ; XREF: TSparseArray__ExchangeWith+4D_r - ; TSparseArray__ExchangeWith+56_w ... + ; TSparseArray__ExchangeWith+56_w ValidItemCount dd ? ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r - ; TSparseArray__ExchangeWith+59_r ... + ; TSparseArray__ExchangeWith+59_r ArrayTriplets_20 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+40_r - ; TFileNameDatabase__Destructor+94_r ... + ; TFileNameDatabase__Destructor+94_r db ? ; undefined db ? ; undefined db ? ; undefined ArrayDwords_38 TGenericArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o - ; TFileNameDatabase__Destructor+34_r ... + ; TFileNameDatabase__Destructor+34_r db ? ; undefined db ? ; undefined db ? ; undefined ArrayDwords_50 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+28_r - ; TFileNameDatabase__Destructor+7C_r ... + ; TFileNameDatabase__Destructor+7C_r TSparseArray ends ; --------------------------------------------------------------------------- @@ -151,12 +151,12 @@ TSparseArray ends TNameIndexStruct struc ; (sizeof=0x7D) ; XREF: TNameIndexStruct::LoadFromStream_Exchange_r ; TFileNameDatabaser NameFragments TGenericArray <> ; XREF: TFileNameDatabase__Destructor+58_r - ; TFileNameDatabase__LoadFromStream+82_r ... + ; TFileNameDatabase__LoadFromStream+82_r db ? ; undefined db ? ; undefined db ? ; undefined Struct68 TSparseArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w - ; TFileNameDatabase__Destructor+28_r ... + ; TFileNameDatabase__Destructor+28_r TNameIndexStruct ends ; --------------------------------------------------------------------------- @@ -164,11 +164,11 @@ TNameIndexStruct ends TByteStream struc ; (sizeof=0x18) ; XREF: TFileNameDatabasePtr::CreateDatabase_r ; TFileNameDatabase_r pbData dd ? ; XREF: TByteStream__Constructor+4_w - ; TByteStream__IsMarDataValid+2_r ... + ; TByteStream__IsMarDataValid+2_r pvMappedFile dd ? ; XREF: TByteStream__Constructor+6_w ; TByteStream__Destructor+3_r cbData dd ? ; XREF: TByteStream__Constructor+9_w - ; TByteStream__GetBytes:loc_1959A05_r ... + ; TByteStream__GetBytes:loc_1959A05_r field_C dd ? ; XREF: TByteStream__Constructor+C_w hFile dd ? ; XREF: TByteStream__Constructor+F_w ; TByteStream__Destructor:loc_19599D2_r @@ -183,11 +183,11 @@ TStruct10 struc ; (sizeof=0x10) ; XREF: TStruct10::sub_1957800_r field_0 dd ? ; XREF: sub_19572E0+24_w ; TFileNameDatabase__Constructor+21A_w field_4 dd ? ; XREF: sub_1956FD0+28_w - ; sub_1956FD0:loc_1957001_w ... + ; sub_1956FD0:loc_1957001_w field_8 dd ? ; XREF: sub_19572E0+4A_w - ; sub_19572E0+5B_w ... + ; sub_19572E0+5B_w field_C dd ? ; XREF: sub_1957050:loc_1957074_w - ; sub_1957050:loc_1957081_w ... + ; sub_1957050:loc_1957081_w TStruct10 ends ; --------------------------------------------------------------------------- @@ -195,52 +195,52 @@ TStruct10 ends TFileNameDatabasePtr struc ; (sizeof=0x4) ; XREF: TFileNameDatabase_r ; MAR_FILE_r pDatabase dd ? ; XREF: MAR_FILE__Constructor+1D_w - ; MAR_FILE__CreateDatabase+22_w ... + ; MAR_FILE__CreateDatabase+22_w TFileNameDatabasePtr ends ; --------------------------------------------------------------------------- TFileNameDatabase struc ; (sizeof=0x240) ; XREF: TFileNameDatabase::LoadFromStream_Exchange_r Struct68_00 TSparseArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o - ; TFileNameDatabase__Destructor+D9_r ... + ; TFileNameDatabase__Destructor+D9_r db ? ; undefined db ? ; undefined db ? ; undefined FileNameIndexes TSparseArray <> ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r - ; TFileNameDatabase__Destructor+AC_r ... + ; TFileNameDatabase__Destructor+AC_r db ? ; undefined db ? ; undefined db ? ; undefined Struct68_D0 TSparseArray <> ; XREF: TFileNameDatabase__Destructor+7C_r - ; TFileNameDatabase__Destructor+88_r ... + ; TFileNameDatabase__Destructor+88_r db ? ; undefined db ? ; undefined db ? ; undefined FrgmDist_LoBits TGenericArray <> ; XREF: TFileNameDatabase__Destructor+70_r - ; TFileNameDatabase__CheckNextPathFragment:loc_1957AC9_r ... + ; TFileNameDatabase__CheckNextPathFragment:loc_1957AC9_r db ? ; undefined db ? ; undefined db ? ; undefined FrgmDist_HiBits TBitEntryArray <> ; XREF: TFileNameDatabase__Destructor+64_r - ; TFileNameDatabase__CheckNextPathFragment+119_r ... + ; TFileNameDatabase__CheckNextPathFragment+119_r IndexStruct_174 TNameIndexStruct <> ; XREF: TFileNameDatabase__Destructor+28_r - ; TFileNameDatabase__Destructor+34_r ... + ; TFileNameDatabase__Destructor+34_r db ? ; undefined db ? ; undefined db ? ; undefined NextDB TFileNameDatabasePtr <> ; XREF: TFileNameDatabase__Destructor+1D_o - ; TFileNameDatabase__CheckNextPathFragment+52_r ... + ; TFileNameDatabase__CheckNextPathFragment+52_r NameFragTable TGenericArray <> ; XREF: TFileNameDatabase__Destructor+E_r - ; TFileNameDatabase__CheckNextPathFragment+2F_r ... + ; TFileNameDatabase__CheckNextPathFragment+2F_r db ? ; undefined db ? ; undefined db ? ; undefined NameFragIndexMask dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+26_r - ; sub_1957B80:loc_1957B95_r ... + ; sub_1957B80:loc_1957B95_r field_214 dd ? ; XREF: TFileNameDatabase__Constructor+20E_w ; TFileNameDatabase__LoadFromStream+110_w Struct10 TStruct10 <> ; XREF: TFileNameDatabase__Constructor+21A_w - ; TFileNameDatabase__Constructor+224_w ... + ; TFileNameDatabase__Constructor+224_w MarStream TByteStream <> ; XREF: TFileNameDatabase__Destructor+3_o ; TFileNameDatabase__Constructor+214_o TFileNameDatabase ends @@ -249,11 +249,11 @@ TFileNameDatabase ends MAR_FILE struc ; (sizeof=0xC) pDatabasePtr TFileNameDatabasePtr <> ; XREF: MAR_FILE__Constructor+1D_w - ; MAR_FILE__CreateDatabase+22_w ... + ; MAR_FILE__CreateDatabase+22_w pbMarFileData dd ? ; XREF: MAR_FILE__Constructor+1A_w - ; MAR_FILE__CreateDatabase+1B_r ... + ; MAR_FILE__CreateDatabase+1B_r cbMarFileData dd ? ; XREF: MAR_FILE__Constructor+12_w - ; MAR_FILE__CreateDatabase+18_r ... + ; MAR_FILE__CreateDatabase+18_r MAR_FILE ends .DATA @@ -368,7 +368,7 @@ operator_delete ENDP TSparseArray__GetItemValue proc near ; CODE XREF: sub_1957350+1A_p - ; TFileNameDatabase__CheckNextPathFragment+103_p ... + ; TFileNameDatabase__CheckNextPathFragment+103_p arg_0 = dword ptr 8 @@ -451,7 +451,7 @@ loc_1959BDE: ; CODE XREF: TSparseArray__GetItemValue+ add esi, eax loc_1959BE0: ; CODE XREF: TSparseArray__GetItemValue+26_j - ; TSparseArray__GetItemValue+45_j ... + ; TSparseArray__GetItemValue+45_j mov ebx, edi ; jumptable 01959B88 default case shr ebx, 5 test bl, 1 @@ -525,7 +525,7 @@ TSparseArray__GetItemValue endp TArchiveDatabase__sub_1959CB0 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1_p - ; sub_1958B00+E8_p ... + ; sub_1958B00+E8_p pThis = dword ptr -4 dwKey = dword ptr 8 @@ -614,7 +614,7 @@ loc_1959D55: ; CODE XREF: TFileNameDatabase__FindNext mov ecx, [ebp+pThis] loc_1959D5F: ; CODE XREF: TFileNameDatabase__FindNextMatch+62_j - ; TFileNameDatabase__FindNextMatch+7C_j ... + ; TFileNameDatabase__FindNextMatch+7C_j mov ecx, [ecx+28h] lea esi, [eax+eax*2] mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] @@ -709,7 +709,7 @@ loc_1959E49: ; CODE XREF: TFileNameDatabase__FindNext lea edx, [edx+esi-1C0h] loc_1959E53: ; CODE XREF: TFileNameDatabase__FindNextMatch+FE_j - ; TFileNameDatabase__FindNextMatch+10B_j ... + ; TFileNameDatabase__FindNextMatch+10B_j mov eax, [ebp+pThis] mov ebx, [eax+8] mov ecx, [ebx+edi*4] @@ -809,7 +809,7 @@ TArchiveDatabase__sub_1959CB0 endp ; Attributes: bp-based frame TNameIndexStruct__CheckNameFragment proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+6B_p - ; TFileNameDatabase__CheckNextPathFragment+191_p ... + ; TFileNameDatabase__CheckNextPathFragment+191_p pThis = dword ptr -4 pUnknownStruct1C= dword ptr 8 @@ -845,7 +845,7 @@ loc_195A1A1: ; CODE XREF: TNameIndexStruct__CheckName jb short loc_195A1A1 loc_195A1BD: ; CODE XREF: TNameIndexStruct__CheckNameFragment+2C_j - ; TNameIndexStruct__CheckNameFragment+5Ej ... + ; TNameIndexStruct__CheckNameFragment+5Ej pop edi pop esi xor al, al @@ -907,7 +907,7 @@ TNameIndexStruct__CheckNameFragment endp ; Attributes: bp-based frame sub_1957350 proc near ; CODE XREF: sub_1957B80+D8p - ; sub_1957B80:loc_1957C73p ... + ; sub_1957B80:loc_1957C73p arg_0 = dword ptr 8 @@ -971,7 +971,7 @@ sub_1957350 endp ; Attributes: bp-based frame sub_1959F50 proc near ; CODE XREF: sub_1957B80+14C_p - ; sub_1958980+62_p ... + ; sub_1958980+62_p var_4 = dword ptr -4 arg_0 = dword ptr 8 @@ -1046,7 +1046,7 @@ loc_1959FCA: ; CODE XREF: sub_1959F50+76_j mov ecx, [ebp+var_4] loc_1959FD4: ; CODE XREF: sub_1959F50+51_j - ; sub_1959F50+5B_j ... + ; sub_1959F50+5B_j mov edi, [ecx+28h] lea esi, [eax+eax*2] sub edx, [edi+esi*4] @@ -1124,7 +1124,7 @@ loc_195A064: ; CODE XREF: sub_1959F50+CD_j sub edx, esi loc_195A066: ; CODE XREF: sub_1959F50+B5_j - ; sub_1959F50+BC_j ... + ; sub_1959F50+BC_j mov ebx, [ecx+8] mov esi, [ebx+edi*4] mov eax, esi @@ -1223,7 +1223,7 @@ sub_1959F50 endp ; Attributes: bp-based frame sub_1957B80 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5E_p - ; TFileNameDatabase__CheckNextPathFragment+180_p ... + ; TFileNameDatabase__CheckNextPathFragment+180_p pStruct40 = dword ptr -4 arg_0 = dword ptr 8 @@ -1300,7 +1300,7 @@ loc_1957C05: ; CODE XREF: sub_1957B80+6C_j jb loc_1957B95 loc_1957C25: ; CODE XREF: sub_1957B80+67_j - ; sub_1957B80+7C_j ... + ; sub_1957B80+7C_j pop edi pop esi xor al, al @@ -1765,7 +1765,7 @@ TFileNameDatabase__FindFileInDatabase endp ; Attributes: bp-based frame TGenericArray__SetMaxItems_BYTE proc near ; CODE XREF: sub_19582E0+2Cp - ; TStruct40__InitSearchBuffers+2Cp ... + ; TStruct40__InitSearchBuffers+2Cp ByteCount = dword ptr 8 @@ -1820,7 +1820,7 @@ TGenericArray__SetMaxItems_BYTE endp TGenericArray__SetMaxItems_STRUCT14 proc near ; CODE XREF: TGenericArray__InsertItem_STRUCT14+2Cp - ; TGenericArray__sub_19583A0+2Dp ... + ; TGenericArray__sub_19583A0+2Dp var_4 = dword ptr -4 ItemCount = dword ptr 8 @@ -2086,7 +2086,7 @@ TGenericArray__InsertItem_STRUCT14 endp ; Attributes: bp-based frame CopyNameFragment proc near ; CODE XREF: sub_1958980+DAp - ; sub_1958D70+6Dp ... + ; sub_1958D70+6Dp pThis = dword ptr -4 pStruct1C = dword ptr 8 @@ -2284,7 +2284,7 @@ CopyNameFragment endp ; Attributes: bp-based frame sub_1958D70 proc near ; CODE XREF: sub_1958980+C9p - ; sub_1958D70+59p ... + ; sub_1958D70+59p var_C = dword ptr -0Ch var_8 = dword ptr -8 @@ -2582,7 +2582,7 @@ sub_1958D70 endp ; Attributes: bp-based frame TFileNameDatabase__sub_1959CB0 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1p - ; TFileNameDatabase__sub_1958B00+E8p ... + ; TFileNameDatabase__sub_1958B00+E8p pThis = dword ptr -4 dwKey = dword ptr 8 @@ -2671,7 +2671,7 @@ loc_1959D55: ; CODE XREF: TFileNameDatabase__sub_1959 mov ecx, [ebp+pThis] loc_1959D5F: ; CODE XREF: TFileNameDatabase__sub_1959CB0+62j - ; TFileNameDatabase__sub_1959CB0+7Cj ... + ; TFileNameDatabase__sub_1959CB0+7Cj mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] lea esi, [eax+eax*2] mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] @@ -2766,7 +2766,7 @@ loc_1959E49: ; CODE XREF: TFileNameDatabase__sub_1959 lea edx, [edx+esi-1C0h] loc_1959E53: ; CODE XREF: TFileNameDatabase__sub_1959CB0+FEj - ; TFileNameDatabase__sub_1959CB0+10Bj ... + ; TFileNameDatabase__sub_1959CB0+10Bj mov eax, [ebp+pThis] mov ebx, [eax+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] mov ecx, [ebx+edi*4] @@ -2866,7 +2866,7 @@ TFileNameDatabase__sub_1959CB0 endp ; Attributes: bp-based frame TNameIndexStruct__CheckAndCopyNameFragment proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+74p - ; TArchiveDatabase__sub_1958B00+1E0p ... + ; TArchiveDatabase__sub_1958B00+1E0p var_C = dword ptr -0Ch pThis = dword ptr -8 @@ -3206,7 +3206,7 @@ TNameIndexStruct__CheckAndCopyNameFragment endp ; Attributes: bp-based frame sub_1959010 proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+67p - ; TArchiveDatabase__sub_1958B00+1CFp ... + ; TArchiveDatabase__sub_1958B00+1CFp pFragmentInfo = dword ptr -0Ch var_8 = dword ptr -8 @@ -3262,7 +3262,7 @@ loc_195907F: ; CODE XREF: sub_1959010+5Ej jnz loc_195912E loc_1959087: ; CODE XREF: sub_1959010+90j - ; sub_1959010+1F3j ... + ; sub_1959010+1F3j pop edi pop esi xor al, al @@ -3962,14 +3962,14 @@ loc_19594B0: ; CODE XREF: TFileNameDatabase__sub_1959 ; --------------------------------------------------------------------------- loc_1959522: ; CODE XREF: TFileNameDatabase__sub_1959460+26Bj - ; TFileNameDatabase__sub_1959460+2D9j ... + ; TFileNameDatabase__sub_1959460+2D9j mov ebx, [ebp+pThis] jmp short loc_1959530 ; --------------------------------------------------------------------------- align 10h loc_1959530: ; CODE XREF: TFileNameDatabase__sub_1959460+23j - ; TFileNameDatabase__sub_1959460+97j ... + ; TFileNameDatabase__sub_1959460+97j mov edx, [esi+TStruct40.ItemCount] cmp edx, [esi+TStruct40.array_18.ItemCount] jnz loc_19595BD diff --git a/dep/CascLib/src/CascRootFile_Ovr.cpp b/dep/CascLib/src/CascRootFile_Ovr.cpp new file mode 100644 index 00000000000..205353c0120 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Ovr.cpp @@ -0,0 +1,199 @@ +/*****************************************************************************/ +/* CascRootFile_Ovr.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Support for loading Overwatch ROOT file */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 28.10.15 1.00 Lad The first version of CascRootFile_Ovr.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Structure definitions for Overwatch root file + +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key + ULONGLONG FileNameHash; // File name hash + DWORD dwFileName; // Offset of the file name in the name cache +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +struct TRootHandler_Ovr : public TRootHandler +{ + // Linear global list of file entries + DYNAMIC_ARRAY FileTable; + + // Linear global list of names + DYNAMIC_ARRAY FileNames; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; +}; + +//----------------------------------------------------------------------------- +// Local functions + +static int InsertFileEntry( + TRootHandler_Ovr * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + PCASC_FILE_ENTRY pFileEntry; + size_t nLength = strlen(szFileName); + + // Attempt to insert the file name to the global buffer + szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1); + if(szFileName == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Attempt to insert the entry to the array of file entries + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + if(pFileEntry == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the file entry + pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->dwFileName = Array_IndexOf(&pRootHandler->FileNames, szFileName); + + // Insert the file entry to the map + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of Overwatch root file + +static int OvrHandler_Insert( + TRootHandler_Ovr * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey); +} + +static LPBYTE OvrHandler_Search(TRootHandler_Ovr * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Are we still inside the root directory range? + while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount) + { + // Retrieve the file item + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1); + strcpy(pSearch->szFileName, (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName)); + + // Prepare the pointer to the next search + pSearch->IndexLevel1++; + return pFileEntry->EncodingKey.Value; + } + + // No more entries + return NULL; +} + +static void OvrHandler_EndSearch(TRootHandler_Ovr * /* pRootHandler */, TCascSearch * /* pSearch */) +{ + // Do nothing +} + +static LPBYTE OvrHandler_GetKey(TRootHandler_Ovr * pRootHandler, const char * szFileName) +{ + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL); +} + +static void OvrHandler_Close(TRootHandler_Ovr * pRootHandler) +{ + if(pRootHandler != NULL) + { + // Free the file map + if(pRootHandler->pRootMap) + Map_Free(pRootHandler->pRootMap); + pRootHandler->pRootMap = NULL; + + // Free the array of the file names and file items + Array_Free(&pRootHandler->FileTable); + Array_Free(&pRootHandler->FileNames); + + // Free the root file itself + CASC_FREE(pRootHandler); + } +} + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + TRootHandler_Ovr * pRootHandler; + ENCODING_KEY KeyBuffer; + QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE}; + void * pTextFile; + size_t nLength; + char szOneLine[0x200]; + char szFileName[MAX_PATH+1]; + DWORD dwFileCountMax = hs->pEncodingMap->TableSize; + int nError = ERROR_SUCCESS; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_Ovr, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_Ovr)); + pRootHandler->Insert = (ROOT_INSERT)OvrHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)OvrHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)OvrHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)OvrHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)OvrHandler_Close; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + + // Allocate the linear array of file entries + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000); + if(nError != ERROR_SUCCESS) + return nError; + + // Allocate the buffer for the file names + nError = Array_Create(&pRootHandler->FileNames, char, 0x10000); + if(nError != ERROR_SUCCESS) + return nError; + + // Create map of ROOT_ENTRY -> FileEntry + pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the ROOT file + pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile); + if(pTextFile != NULL) + { + // Skip the first line, containing "#MD5|CHUNK_ID|FILENAME|INSTALLPATH" + ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine)); + + // Parse the next lines + while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0) + { + // Parse the line + nError = ParseRootFileLine(szOneLine, szOneLine + nLength, &EncodingKey, szFileName, _maxchars(szFileName)); + if(nError == ERROR_SUCCESS) + { + InsertFileEntry(pRootHandler, szFileName, KeyBuffer.Value); + } + } + + ListFile_Free(pTextFile); + } + + // Succeeded + return nError; +} diff --git a/dep/CascLib/src/CascRootFile_WoW6.cpp b/dep/CascLib/src/CascRootFile_WoW6.cpp new file mode 100644 index 00000000000..0c631f82b00 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_WoW6.cpp @@ -0,0 +1,531 @@ +/*****************************************************************************/ +/* CascOpenStorage.cpp Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Storage functions for CASC */ +/* Note: WoW6 offsets refer to WoW.exe 6.0.3.19116 (32-bit) */ +/* SHA1: c10e9ffb7d040a37a356b96042657e1a0c95c0dd */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.04.14 1.00 Lad The first version of CascOpenStorage.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +#define ROOT_SEARCH_PHASE_INITIALIZING 0 +#define ROOT_SEARCH_PHASE_LISTFILE 1 +#define ROOT_SEARCH_PHASE_NAMELESS 2 +#define ROOT_SEARCH_PHASE_FINISHED 2 + +// On-disk version of locale block +typedef struct _FILE_LOCALE_BLOCK +{ + DWORD NumberOfFiles; // Number of entries + DWORD Flags; + DWORD Locales; // File locale mask (CASC_LOCALE_XXX) + + // Followed by a block of 32-bit integers (count: NumberOfFiles) + // Followed by the MD5 and file name hash (count: NumberOfFiles) + +} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK; + +// On-disk version of root entry +typedef struct _FILE_ROOT_ENTRY +{ + ENCODING_KEY EncodingKey; // MD5 of the file + ULONGLONG FileNameHash; // Jenkins hash of the file name + +} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY; + + +typedef struct _CASC_ROOT_BLOCK +{ + PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block + PDWORD FileDataIds; // Pointer to the array of File Data IDs + PFILE_ROOT_ENTRY pRootEntries; + +} CASC_ROOT_BLOCK, *PCASC_ROOT_BLOCK; + +// Root file entry for CASC storages without MNDX root file (World of Warcraft 6.0+) +// Does not match to the in-file structure of the root entry +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // File encoding key (MD5) + ULONGLONG FileNameHash; // Jenkins hash of the file name + DWORD FileDataId; // File Data Index + DWORD Locales; // Locale flags of the file + +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +struct TRootHandler_WoW6 : public TRootHandler +{ + // Linear global list of file entries + DYNAMIC_ARRAY FileTable; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; + + // For counting files + DWORD dwTotalFileCount; + DWORD FileDataId; +}; + +// Prototype for root file parsing routine +typedef int (*PARSE_ROOT)(TRootHandler_WoW6 * pRootHandler, PCASC_ROOT_BLOCK pBlockInfo); + +//----------------------------------------------------------------------------- +// Local functions + +static bool IsFileDataIdName(const char * szFileName) +{ + BYTE BinaryValue[4]; + + // File name must begin with "File", case insensitive + if(AsciiToUpperTable_BkSlash[szFileName[0]] == 'F' && + AsciiToUpperTable_BkSlash[szFileName[1]] == 'I' && + AsciiToUpperTable_BkSlash[szFileName[2]] == 'L' && + AsciiToUpperTable_BkSlash[szFileName[3]] == 'E') + { + // Then, 8 hexadecimal digits must follow + if(ConvertStringToBinary(szFileName + 4, 8, BinaryValue) == ERROR_SUCCESS) + { + // Must be followed by an extension or end-of-string + return (szFileName[0x0C] == 0 || szFileName[0x0C] == '.'); + } + } + + return false; +} + +// Search by FileDataId +PCASC_FILE_ENTRY FindRootEntry(DYNAMIC_ARRAY & FileTable, DWORD FileDataId) +{ + PCASC_FILE_ENTRY pStartEntry = (PCASC_FILE_ENTRY)FileTable.ItemArray; + PCASC_FILE_ENTRY pMidlEntry; + PCASC_FILE_ENTRY pEndEntry = pStartEntry + FileTable.ItemCount - 1; + int nResult; + + // Perform binary search on the table + while(pStartEntry < pEndEntry) + { + // Calculate the middle of the interval + pMidlEntry = pStartEntry + ((pEndEntry - pStartEntry) / 2); + + // Did we find it? + nResult = (int)FileDataId - (int)pMidlEntry->FileDataId; + if(nResult == 0) + return pMidlEntry; + + // Move the interval to the left or right + (nResult < 0) ? pEndEntry = pMidlEntry : pStartEntry = pMidlEntry + 1; + } + + return NULL; +} + +// Search by file name hash +// Also used in CascSearchFile +PCASC_FILE_ENTRY FindRootEntry(PCASC_MAP pRootMap, const char * szFileName, DWORD * PtrTableIndex) +{ + // Calculate the HASH value of the normalized file name + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + // Perform the hash search + return (PCASC_FILE_ENTRY)Map_FindObject(pRootMap, &FileNameHash, PtrTableIndex); +} + +LPBYTE VerifyLocaleBlock(PCASC_ROOT_BLOCK pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd) +{ + // Validate the file locale block + pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->pLocaleBlockHdr + 1); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Validate the array of 32-bit integers + pBlockInfo->FileDataIds = (PDWORD)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->FileDataIds + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Validate the array of root entries + pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Return the position of the next block + return pbFilePointer; +} + +static int ParseRoot_CountFiles( + TRootHandler_WoW6 * pRootHandler, + PCASC_ROOT_BLOCK pRootBlock) +{ + // Add the file count to the total file count + pRootHandler->dwTotalFileCount += pRootBlock->pLocaleBlockHdr->NumberOfFiles; + return ERROR_SUCCESS; +} + +static int ParseRoot_AddRootEntries( + TRootHandler_WoW6 * pRootHandler, + PCASC_ROOT_BLOCK pRootBlock) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Sanity checks + assert(pRootHandler->FileTable.ItemArray != NULL); + assert(pRootHandler->FileTable.ItemCountMax != 0); + + // WoW.exe (build 19116): Blocks with zero files are skipped + for(DWORD i = 0; i < pRootBlock->pLocaleBlockHdr->NumberOfFiles; i++) + { + // Create new entry, with overflow check + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_INSUFFICIENT_BUFFER; + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + + // (004147A3) Prepare the CASC_FILE_ENTRY structure + pFileEntry->FileNameHash = pRootBlock->pRootEntries[i].FileNameHash; + pFileEntry->FileDataId = pRootHandler->FileDataId + pRootBlock->FileDataIds[i]; + pFileEntry->Locales = pRootBlock->pLocaleBlockHdr->Locales; + pFileEntry->EncodingKey = pRootBlock->pRootEntries[i].EncodingKey; + + // Also, insert the entry to the map + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + + // Update the local File Data Id + assert((pFileEntry->FileDataId + 1) > pFileEntry->FileDataId); + pRootHandler->FileDataId = pFileEntry->FileDataId + 1; + + // Move to the next root entry + pFileEntry++; + } + + return ERROR_SUCCESS; +} + +static int ParseWowRootFileInternal( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask, + bool bLoadBlocksWithFlags80, + BYTE HighestBitValue) +{ + CASC_ROOT_BLOCK RootBlock; + + // Now parse the root file + while(pbRootFile < pbRootFileEnd) + { + // Validate the file locale block + pbRootFile = VerifyLocaleBlock(&RootBlock, pbRootFile, pbRootFileEnd); + if(pbRootFile == NULL) + break; + + // WoW.exe (build 19116): Entries with flag 0x100 set are skipped + if(RootBlock.pLocaleBlockHdr->Flags & 0x100) + continue; + + // WoW.exe (build 19116): Entries with flag 0x80 set are skipped if arg_4 is set to FALSE (which is by default) + if((RootBlock.pLocaleBlockHdr->Flags & 0x80) && bLoadBlocksWithFlags80 == 0) + continue; + + // WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to arg_8 are skipped + if((RootBlock.pLocaleBlockHdr->Flags >> 0x1F) != HighestBitValue) + continue; + + // WoW.exe (build 19116): Locales other than defined mask are skipped too + if((RootBlock.pLocaleBlockHdr->Locales & dwLocaleMask) == 0) + continue; + + // Now call the custom function + pfnParseRoot(pRootHandler, &RootBlock); + } + + return ERROR_SUCCESS; +} + +/* + // Code from WoW.exe + if(dwLocaleMask == CASC_LOCALE_DUAL_LANG) + { + // Is this english version of WoW? + if(arg_4 == CASC_LOCALE_BIT_ENUS) + { + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENGB, false, HighestBitValue); + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); + return ERROR_SUCCESS; + } + + // Is this portuguese version of WoW? + if(arg_4 == CASC_LOCALE_BIT_PTBR) + { + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTPT, false, HighestBitValue); + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); + } + } + + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, (1 << arg_4), false, HighestBitValue); +*/ + +static int ParseWowRootFile2( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask, + BYTE HighestBitValue) +{ + // Load the locale as-is + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, false, HighestBitValue); + + // If we wanted enGB, we also load enUS for the missing files + if(dwLocaleMask == CASC_LOCALE_ENGB) + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_ENUS, false, HighestBitValue); + + if(dwLocaleMask == CASC_LOCALE_PTPT) + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_PTBR, false, HighestBitValue); + + return ERROR_SUCCESS; +} + +// WoW.exe: 004146C7 (BuildManifest::Load) +static int ParseWowRootFile( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask) +{ + ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 0); + ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 1); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of WoW6 root file + +static int WowHandler_Insert( + TRootHandler_WoW6 * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + PCASC_FILE_ENTRY pFileEntry; + DWORD FileDataId = 0; + + // Don't let the number of items to overflow + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_NOT_ENOUGH_MEMORY; + + // Insert the item to the linear file list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + if(pFileEntry != NULL) + { + // Get the file data ID of the previous item (0 if this is the first one) + if(pRootHandler->FileTable.ItemCount > 1) + FileDataId = pFileEntry[-1].FileDataId; + + // Fill-in the new entry + pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->FileDataId = FileDataId + 1; + pFileEntry->Locales = CASC_LOCALE_ALL; + + // Verify collisions (debug version only) + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + + // Insert the entry to the map + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + } + + return ERROR_SUCCESS; +} + +static LPBYTE WowHandler_Search(TRootHandler_WoW6 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD PtrLocaleFlags) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Only if we have a listfile + if(pSearch->pCache != NULL) + { + // Keep going through the listfile + while(ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH)) + { + // Find the root entry + pFileEntry = FindRootEntry(pRootHandler->pRootMap, pSearch->szFileName, NULL); + if(pFileEntry != NULL) + { + // Give the caller the locale mask + if(PtrLocaleFlags != NULL) + PtrLocaleFlags[0] = pFileEntry->Locales; + return pFileEntry->EncodingKey.Value; + } + } + } + + // No more files + return NULL; +} + +static LPBYTE WowHandler_GetKey(TRootHandler_WoW6 * pRootHandler, const char * szFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + DWORD FileDataId; + BYTE FileDataIdLE[4]; + + // Open by FileDataId. The file name must be as following: + // File########.xxx, where '#' are hexa-decimal numbers (case insensitive). + // Extension is ignored in that case + if(IsFileDataIdName(szFileName)) + { + ConvertStringToBinary(szFileName + 4, 8, FileDataIdLE); + FileDataId = ConvertBytesToInteger_4(FileDataIdLE); + + pFileEntry = FindRootEntry(pRootHandler->FileTable, FileDataId); + } + else + { + // Find by the file name hash + pFileEntry = FindRootEntry(pRootHandler->pRootMap, szFileName, NULL); + } + + return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL; +} + +static void WowHandler_EndSearch(TRootHandler_WoW6 * /* pRootHandler */, TCascSearch * pSearch) +{ + if(pSearch->pRootContext != NULL) + CASC_FREE(pSearch->pRootContext); + pSearch->pRootContext = NULL; +} + +static void WowHandler_Close(TRootHandler_WoW6 * pRootHandler) +{ + if(pRootHandler != NULL) + { + Array_Free(&pRootHandler->FileTable); + Map_Free(pRootHandler->pRootMap); + CASC_FREE(pRootHandler); + } +} + +#ifdef _DEBUG +static void TRootHandlerWoW6_Dump( + TCascStorage * hs, + TDumpContext * dc, // Pointer to an opened file + LPBYTE pbRootFile, + DWORD cbRootFile, + const TCHAR * szListFile, + int nDumpLevel) +{ + PCASC_ENCODING_ENTRY pEncodingEntry; + CASC_ROOT_BLOCK BlockInfo; + PLISTFILE_MAP pListMap; + QUERY_KEY EncodingKey; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + LPBYTE pbFilePointer; + char szOneLine[0x100]; + DWORD i; + + // Create the listfile map + pListMap = ListFile_CreateMap(szListFile); + + // Dump the root entries + for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) + { + // Validate the root block + pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); + if(pbFilePointer == NULL) + break; + + // Dump the locale block + dump_print(dc, "Flags: %08X Locales: %08X NumberOfFiles: %u\n" + "=========================================================\n", + BlockInfo.pLocaleBlockHdr->Flags, + BlockInfo.pLocaleBlockHdr->Locales, + BlockInfo.pLocaleBlockHdr->NumberOfFiles); + + // Dump the hashes and encoding keys + for(i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) + { + // Dump the entry + dump_print(dc, "%08X %08X-%08X %s %s\n", + (DWORD)(BlockInfo.FileDataIds[i]), + (DWORD)(BlockInfo.pRootEntries[i].FileNameHash >> 0x20), + (DWORD)(BlockInfo.pRootEntries[i].FileNameHash), + StringFromMD5(BlockInfo.pRootEntries[i].EncodingKey.Value, szOneLine), + ListFile_FindName(pListMap, BlockInfo.pRootEntries[i].FileNameHash)); + + // Find the encoding entry in the encoding table + if(nDumpLevel >= DUMP_LEVEL_ENCODING_FILE) + { + EncodingKey.pbData = BlockInfo.pRootEntries[i].EncodingKey.Value; + EncodingKey.cbData = MD5_HASH_SIZE; + pEncodingEntry = FindEncodingEntry(hs, &EncodingKey, NULL); + CascDumpEncodingEntry(hs, dc, pEncodingEntry, nDumpLevel); + } + } + + // Put extra newline + dump_print(dc, "\n"); + } + + ListFile_FreeMap(pListMap); +} +#endif + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask) +{ + TRootHandler_WoW6 * pRootHandler; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + int nError; + + // Verify the size + if(pbRootFile == NULL || cbRootFile <= sizeof(PFILE_LOCALE_BLOCK)) + nError = ERROR_FILE_CORRUPT; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_WoW6, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_WoW6)); + pRootHandler->Insert = (ROOT_INSERT)WowHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)WowHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)WowHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)WowHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)WowHandler_Close; + +#ifdef _DEBUG + pRootHandler->Dump = TRootHandlerWoW6_Dump; // Support for ROOT file dump +#endif // _DEBUG + + // Count the files that are going to be loaded + ParseWowRootFile(pRootHandler, ParseRoot_CountFiles, pbRootFile, pbRootFileEnd, dwLocaleMask); + pRootHandler->dwTotalFileCount += CASC_EXTRA_FILES; + + // Create linear table that will contain all root items + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, pRootHandler->dwTotalFileCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Create the map of FileHash ->FileEntry + pRootHandler->pRootMap = Map_Create(pRootHandler->dwTotalFileCount, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the root file again and insert all files to the map + ParseWowRootFile(pRootHandler, ParseRoot_AddRootEntries, pbRootFile, pbRootFileEnd, dwLocaleMask); + return ERROR_SUCCESS; +} diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp index 2dbdd470478..9c0f56dc9ba 100644 --- a/dep/CascLib/src/common/Common.cpp +++ b/dep/CascLib/src/common/Common.cpp @@ -99,7 +99,7 @@ void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength) szTarget[cchLength] = 0; } -char * NewStr(const char * szString, size_t nCharsToReserve) +char * CascNewStr(const char * szString, size_t nCharsToReserve) { char * szNewString = NULL; size_t nLength; @@ -118,7 +118,7 @@ char * NewStr(const char * szString, size_t nCharsToReserve) return szNewString; } -wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve) +wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve) { wchar_t * szNewString = NULL; size_t nLength; @@ -137,22 +137,20 @@ wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve) return szNewString; } -TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd) +TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd) { TCHAR * szNewString = NULL; - TCHAR * szStringPtr = NULL; - size_t nLength = (size_t)(pbStringEnd - pbStringBegin); - if(pbStringEnd > pbStringBegin) + // Only if the entry is valid + if(szBegin != NULL && szEnd > szBegin) { - szNewString = szStringPtr = CASC_ALLOC(TCHAR, nLength + 1); + // Allocate and copy the string + szNewString = CASC_ALLOC(TCHAR, (szEnd - szBegin + 1)); if(szNewString != NULL) - { - CopyString(szStringPtr, (const char *)pbStringBegin, nLength); - szStringPtr[nLength] = 0; - } + CopyString(szNewString, szBegin, (szEnd - szBegin)); } + // Return the string return szNewString; } @@ -218,30 +216,60 @@ TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir) return szFullPath; } -void NormalizeFileName_UpperBkSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars) +TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength) { - char * szTrgFileEnd = szTrgFileName + cchMaxChars; - size_t i; + TCHAR * szFullPath = NULL; + TCHAR * szSubDir; - // Normalize the file name: ToLower + BackSlashToSlash - for(i = 0; szSrcFileName[i] != 0 && szTrgFileName < szTrgFileEnd; i++) - szTrgFileName[i] = AsciiToUpperTable_BkSlash[szSrcFileName[i]]; + // Create the subdir string + szSubDir = CASC_ALLOC(TCHAR, nLength + 1); + if(szSubDir != NULL) + { + CopyString(szSubDir, szString, nLength); + szFullPath = CombinePath(szPath, szSubDir); + CASC_FREE(szSubDir); + } - assert(szSrcFileName[i] == 0); - szTrgFileName[i] = 0; + return szFullPath; } -void NormalizeFileName_LowerSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars) +size_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars) { - char * szTrgFileEnd = szTrgFileName + cchMaxChars; + char * szNormNameEnd = szNormName + cchMaxChars; size_t i; // Normalize the file name: ToLower + BackSlashToSlash - for(i = 0; szSrcFileName[i] != 0 && szTrgFileName < szTrgFileEnd; i++) - szTrgFileName[i] = AsciiToLowerTable_Slash[szSrcFileName[i]]; + for(i = 0; szFileName[0] != 0 && szNormName < szNormNameEnd; i++) + *szNormName++ = NormTable[*szFileName++]; - assert(szSrcFileName[i] == 0); - szTrgFileName[i] = 0; + // Terminate the string + szNormName[0] = 0; + return i; +} + +size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars) +{ + return NormalizeFileName(AsciiToUpperTable_BkSlash, szNormName, szFileName, cchMaxChars); +} + +size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars) +{ + return NormalizeFileName(AsciiToLowerTable_Slash, szNormName, szFileName, cchMaxChars); +} + +ULONGLONG CalcFileNameHash(const char * szFileName) +{ + char szNormName[MAX_PATH+1]; + uint32_t dwHashHigh = 0; + uint32_t dwHashLow = 0; + size_t nLength; + + // Normalize the file name - convert to uppercase, slashes to backslashes + nLength = NormalizeFileName_UpperBkSlash(szNormName, szFileName, MAX_PATH); + + // Calculate the HASH value of the normalized file name + hashlittle2(szNormName, nLength, &dwHashHigh, &dwHashLow); + return ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; } int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue) @@ -256,6 +284,22 @@ int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue) return (Digit > 0x0F) ? ERROR_BAD_FORMAT : ERROR_SUCCESS; } +int ConvertStringToInt08(const char * szString, PDWORD PtrValue) +{ + BYTE DigitOne = AsciiToUpperTable_BkSlash[szString[0]] - '0'; + BYTE DigitTwo = AsciiToUpperTable_BkSlash[szString[1]] - '0'; + + // Fix the digits + if(DigitOne > 9) + DigitOne -= 'A' - '9' - 1; + if(DigitTwo > 9) + DigitTwo -= 'A' - '9' - 1; + + // Combine them into a value + PtrValue[0] = (DigitOne << 0x04) | DigitTwo; + return (DigitOne <= 0x0F && DigitTwo <= 0x0F) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; +} + int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue) { // The number of digits must be even @@ -290,6 +334,41 @@ int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrVa return ERROR_SUCCESS; } +// Converts string blob to binary blob. +int ConvertStringToBinary( + const char * szString, + size_t nMaxDigits, + LPBYTE pbBinary) +{ + const char * szStringEnd = szString + nMaxDigits; + DWORD dwCounter = 0; + BYTE DigitValue; + BYTE ByteValue = 0; + + // Convert the string + while(szString < szStringEnd) + { + // Retrieve the digit converted to hexa + DigitValue = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - '0'); + if(DigitValue > 9) + DigitValue -= 'A' - '9' - 1; + if(DigitValue > 0x0F) + return ERROR_BAD_FORMAT; + + // Insert the digit to the binary buffer + ByteValue = (ByteValue << 0x04) | DigitValue; + dwCounter++; + + // If we reached the second digit, it means that we need + // to flush the byte value and move on + if((dwCounter & 0x01) == 0) + *pbBinary++ = ByteValue; + szString++; + } + + return ERROR_SUCCESS; +} + char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer) { char * szSaveBuffer = szBuffer; @@ -308,6 +387,11 @@ char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer) return szSaveBuffer; } +char * StringFromMD5(LPBYTE md5, char * szBuffer) +{ + return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer); +} + //----------------------------------------------------------------------------- // File name utilities @@ -341,87 +425,55 @@ const char * GetPlainFileName(const char * szFileName) bool CheckWildCard(const char * szString, const char * szWildCard) { - const char * szSubString; - int nSubStringLength; - int nMatchCount = 0; + const char * szWildCardPtr; - // When the mask is empty, it never matches - if(szWildCard == NULL || *szWildCard == 0) - return false; - - // If the wildcard contains just "*", then it always matches - if(szWildCard[0] == '*' && szWildCard[1] == 0) - return true; - - // Do normal test for(;;) { // If there is '?' in the wildcard, we skip one char - while(*szWildCard == '?') + while(szWildCard[0] == '?') { + if(szString[0] == 0) + return false; + szWildCard++; szString++; } - // If there is '*', means zero or more chars. We have to - // find the sequence after '*' - if(*szWildCard == '*') + // Handle '*' + szWildCardPtr = szWildCard; + if(szWildCardPtr[0] != 0) { - // More stars is equal to one star - while(*szWildCard == '*' || *szWildCard == '?') - szWildCard++; - - // If we found end of the wildcard, it's a match - if(*szWildCard == 0) - return true; - - // Determine the length of the substring in szWildCard - szSubString = szWildCard; - while(*szSubString != 0 && *szSubString != '?' && *szSubString != '*') - szSubString++; - nSubStringLength = (int)(szSubString - szWildCard); - nMatchCount = 0; - - // Now we have to find a substring in szString, - // that matches the substring in szWildCard - while(*szString != 0) + if(szWildCardPtr[0] == '*') { - // Calculate match count - while(nMatchCount < nSubStringLength) - { - if(AsciiToUpperTable_BkSlash[(BYTE)szString[nMatchCount]] != AsciiToUpperTable_BkSlash[(BYTE)szWildCard[nMatchCount]]) - break; - if(szString[nMatchCount] == 0) - break; - nMatchCount++; - } + szWildCardPtr++; - // If the match count has reached substring length, we found a match - if(nMatchCount == nSubStringLength) - { - szWildCard += nMatchCount; - szString += nMatchCount; - break; - } + if(szWildCardPtr[0] == '*') + continue; - // No match, move to the next char in szString - nMatchCount = 0; - szString++; + if(szWildCardPtr[0] == 0) + return true; + + if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] == AsciiToUpperTable_BkSlash[szString[0]]) + { + if(CheckWildCard(szString, szWildCardPtr)) + return true; + } } + else + { + if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] != AsciiToUpperTable_BkSlash[szString[0]]) + return false; + + szWildCard = szWildCardPtr + 1; + } + + if(szString[0] == 0) + return false; + szString++; } else { - // If we came to the end of the string, compare it to the wildcard - if(AsciiToUpperTable_BkSlash[(BYTE)*szString] != AsciiToUpperTable_BkSlash[(BYTE)*szWildCard]) - return false; - - // If we arrived to the end of the string, it's a match - if(*szString == 0) - return true; - - // Otherwise, continue in comparing - szWildCard++; - szString++; + return (szString[0] == 0) ? true : false; } } } diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h index ae098adb084..484276a3bd7 100644 --- a/dep/CascLib/src/common/Common.h +++ b/dep/CascLib/src/common/Common.h @@ -28,14 +28,6 @@ extern unsigned char AsciiToLowerTable_Slash[256]; extern unsigned char AsciiToUpperTable_BkSlash[256]; extern unsigned char IntToHexChar[]; -//----------------------------------------------------------------------------- -// GetLastError/SetLastError support for non-Windows platform - -#ifndef PLATFORM_WINDOWS -int GetLastError(); -void SetLastError(int nError); -#endif // PLATFORM_WINDOWS - //----------------------------------------------------------------------------- // String manipulation @@ -43,19 +35,25 @@ void CopyString(char * szTarget, const char * szSource, size_t cchLength); void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength); void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength); -char * NewStr(const char * szString, size_t nCharsToReserve); -wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve); +char * CascNewStr(const char * szString, size_t nCharsToReserve); +wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve); -TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd); +TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd); TCHAR * CombinePath(const TCHAR * szPath, const TCHAR * szSubDir); +TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength); -void NormalizeFileName_UpperBkSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars); -void NormalizeFileName_LowerSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars); +size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); +size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); + +ULONGLONG CalcFileNameHash(const char * szFileName); int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue); +int ConvertStringToInt08(const char * szString, PDWORD PtrValue); int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue); +int ConvertStringToBinary(const char * szString, size_t nMaxDigits, LPBYTE pbBinary); char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer); +char * StringFromMD5(LPBYTE md5, char * szBuffer); //----------------------------------------------------------------------------- // File name utilities diff --git a/dep/CascLib/src/common/Directory.h b/dep/CascLib/src/common/Directory.h new file mode 100644 index 00000000000..ae97dca3d76 --- /dev/null +++ b/dep/CascLib/src/common/Directory.h @@ -0,0 +1,29 @@ +/*****************************************************************************/ +/* Directory.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Directory functions for CascLib */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of Directory.h */ +/*****************************************************************************/ + +#ifndef __DIRECTORY_H__ +#define __DIRECTORY_H__ + +//----------------------------------------------------------------------------- +// Scanning a directory + +typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext); + +bool DirectoryExists(const TCHAR * szDirectory); + +int ScanIndexDirectory( + const TCHAR * szIndexPath, + INDEX_FILE_FOUND pfnOnFileFound, + PDWORD IndexArray, + PDWORD OldIndexArray, + void * pvContext + ); + +#endif // __DIRECTORY_H__ diff --git a/dep/CascLib/src/common/DumpContext.cpp b/dep/CascLib/src/common/DumpContext.cpp new file mode 100644 index 00000000000..8783ff201ba --- /dev/null +++ b/dep/CascLib/src/common/DumpContext.cpp @@ -0,0 +1,153 @@ +/*****************************************************************************/ +/* DumpContext.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Implementation of dump context */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 16.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +static TCHAR * FormatFileName(TCascStorage * hs, const TCHAR * szNameFormat) +{ + TCHAR * szFileName; + TCHAR * szSrc; + TCHAR * szTrg; + + // Create copy of the file name + szFileName = szSrc = szTrg = CascNewStr(szNameFormat, 0); + if(szFileName != NULL) + { + // Format the file name + while(szSrc[0] != 0) + { + if(szSrc[0] == _T('%')) + { + // Replace "%build%" with a build number + if(!_tcsncmp(szSrc, _T("%build%"), 7)) + { + szTrg += _stprintf(szTrg, _T("%u"), hs->dwBuildNumber); + szSrc += 7; + continue; + } + } + + // Just copy the character + *szTrg++ = *szSrc++; + } + + // Terminate the target file name + szTrg[0] = 0; + } + + return szFileName; +} + +//----------------------------------------------------------------------------- +// Public functions + +TDumpContext * CreateDumpContext(TCascStorage * hs, const TCHAR * szNameFormat) +{ + TDumpContext * dc; + TCHAR * szFileName; + + // Validate the storage handle + if(hs != NULL) + { + // Calculate the number of bytes needed for dump context + dc = CASC_ALLOC(TDumpContext, 1); + if(dc != NULL) + { + // Initialize the dump context + memset(dc, 0, sizeof(TDumpContext)); + + // Format the real file name + szFileName = FormatFileName(hs, szNameFormat); + if(szFileName != NULL) + { + // Create the file + dc->pStream = FileStream_CreateFile(szFileName, 0); + if(dc->pStream != NULL) + { + // Initialize buffers + dc->pbBufferBegin = + dc->pbBufferPtr = dc->DumpBuffer; + dc->pbBufferEnd = dc->DumpBuffer + CASC_DUMP_BUFFER_SIZE; + + // Success + CASC_FREE(szFileName); + return dc; + } + + // File create failed --> delete the file name + CASC_FREE(szFileName); + } + + // Free the dump context + CASC_FREE(dc); + } + } + + return NULL; +} + +int dump_print(TDumpContext * dc, const char * szFormat, ...) +{ + va_list argList; + char szBuffer[0x200]; + int nLength = 0; + + // Only if the dump context is valid + if(dc != NULL) + { + // Print the buffer using sprintf + va_start(argList, szFormat); + nLength = vsprintf(szBuffer, szFormat, argList); + assert(nLength < 0x200); + va_end(argList); + + // Copy the string. Replace "\n" with "\n\r" + for(int i = 0; i < nLength; i++) + { + // Flush the buffer, if needed + if((dc->pbBufferPtr + 2) >= dc->pbBufferEnd) + { + FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin)); + dc->pbBufferPtr = dc->pbBufferBegin; + } + + // Copy the char + if(szBuffer[i] == 0x0A) + *dc->pbBufferPtr++ = 0x0D; + *dc->pbBufferPtr++ = szBuffer[i]; + } + } + + return nLength; +} + +int dump_close(TDumpContext * dc) +{ + // Only if the dump context is valid + if(dc != NULL) + { + // Flush the dump context if there are some data + if(dc->pbBufferPtr > dc->pbBufferBegin) + FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin)); + dc->pbBufferPtr = dc->pbBufferBegin; + + // Free the file stream and the entire context + if(dc->pStream != NULL) + FileStream_Close(dc->pStream); + CASC_FREE(dc); + } + + return 0; +} diff --git a/dep/CascLib/src/common/DumpContext.h b/dep/CascLib/src/common/DumpContext.h new file mode 100644 index 00000000000..6f725f5b942 --- /dev/null +++ b/dep/CascLib/src/common/DumpContext.h @@ -0,0 +1,38 @@ +/*****************************************************************************/ +/* DumpContext.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Interface for TDumpContext */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 16.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __DUMP_CONTEXT_H__ +#define __DUMP_CONTEXT_H__ + +//----------------------------------------------------------------------------- +// Defines + +// Size of the buffer for the dump context +#define CASC_DUMP_BUFFER_SIZE 0x10000 + +// Structure for dump context +struct TDumpContext +{ + TFileStream * pStream; // Pointer to the open stream + LPBYTE pbBufferBegin; // Begin of the dump buffer + LPBYTE pbBufferPtr; // Current dump buffer pointer + LPBYTE pbBufferEnd; // End of the dump buffer + + BYTE DumpBuffer[CASC_DUMP_BUFFER_SIZE]; // Dump buffer +}; + +//----------------------------------------------------------------------------- +// Dump context functions + +TDumpContext * CreateDumpContext(struct _TCascStorage * hs, const TCHAR * szNameFormat); +int dump_print(TDumpContext * dc, const char * szFormat, ...); +int dump_close(TDumpContext * dc); + +#endif // __DUMP_CONTEXT_H__ diff --git a/dep/CascLib/src/common/DynamicArray.cpp b/dep/CascLib/src/common/DynamicArray.cpp new file mode 100644 index 00000000000..e744fbe3912 --- /dev/null +++ b/dep/CascLib/src/common/DynamicArray.cpp @@ -0,0 +1,101 @@ +/*****************************************************************************/ +/* DynamicArray.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of DynamicArray.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +static bool EnlargeArray(PDYNAMIC_ARRAY pArray, size_t NewItemCount) +{ + char * NewItemArray; + size_t ItemCountMax; + + // We expect the array to be already allocated + assert(pArray->ItemArray != NULL); + assert(pArray->ItemCountMax != 0); + + // Shall we enlarge the table? + if(NewItemCount > pArray->ItemCountMax) + { + // Calculate new table size + ItemCountMax = pArray->ItemCountMax; + while(ItemCountMax < NewItemCount) + ItemCountMax = ItemCountMax << 1; + + // Allocate new table + NewItemArray = CASC_REALLOC(char, pArray->ItemArray, pArray->ItemSize * ItemCountMax); + if(NewItemArray == NULL) + return false; + + // Set the new table size + pArray->ItemCountMax = ItemCountMax; + pArray->ItemArray = NewItemArray; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Public functions + +int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax) +{ + pArray->ItemArray = CASC_ALLOC(char, (ItemSize * ItemCountMax)); + if(pArray->ItemArray == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + pArray->ItemCountMax = ItemCountMax; + pArray->ItemCount = 0; + pArray->ItemSize = ItemSize; + return ERROR_SUCCESS; +} + +void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount) +{ + char * NewItemPtr; + + // Try to enlarge the buffer, if needed + if(!EnlargeArray(pArray, pArray->ItemCount + NewItemCount)) + return NULL; + NewItemPtr = pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize); + + // Copy the old item(s), if any + if(NewItems != NULL) + memcpy(NewItemPtr, NewItems, (NewItemCount * pArray->ItemSize)); + + // Increment the size of the array + pArray->ItemCount += NewItemCount; + return NewItemPtr; +} + +void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex) +{ + assert(ItemIndex < pArray->ItemCount); + return pArray->ItemArray + (ItemIndex * pArray->ItemSize); +} + +size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr) +{ + char * ArrayItem = (char *)ArrayPtr; + + assert(pArray->ItemArray <= ArrayItem && ArrayItem <= pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize)); + return ((ArrayItem - pArray->ItemArray) / pArray->ItemSize); +} + +void Array_Free(PDYNAMIC_ARRAY pArray) +{ + if(pArray != NULL && pArray->ItemArray != NULL) + { + CASC_FREE(pArray->ItemArray); + } +} diff --git a/dep/CascLib/src/common/DynamicArray.h b/dep/CascLib/src/common/DynamicArray.h new file mode 100644 index 00000000000..11cefacdcc4 --- /dev/null +++ b/dep/CascLib/src/common/DynamicArray.h @@ -0,0 +1,37 @@ +/*****************************************************************************/ +/* DynamicArray.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Common array implementation */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of DynamicArray.h */ +/*****************************************************************************/ + +#ifndef __DYNAMIC_ARRAY_H__ +#define __DYNAMIC_ARRAY_H__ + +//----------------------------------------------------------------------------- +// Structures + +typedef struct _DYNAMIC_ARRAY +{ + char * ItemArray; // Pointer to items + size_t ItemCountMax; // Current number of items + size_t ItemCount; // Total size of the buffer + size_t ItemSize; // Size of the single item + +} DYNAMIC_ARRAY, *PDYNAMIC_ARRAY; + +//----------------------------------------------------------------------------- +// Functions for managing the array + +int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax); +void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount); +void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex); +size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr); +void Array_Free(PDYNAMIC_ARRAY pArray); + +#define Array_Create(pArray, type, ItemCountMax) Array_Create_(pArray, sizeof(type), ItemCountMax) + +#endif // __DYNAMIC_ARRAY__ diff --git a/dep/CascLib/src/common/FileStream.cpp b/dep/CascLib/src/common/FileStream.cpp index 8e541b44fca..ef9cc55d7ea 100644 --- a/dep/CascLib/src/common/FileStream.cpp +++ b/dep/CascLib/src/common/FileStream.cpp @@ -16,7 +16,6 @@ #define __CASCLIB_SELF__ #include "../CascLib.h" #include "../CascCommon.h" -#include "FileStream.h" #ifdef _MSC_VER #pragma comment(lib, "wininet.lib") // Internet functions for HTTP stream diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp index 42131a2bc2c..b9915f0f31c 100644 --- a/dep/CascLib/src/common/ListFile.cpp +++ b/dep/CascLib/src/common/ListFile.cpp @@ -13,176 +13,33 @@ #include "../CascCommon.h" //----------------------------------------------------------------------------- -// Listfile entry structure +// Listfile cache structure -#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer - -typedef bool (*RELOAD_CACHE)(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead); -typedef void (*CLOSE_STREAM)(void * pvCacheContext); - -struct TListFileCache +typedef struct _LISTFILE_CACHE { - RELOAD_CACHE pfnReloadCache; // Function for reloading the cache - CLOSE_STREAM pfnCloseStream; // Function for closing the stream - void * pvCacheContext; // Reload context passed to reload function - char * szMask; // Self-relative pointer to file mask - DWORD dwFileSize; // Total size of the cached file - DWORD dwFilePos; // Position of the cache in the file - BYTE * pBegin; // The begin of the listfile cache - BYTE * pPos; - BYTE * pEnd; // The last character in the file cache + char * pBegin; // The begin of the listfile cache + char * pPos; // Current position in the cache + char * pEnd; // The last character in the file cache - BYTE Buffer[CACHE_BUFFER_SIZE]; -// char MaskBuff[1] // Followed by the name mask (if any) -}; + // Followed by the cache (variable length) + +} LISTFILE_CACHE, *PLISTFILE_CACHE; //----------------------------------------------------------------------------- -// Local functions +// Creating the listfile cache for the given amount of data -static bool ReloadCache_ExternalFile(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead) +static PLISTFILE_CACHE CreateListFileCache(DWORD dwFileSize) { - TFileStream * pStream = (TFileStream *)pvCacheContext; - - return FileStream_Read(pStream, NULL, pbBuffer, dwBytesToRead); -} - -static void CloseStream_ExternalFile(void * pvCacheContext) -{ - TFileStream * pStream = (TFileStream *)pvCacheContext; - - return FileStream_Close(pStream); -} - - -// Reloads the cache. Returns number of characters -// that has been loaded into the cache. -static DWORD ReloadListFileCache(TListFileCache * pCache) -{ - DWORD dwBytesToRead = 0; - - // Only do something if the cache is empty - if(pCache->pPos >= pCache->pEnd) - { - // Move the file position forward - pCache->dwFilePos += CACHE_BUFFER_SIZE; - if(pCache->dwFilePos >= pCache->dwFileSize) - return 0; - - // Get the number of bytes remaining - dwBytesToRead = pCache->dwFileSize - pCache->dwFilePos; - if(dwBytesToRead > CACHE_BUFFER_SIZE) - dwBytesToRead = CACHE_BUFFER_SIZE; - - // Load the next data chunk to the cache - // If we didn't read anything, it might mean that the block - // of the file is not available - // We stop reading the file at this point, because the rest - // of the listfile is unreliable - if(!pCache->pfnReloadCache(pCache->pvCacheContext, pCache->Buffer, dwBytesToRead)) - return 0; - - // Set the buffer pointers - pCache->pBegin = - pCache->pPos = &pCache->Buffer[0]; - pCache->pEnd = pCache->pBegin + dwBytesToRead; - } - - return dwBytesToRead; -} - -static size_t ReadListFileLine(TListFileCache * pCache, char * szLine, size_t nMaxChars) -{ - char * szLineBegin = szLine; - char * szLineEnd = szLine + nMaxChars - 1; - char * szExtraString = NULL; - - // Skip newlines, spaces, tabs and another non-printable stuff - for(;;) - { - // If we need to reload the cache, do it - if(pCache->pPos == pCache->pEnd) - { - if(ReloadListFileCache(pCache) == 0) - break; - } - - // If we found a non-whitespace character, stop - if(pCache->pPos[0] > 0x20) - break; - - // Skip the character - pCache->pPos++; - } - - // Copy the remaining characters - while(szLine < szLineEnd) - { - // If we need to reload the cache, do it now and resume copying - if(pCache->pPos == pCache->pEnd) - { - if(ReloadListFileCache(pCache) == 0) - break; - } - - // If we have found a newline, stop loading - if(pCache->pPos[0] == 0x0D || pCache->pPos[0] == 0x0A) - break; - - // Blizzard listfiles can also contain information about patch: - // Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326) - if(pCache->pPos[0] == '~') - szExtraString = szLine; - - // Copy the character - *szLine++ = *pCache->pPos++; - } - - // Terminate line with zero - *szLine = 0; - - // If there was extra string after the file name, clear it - if(szExtraString != NULL) - { - if(szExtraString[0] == '~' && szExtraString[1] == 'P') - { - szLine = szExtraString; - *szExtraString = 0; - } - } - - // Return the length of the line - return (szLine - szLineBegin); -} - -static TListFileCache * CreateListFileCache(RELOAD_CACHE pfnReloadCache, CLOSE_STREAM pfnCloseStream, void * pvCacheContext, DWORD dwFileSize) -{ - TListFileCache * pCache = NULL; - DWORD dwBytesToRead; + PLISTFILE_CACHE pCache; // Allocate cache for one file block - pCache = (TListFileCache *)CASC_ALLOC(BYTE, sizeof(TListFileCache)); + pCache = (PLISTFILE_CACHE)CASC_ALLOC(BYTE, sizeof(LISTFILE_CACHE) + dwFileSize); if(pCache != NULL) { - // Clear the entire structure - memset(pCache, 0, sizeof(TListFileCache)); - pCache->pfnReloadCache = pfnReloadCache; - pCache->pfnCloseStream = pfnCloseStream; - pCache->pvCacheContext = pvCacheContext; - pCache->dwFileSize = dwFileSize; - - // Load the file cache from the file - dwBytesToRead = CASCLIB_MIN(CACHE_BUFFER_SIZE, dwFileSize); - if(pfnReloadCache(pvCacheContext, pCache->Buffer, dwBytesToRead)) - { - // Allocate pointers - pCache->pBegin = pCache->pPos = &pCache->Buffer[0]; - pCache->pEnd = pCache->pBegin + dwBytesToRead; - } - else - { - ListFile_Free(pCache); - pCache = NULL; - } + // Set the initial pointers + pCache->pBegin = + pCache->pPos = (char *)(pCache + 1); + pCache->pEnd = pCache->pBegin + dwFileSize; } // Return the cache @@ -194,7 +51,7 @@ static TListFileCache * CreateListFileCache(RELOAD_CACHE pfnReloadCache, CLOSE_S void * ListFile_OpenExternal(const TCHAR * szListFile) { - TListFileCache * pCache; + PLISTFILE_CACHE pCache = NULL; TFileStream * pStream; ULONGLONG FileSize = 0; @@ -204,46 +61,135 @@ void * ListFile_OpenExternal(const TCHAR * szListFile) { // Retrieve the size of the external listfile FileStream_GetSize(pStream, &FileSize); - if(0 < FileSize && FileSize <= 0xFFFFFFFF) - { - // Create the cache for the listfile - pCache = CreateListFileCache(ReloadCache_ExternalFile, CloseStream_ExternalFile, pStream, (DWORD)FileSize); + if(0 < FileSize && FileSize <= 0x30000000) + { + // Create the in-memory cache for the entire listfile + // The listfile does not have any data loaded yet + pCache = CreateListFileCache((DWORD)FileSize); if(pCache != NULL) - return pCache; + { + if(!FileStream_Read(pStream, NULL, pCache->pBegin, (DWORD)FileSize)) + { + ListFile_Free(pCache); + pCache = NULL; + } + } } // Close the file stream FileStream_Close(pStream); } - return NULL; + return pCache; +} + +void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer) +{ + PLISTFILE_CACHE pCache = NULL; + + // Create the in-memory cache for the entire listfile + // The listfile does not have any data loaded yet + pCache = CreateListFileCache(cbBuffer); + if(pCache != NULL) + memcpy(pCache->pBegin, pbBuffer, cbBuffer); + + return pCache; +} + +// Performs the MD5-based check on the listfile +bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5) +{ + PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile; + + // Must be at the beginning + assert(pCache->pPos == pCache->pBegin); + + // Verify the MD5 hash for the entire block + return VerifyDataBlockHash(pCache->pBegin, (DWORD)(pCache->pEnd - pCache->pBegin), pbHashMD5); +} + +size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd) +{ + PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile; + char * szExtraString = NULL; + char * szLineBegin; + char * szLineEnd; + + // Skip newlines, spaces, tabs and another non-printable stuff + while(pCache->pPos < pCache->pEnd && pCache->pPos[0] <= 0x20) + pCache->pPos++; + + // Remember the begin of the line + szLineBegin = pCache->pPos; + + // Copy the remaining characters + while(pCache->pPos < pCache->pEnd) + { + // If we have found a newline, stop loading + if(pCache->pPos[0] == 0x0D || pCache->pPos[0] == 0x0A) + break; + + // Blizzard listfiles can also contain information about patch: + // Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326) + if(pCache->pPos[0] == '~') + szExtraString = pCache->pPos; + + // Move the position by one character forward + pCache->pPos++; + } + + // Remember the end of the line + szLineEnd = (szExtraString != NULL && szExtraString[0] == '~' && szExtraString[1] == 'P') ? szExtraString : pCache->pPos; + + // Give the caller the positions of the begin and end of the line + pszLineBegin[0] = szLineBegin; + pszLineEnd[0] = szLineEnd; + return (size_t)(szLineEnd - szLineBegin); +} + +size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars) +{ + const char * szLineBegin = NULL; + const char * szLineEnd = NULL; + size_t nLength; + + // Retrieve the next line + nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd); + + // Check the length + if(nLength > nMaxChars) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + // Copy the line to the user buffer + memcpy(szBuffer, szLineBegin, nLength); + szBuffer[nLength] = 0; + return nLength; } size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars) { - TListFileCache * pCache = (TListFileCache *)pvListFile; size_t nLength = 0; - int nError = ERROR_INVALID_PARAMETER; + int nError = ERROR_SUCCESS; // Check for parameters - if(pCache != NULL) + for(;;) { - for(;;) + // Read the (next) line + nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars); + if(nLength == 0) { - // Read the (next) line - nLength = ReadListFileLine(pCache, szBuffer, nMaxChars); - if(nLength == 0) - { - nError = ERROR_NO_MORE_FILES; - break; - } + nError = ERROR_NO_MORE_FILES; + break; + } - // If some mask entered, check it - if(CheckWildCard(szBuffer, szMask)) - { - nError = ERROR_SUCCESS; - break; - } + // If some mask entered, check it + if(CheckWildCard(szBuffer, szMask)) + { + nError = ERROR_SUCCESS; + break; } } @@ -254,14 +200,9 @@ size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, void ListFile_Free(void * pvListFile) { - TListFileCache * pCache = (TListFileCache *)pvListFile; - - // Valid parameter check - if(pCache != NULL) + if(pvListFile != NULL) { - if(pCache->pfnCloseStream != NULL) - pCache->pfnCloseStream(pCache->pvCacheContext); - CASC_FREE(pCache); + CASC_FREE(pvListFile); } } @@ -293,11 +234,8 @@ static PLISTFILE_MAP ListMap_Create() static PLISTFILE_MAP ListMap_InsertName(PLISTFILE_MAP pListMap, const char * szFileName, size_t nLength) { PLISTFILE_ENTRY pListEntry; - char szFileName2[MAX_PATH+1]; size_t cbToAllocate; size_t cbEntrySize; - uint32_t dwHashHigh = 0; - uint32_t dwHashLow = 0; // Make sure there is enough space in the list map cbEntrySize = sizeof(LISTFILE_ENTRY) + nLength; @@ -314,14 +252,10 @@ static PLISTFILE_MAP ListMap_InsertName(PLISTFILE_MAP pListMap, const char * szF // Get the pointer to the first entry pListEntry = (PLISTFILE_ENTRY)((LPBYTE)(pListMap + 1) + pListMap->cbBuffer); - - // Get the name hash - NormalizeFileName_UpperBkSlash(szFileName2, szFileName, MAX_PATH); - hashlittle2(szFileName2, nLength, &dwHashHigh, &dwHashLow); - - // Calculate the HASH value of the normalized file name - pListEntry->FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; + pListEntry->FileNameHash = CalcFileNameHash(szFileName); pListEntry->cbEntrySize = (DWORD)cbEntrySize; + + // Copy the file name to the entry memcpy(pListEntry->szFileName, szFileName, nLength); pListEntry->szFileName[nLength] = 0; @@ -357,7 +291,7 @@ static PLISTFILE_MAP ListMap_Finish(PLISTFILE_MAP pListMap) pbEntry += pListEntry->cbEntrySize; // Insert the entry to the map - Map_InsertObject(pMap, pListEntry); + Map_InsertObject(pMap, pListEntry, &pListEntry->FileNameHash); } return pListMap; @@ -408,7 +342,7 @@ const char * ListFile_FindName(PLISTFILE_MAP pListMap, ULONGLONG FileNameHash) PLISTFILE_ENTRY pListEntry = NULL; if(pListMap != NULL) - pListEntry = (PLISTFILE_ENTRY)Map_FindObject(pListMap->pNameMap, &FileNameHash); + pListEntry = (PLISTFILE_ENTRY)Map_FindObject(pListMap->pNameMap, &FileNameHash, NULL); return (pListEntry != NULL) ? pListEntry->szFileName : ""; } diff --git a/dep/CascLib/src/common/ListFile.h b/dep/CascLib/src/common/ListFile.h index 9815160e1ea..84bec3ed751 100644 --- a/dep/CascLib/src/common/ListFile.h +++ b/dep/CascLib/src/common/ListFile.h @@ -37,6 +37,10 @@ typedef struct _LISTFILE_MAP // Functions for parsing an external listfile void * ListFile_OpenExternal(const TCHAR * szListFile); +void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer); +bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5); +size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd); +size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars); size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars); void ListFile_Free(void * pvListFile); diff --git a/dep/CascLib/src/common/Map.cpp b/dep/CascLib/src/common/Map.cpp index 70697a158ab..30ae8ea0531 100644 --- a/dep/CascLib/src/common/Map.cpp +++ b/dep/CascLib/src/common/Map.cpp @@ -15,51 +15,82 @@ //----------------------------------------------------------------------------- // Local functions -static DWORD CalcHashIndex(PCASC_MAP pMap, void * pvIdentifier) +// Returns the extension, right after "." +static const char * String_GetExtension(const char * szString) { + const char * szExtension = strrchr(szString, '.'); + return (szExtension != NULL) ? szExtension + 1 : NULL; +} + +static DWORD CalcHashIndex_Key(PCASC_MAP pMap, void * pvKey) +{ + LPBYTE pbKey = (LPBYTE)pvKey; DWORD dwHash = 0x7EEE7EEE; - // Is it a string table? - if(pMap->KeyLength == KEY_LENGTH_STRING) - { - char * szString = (char *)pvIdentifier; + // Construct the hash from the first 8 digits + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[0]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[1]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[2]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[3]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[4]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[5]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[6]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[7]; - for(size_t i = 0; szString[i] != 0; i++) - dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ szString[i]; - } - else - { - LPBYTE pbHash = (LPBYTE)pvIdentifier; + // Return the hash limited by the table size + return (dwHash % pMap->TableSize); +} - // Construct the hash from the first 4 digits - for(size_t i = 0; i < pMap->KeyLength; i++) - dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbHash[i]; +static DWORD CalcHashIndex_String(PCASC_MAP pMap, const char * szString, const char * szStringEnd) +{ + LPBYTE pbKeyEnd = (LPBYTE)szStringEnd; + LPBYTE pbKey = (LPBYTE)szString; + DWORD dwHash = 0x7EEE7EEE; + + // Hash the string itself + while(pbKey < pbKeyEnd) + { + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ AsciiToUpperTable_BkSlash[pbKey[0]]; + pbKey++; } // Return the hash limited by the table size return (dwHash % pMap->TableSize); } -static bool CompareIdentifier(PCASC_MAP pMap, void * pvTableEntry, void * pvIdentifier) +static bool CompareObject_Key(PCASC_MAP pMap, void * pvObject, void * pvKey) { - // Is it a string table? - if(pMap->KeyLength == KEY_LENGTH_STRING) - { - char * szTableEntry = (char *)pvTableEntry; - char * szIdentifier = (char *)pvIdentifier; + LPBYTE pbObjectKey = (LPBYTE)pvObject + pMap->KeyOffset; - return (strcmp(szTableEntry, szIdentifier) == 0); - } - else + return (memcmp(pbObjectKey, pvKey, pMap->KeyLength) == 0); +} + +static bool CompareObject_String( + PCASC_MAP pMap, + const char * szExistingString, + const char * szString, + const char * szStringEnd) +{ + // Keep compiler happy + CASCLIB_UNUSED(pMap); + + // Compare the whole part, case insensitive + while(szString < szStringEnd) { - return (memcmp(pvTableEntry, pvIdentifier, pMap->KeyLength) == 0); + if(AsciiToUpperTable_BkSlash[*szExistingString] != AsciiToUpperTable_BkSlash[*szString]) + return false; + + szExistingString++; + szString++; } + + return true; } //----------------------------------------------------------------------------- // Public functions -PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset) +PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset) { PCASC_MAP pMap; size_t cbToAllocate; @@ -76,7 +107,7 @@ PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset) memset(pMap, 0, cbToAllocate); pMap->KeyLength = dwKeyLength; pMap->TableSize = dwTableSize; - pMap->MemberOffset = dwMemberOffset; + pMap->KeyOffset = dwKeyOffset; } // Return the allocated map @@ -104,24 +135,28 @@ size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray) return pMap->ItemCount; } -void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier) +void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex) { - void * pvTableEntry; + void * pvObject; DWORD dwHashIndex; // Verify pointer to the map if(pMap != NULL) { // Construct the main index - dwHashIndex = CalcHashIndex(pMap, pvIdentifier); + dwHashIndex = CalcHashIndex_Key(pMap, pvKey); while(pMap->HashTable[dwHashIndex] != NULL) { // Get the pointer at that position - pvTableEntry = pMap->HashTable[dwHashIndex]; + pvObject = pMap->HashTable[dwHashIndex]; // Compare the hash - if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier)) - return ((LPBYTE)pvTableEntry - pMap->MemberOffset); + if(CompareObject_Key(pMap, pvObject, pvKey)) + { + if(PtrIndex != NULL) + PtrIndex[0] = dwHashIndex; + return pvObject; + } // Move to the next entry dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; @@ -132,9 +167,9 @@ void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier) return NULL; } -bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) +bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey) { - void * pvTableEntry; + void * pvExistingObject; DWORD dwHashIndex; // Verify pointer to the map @@ -145,14 +180,14 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) return false; // Construct the hash index - dwHashIndex = CalcHashIndex(pMap, pvIdentifier); + dwHashIndex = CalcHashIndex_Key(pMap, pvKey); while(pMap->HashTable[dwHashIndex] != NULL) { // Get the pointer at that position - pvTableEntry = pMap->HashTable[dwHashIndex]; + pvExistingObject = pMap->HashTable[dwHashIndex]; // Check if hash being inserted conflicts with an existing hash - if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier)) + if(CompareObject_Key(pMap, pvExistingObject, pvKey)) return false; // Move to the next entry @@ -160,7 +195,7 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) } // Insert at that position - pMap->HashTable[dwHashIndex] = pvIdentifier; + pMap->HashTable[dwHashIndex] = pvNewObject; pMap->ItemCount++; return true; } @@ -169,6 +204,78 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) return false; } +bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension) +{ + const char * szExistingString; + const char * szStringEnd = NULL; + DWORD dwHashIndex; + + // Verify pointer to the map + if(pMap != NULL) + { + // Limit check + if((pMap->ItemCount + 1) >= pMap->TableSize) + return false; + + // Retrieve the length of the string without extension + if(bCutExtension) + szStringEnd = String_GetExtension(szString); + if(szStringEnd == NULL) + szStringEnd = szString + strlen(szString); + + // Construct the hash index + dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd); + while(pMap->HashTable[dwHashIndex] != NULL) + { + // Get the pointer at that position + szExistingString = (const char *)pMap->HashTable[dwHashIndex]; + + // Check if hash being inserted conflicts with an existing hash + if(CompareObject_String(pMap, szExistingString, szString, szStringEnd)) + return false; + + // Move to the next entry + dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; + } + + // Insert at that position + pMap->HashTable[dwHashIndex] = (void *)szString; + pMap->ItemCount++; + return true; + } + + // Failed + return false; +} + +const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd) +{ + const char * szExistingString; + DWORD dwHashIndex; + + // Verify pointer to the map + if(pMap != NULL) + { + // Construct the main index + dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd); + while(pMap->HashTable[dwHashIndex] != NULL) + { + // Get the pointer at that position + szExistingString = (const char *)pMap->HashTable[dwHashIndex]; + + // Compare the hash + if(CompareObject_String(pMap, szExistingString, szString, szStringEnd)) + return szExistingString; + + // Move to the next entry + dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; + } + } + + // Not found, sorry + return NULL; +} + void Map_Free(PCASC_MAP pMap) { if(pMap != NULL) diff --git a/dep/CascLib/src/common/Map.h b/dep/CascLib/src/common/Map.h index 40ea4238b81..7b0c1321e6c 100644 --- a/dep/CascLib/src/common/Map.h +++ b/dep/CascLib/src/common/Map.h @@ -20,20 +20,23 @@ typedef struct _CASC_MAP { size_t TableSize; size_t ItemCount; // Number of items in the map - size_t MemberOffset; // How far is the hash from the begin of the structure (in bytes) + size_t KeyOffset; // How far is the hash from the begin of the structure (in bytes) size_t KeyLength; // Length of the hash key void * HashTable[1]; // Pointer table } CASC_MAP, *PCASC_MAP; +typedef bool (*MAP_COMPARE)(PCASC_MAP pMap, void * pvObject, void * pvKey); + //----------------------------------------------------------------------------- // Functions -PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset); +PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset); size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray); -void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier); -bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier); -void Map_Sort(PCASC_MAP pMap); +void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex); +bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey); +const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd); +bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension); void Map_Free(PCASC_MAP pMap); #endif // __HASHTOPTR_H__ diff --git a/dep/CascLib/src/common/RootHandler.cpp b/dep/CascLib/src/common/RootHandler.cpp new file mode 100644 index 00000000000..df9953f3ea6 --- /dev/null +++ b/dep/CascLib/src/common/RootHandler.cpp @@ -0,0 +1,78 @@ +/*****************************************************************************/ +/* RootHandler.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Implementation of root handler */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Common support + +int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey) +{ + if(pRootHandler == NULL || pRootHandler->Insert == NULL) + return ERROR_NOT_SUPPORTED; + + return pRootHandler->Insert(pRootHandler, szFileName, pbEncodingKey); +} + +LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags) +{ + // Check if the root structure is valid at all + if(pRootHandler == NULL) + return NULL; + + return pRootHandler->Search(pRootHandler, pSearch, PtrFileSize, PtrLocaleFlags); +} + +void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch) +{ + // Check if the root structure is valid at all + if(pRootHandler != NULL) + { + pRootHandler->EndSearch(pRootHandler, pSearch); + } +} + +LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName) +{ + // Check if the root structure is valid at all + if(pRootHandler == NULL) + return NULL; + + return pRootHandler->GetKey(pRootHandler, szFileName); +} + +void RootHandler_Dump(TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel) +{ + TDumpContext * dc; + + // Only if the ROOT provider suports the dump option + if(hs->pRootHandler != NULL && hs->pRootHandler->Dump != NULL) + { + // Create the dump file + dc = CreateDumpContext(hs, szNameFormat); + if(dc != NULL) + { + // Dump the content and close the file + hs->pRootHandler->Dump(hs, dc, pbRootHandler, cbRootHandler, szListFile, nDumpLevel); + dump_close(dc); + } + } +} + +void RootHandler_Close(TRootHandler * pRootHandler) +{ + // Check if the root structure is allocated at all + if(pRootHandler != NULL) + { + pRootHandler->Close(pRootHandler); + } +} diff --git a/dep/CascLib/src/common/RootHandler.h b/dep/CascLib/src/common/RootHandler.h new file mode 100644 index 00000000000..e1869e351cc --- /dev/null +++ b/dep/CascLib/src/common/RootHandler.h @@ -0,0 +1,88 @@ +/*****************************************************************************/ +/* RootHandler.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Interface for root handlers */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __ROOT_HANDLER_H__ +#define __ROOT_HANDLER_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define CASC_MNDX_ROOT_SIGNATURE 0x58444E4D // 'MNDX' +#define CASC_DIABLO3_ROOT_SIGNATURE 0x8007D0C4 +#define CASC_OVERWATCH_ROOT_SIGNATURE 0x35444D23 // '#MD5' + +#define ROOT_FLAG_HAS_NAMES 0x00000001 // The root file contains file names + +#define DUMP_LEVEL_ROOT_FILE 1 // Dump root file +#define DUMP_LEVEL_ENCODING_FILE 2 // Dump root file + encoding file +#define DUMP_LEVEL_INDEX_ENTRIES 3 // Dump root file + encoding file + index entries + +//----------------------------------------------------------------------------- +// Root file function prototypes + +typedef int (*ROOT_INSERT)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + const char * szFileName, // Pointer to the file name + LPBYTE pbEncodingKey // Pointer to the encoding key of the file name + ); + +typedef LPBYTE (*ROOT_SEARCH)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + struct _TCascSearch * pSearch, // Pointer to the initialized search structure + PDWORD PtrFileSize, // Pointer to receive file size (optional) + PDWORD PtrLocaleFlags // Pointer to receive locale flags (optional) + ); + +typedef void (*ROOT_ENDSEARCH)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + struct _TCascSearch * pSearch // Pointer to the initialized search structure + ); + +typedef LPBYTE (*ROOT_GETKEY)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + const char * szFileName // Pointer to the name of a file + ); + +typedef void (*ROOT_DUMP)( + struct _TCascStorage * hs, // Pointer to the open storage + TDumpContext * dc, // Opened dump context + LPBYTE pbRootHandler, // Pointer to the loaded ROOT file + DWORD cbRootHandler, // Length of the loaded ROOT file + const TCHAR * szListFile, + int nDumpLevel + ); + +typedef void (*ROOT_CLOSE)( + struct TRootHandler * pRootHandler // Pointer to an initialized root handler + ); + +struct TRootHandler +{ + ROOT_INSERT Insert; // Inserts an existing file name + ROOT_SEARCH Search; // Performs the root file search + ROOT_ENDSEARCH EndSearch; // Performs cleanup after searching + ROOT_GETKEY GetKey; // Retrieves encoding key for a file name + ROOT_DUMP Dump; + ROOT_CLOSE Close; // Closing the root file + + DWORD dwRootFlags; // Root flags - see the ROOT_FLAG_XXX +}; + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey); +LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags); +void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch); +LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName); +void RootHandler_Dump(struct _TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel); +void RootHandler_Close(TRootHandler * pRootHandler); + +#endif // __ROOT_HANDLER_H__ diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c index 537516d80d9..1cd875f5260 100644 --- a/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c +++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c @@ -19,8 +19,8 @@ #if (ARGTYPE == 0) void crypt_argchk(char *v, char *s, int d) { - fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n", - v, d, s); + fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n", + v, d, s); (void)raise(SIGABRT); } #endif From b9f1dffa14fbd340634b035e05e59063d0028bfa Mon Sep 17 00:00:00 2001 From: Carbenium Date: Mon, 8 Feb 2016 22:33:58 +0100 Subject: [PATCH 47/79] Core/PacketIO: Updated and enabled SMSG_CHAT_PLAYER_AMBIGUOUS --- src/server/game/Handlers/ChatHandler.cpp | 6 +++--- src/server/game/Server/Packets/ChatPackets.cpp | 8 ++++++++ src/server/game/Server/Packets/ChatPackets.h | 10 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 462ed8051be..2e91381b6e4 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -653,9 +653,9 @@ void WorldSession::SendChatPlayerNotfoundNotice(std::string const& name) void WorldSession::SendPlayerAmbiguousNotice(std::string const& name) { - WorldPacket data(SMSG_CHAT_PLAYER_AMBIGUOUS, name.size()+1); - data << name; - SendPacket(&data); + WorldPackets::Chat::ChatPlayerAmbiguous packet; + packet.Name = name; + SendPacket(packet.Write()); } void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp index be923c1b847..cfaa986eaaa 100644 --- a/src/server/game/Server/Packets/ChatPackets.cpp +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -271,3 +271,11 @@ void WorldPackets::Chat::ChatReportIgnored::Read() _worldPacket >> IgnoredGUID; _worldPacket >> Reason; } + +WorldPacket const * WorldPackets::Chat::ChatPlayerAmbiguous::Write() +{ + _worldPacket.WriteBits(Name.length(), 9); + _worldPacket.WriteString(Name); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index 6f13419666e..e981feddb79 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -300,6 +300,16 @@ namespace WorldPackets ObjectGuid IgnoredGUID; uint8 Reason = 0; }; + + class ChatPlayerAmbiguous : ServerPacket + { + public: + ChatPlayerAmbiguous() : ServerPacket(SMSG_CHAT_PLAYER_AMBIGUOUS, 2 + Name.length()) { } + + WorldPacket const* Write() override; + + std::string Name; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7adadcffeb9..15048b52537 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -970,7 +970,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_IGNORED_ACCOUNT_MUTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_IS_DOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_NOT_IN_PARTY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOTFOUND, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RECONNECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From 4f78efd4633f79285f176b61367a067b2cd90e2b Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 9 Feb 2016 00:14:58 +0100 Subject: [PATCH 48/79] Core/Maps: Parse MFBO adt chunk to properly handle height where player counts as falling under the map * This fixes the height at which player is instantly killed when falling from The Frozen Throne * Set PLAYER_FLAGS_IS_OUT_OF_BOUNDS on players under the map to enable release spirit button while still falling Note: Extracting new maps is required --- dep/PackageList.txt | 2 +- src/server/game/DataStores/DBCStructure.h | 3 - src/server/game/Entities/Player/Player.cpp | 7 +- src/server/game/Handlers/MovementHandler.cpp | 3 +- src/server/game/Maps/Map.cpp | 62 ++++++++--- src/server/game/Maps/Map.h | 11 +- src/tools/map_extractor/CMakeLists.txt | 2 + src/tools/map_extractor/System.cpp | 107 +++++++++++++++++-- src/tools/map_extractor/adt.h | 16 +++ src/tools/map_extractor/loadlib.cpp | 3 +- src/tools/mmaps_generator/TerrainBuilder.cpp | 2 +- 11 files changed, 187 insertions(+), 31 deletions(-) diff --git a/dep/PackageList.txt b/dep/PackageList.txt index f7ae2c36e3f..5ad9cef5982 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -46,7 +46,7 @@ recastnavigation (Recast is state of the art navigation mesh construction toolse CascLib (An open-source implementation of library for reading CASC storage from Blizzard games since 2014) https://github.com/ladislav-zezula/CascLib - Version: d1d617d4feecd39bae049e19b0e217a1a84bedc6 + Version: 919a2d670cb749c501ee15887a88e9b9a538961b zmqpp (C++ binding for 0mq/zmq is a 'high-level' library that hides most of the c-style interface core 0mq provides.) https://github.com/zeromq/zmqpp diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index f051184b7e7..ec334fb3b8f 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -34,9 +34,6 @@ struct AnimKitEntry //uint32 LowDefAnimKitID; // 3 }; -// Temporary define until max depth is found somewhere (adt?) -#define MAX_MAP_DEPTH -5000 - struct AreaTableEntry { uint32 ID; // 0 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b3007affd83..7e30a125827 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4235,6 +4235,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) // remove death flag + set aura SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); // This must be called always even on Players with race != RACE_NIGHTELF in case of faction change RemoveAurasDueToSpell(20584); // RACE_NIGHTELF speed bonuses @@ -4635,7 +4636,7 @@ void Player::RepopAtGraveyard() AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId()); // Such zones are considered unreachable as a ghost and the player must be automatically revived - if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < MAX_MAP_DEPTH) + if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) { ResurrectPlayer(0.5f); SpawnCorpseBones(); @@ -4670,8 +4671,10 @@ void Player::RepopAtGraveyard() GetSession()->SendPacket(packet.Write()); } } - else if (GetPositionZ() < MAX_MAP_DEPTH) + else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); } bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) const diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index fb391229340..3ab9f683dea 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -382,7 +382,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); - if (movementInfo.pos.GetPositionZ() < MAX_MAP_DEPTH) + if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY())) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { @@ -391,6 +391,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov /// @todo discard movement packets after the player is rooted if (plrMover->IsAlive()) { + plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 510d678821b..304f1ef7c2a 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -40,7 +40,7 @@ #include "Weather.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','6'} }; +u_map_magic MapVersionMagic = { {'v','1','.','7'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1655,13 +1655,15 @@ GridMap::GridMap() _flags = 0; // Area data _gridArea = 0; - _areaMap = NULL; + _areaMap = nullptr; // Height level data _gridHeight = INVALID_HEIGHT; _gridGetHeight = &GridMap::getHeightFromFlat; _gridIntHeightMultiplier = 0; - m_V9 = NULL; - m_V8 = NULL; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; // Liquid data _liquidType = 0; _liquidOffX = 0; @@ -1669,9 +1671,9 @@ GridMap::GridMap() _liquidWidth = 0; _liquidHeight = 0; _liquidLevel = INVALID_HEIGHT; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; } GridMap::~GridMap() @@ -1734,15 +1736,19 @@ void GridMap::unloadData() delete[] _areaMap; delete[] m_V9; delete[] m_V8; + delete[] _maxHeight; + delete[] _minHeight; delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; - _areaMap = NULL; - m_V9 = NULL; - m_V8 = NULL; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _areaMap = nullptr; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; _gridGetHeight = &GridMap::getHeightFromFlat; } @@ -1807,6 +1813,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) } else _gridGetHeight = &GridMap::getHeightFromFlat; + + if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + _maxHeight = new float[16 * 16]; + _minHeight = new float[16 * 16]; + if (fread(_maxHeight, sizeof(float), 16 * 16, in) != 16 * 16 || + fread(_minHeight, sizeof(float), 16 * 16, in) != 16 * 16) + return false; + } + return true; } @@ -2077,6 +2093,18 @@ float GridMap::getHeightFromUint16(float x, float y) const return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight; } +float GridMap::getMinHeight(float x, float y) const +{ + if (!_minHeight) + return -500.0f; + + x = 16 * (CENTER_GRID_ID - x / SIZE_OF_GRIDS); + y = 16 * (CENTER_GRID_ID - y / SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return _minHeight[lx * 16 + ly]; +} + float GridMap::getLiquidLevel(float x, float y) const { if (!_liquidMap) @@ -2277,6 +2305,14 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float return mapHeight; // explicitly use map data } +float Map::GetMinHeight(float x, float y) const +{ + if (GridMap const* grid = const_cast(this)->GetGrid(x, y)) + return grid->getMinHeight(x, y); + + return -500.0f; +} + inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) { bool outdoor = true; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index bf8770cfd30..bf29a257419 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -100,9 +100,10 @@ struct map_areaHeader uint16 gridArea; }; -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -168,6 +169,8 @@ class GridMap uint16* m_uint16_V8; uint8* m_uint8_V8; }; + float* _maxHeight; + float* _minHeight; // Height level data float _gridHeight; float _gridIntHeightMultiplier; @@ -208,6 +211,7 @@ public: uint16 getArea(float x, float y) const; inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} + float getMinHeight(float x, float y) const; float getLiquidLevel(float x, float y) const; uint8 getTerrainType(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); @@ -329,6 +333,7 @@ class Map : public GridRefManager // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; + float GetMinHeight(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index 32fccaa2038..58435a51121 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -14,6 +14,7 @@ file(GLOB_RECURSE sources *.cpp *.h) include_directories ( ${CMAKE_SOURCE_DIR}/dep/CascLib/src ${CMAKE_SOURCE_DIR}/dep/cppformat + ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/src/common ${CMAKE_SOURCE_DIR}/src/common/Utilities ${CMAKE_SOURCE_DIR}/src/server/shared @@ -31,6 +32,7 @@ target_link_libraries(mapextractor casc common format + g3dlib ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 2d36df68df1..a079ab42367 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -40,6 +40,8 @@ #include "adt.h" #include "wdt.h" +#include + namespace { const char* HumanReadableCASCError(int error) @@ -351,7 +353,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.6"; +static char const* MAP_VERSION_MAGIC = "v1.7"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -380,9 +382,10 @@ struct map_areaHeader uint16 gridArea; }; -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -442,14 +445,17 @@ bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8]; -bool TransformToHighRes(uint16 holes, uint8 hiResHoles[8]) +float flight_box_max[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +float flight_box_min[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + +bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8]) { for (uint8 i = 0; i < 8; i++) { for (uint8 j = 0; j < 8; j++) { int32 holeIdxL = (i / 2) * 4 + (j / 2); - if (((holes >> holeIdxL) & 1) == 1) + if (((lowResHoles >> holeIdxL) & 1) == 1) hiResHoles[i] |= (1 << j); } } @@ -482,6 +488,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int memset(holes, 0, sizeof(holes)); bool hasHoles = false; + bool hasFlightBox = false; for (std::multimap::const_iterator itr = adt.chunks.lower_bound("MCNK"); itr != adt.chunks.upper_bound("MCNK"); ++itr) { @@ -696,6 +703,82 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } } + if (FileChunk* chunk = adt.GetChunk("MFBO")) + { + static uint32 const indices[] = + { + 3, 0, 4, + 0, 1, 4, + 1, 2, 4, + 2, 5, 4, + 5, 8, 4, + 8, 7, 4, + 7, 6, 4, + 6, 3, 4 + }; + + static float const boundGridCoords[] = + { + 0.0f, 0.0f, + 0.0f, -266.66666f, + 0.0f, -533.33331f, + -266.66666f, 0.0f, + -266.66666f, -266.66666f, + -266.66666f, -533.33331f, + -533.33331f, 0.0f, + -533.33331f, -266.66666f, + -533.33331f, -533.33331f + }; + + adt_MFBO* mfbo = chunk->As(); + for (int gy = 0; gy < ADT_CELLS_PER_GRID; ++gy) + { + for (int gx = 0; gx < ADT_CELLS_PER_GRID; ++gx) + { + int32 quarterIndex = 0; + if (gy > ADT_CELLS_PER_GRID / 2) + { + if (gx > ADT_CELLS_PER_GRID / 2) + { + quarterIndex = 4 + gx < gy; + } + else + quarterIndex = 2; + } + else if (gx > ADT_CELLS_PER_GRID / 2) + { + quarterIndex = 7; + } + else + quarterIndex = gx > gy; + + quarterIndex *= 3; + G3D::Plane planeMax( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 2]]) + ); + + G3D::Plane planeMin( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 2]]) + ); + + auto non_nan_distance = [](G3D::Plane const& plane){ + auto d = plane.distance(G3D::Vector3(0.0f, 0.0f, 0.0f)); + assert(!G3D::isNaN(d)); + return d; + }; + + flight_box_max[gy][gx] = non_nan_distance(planeMax); + flight_box_min[gy][gx] = non_nan_distance(planeMin); + } + } + + hasFlightBox = true; + } + //============================================ // Try pack area data //============================================ @@ -787,6 +870,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit) heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT; + if (hasFlightBox) + { + heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS; + map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min); + } + // Try store as packed in uint16 or uint8 values if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT)) { @@ -958,6 +1047,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } } + if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + outFile.write(reinterpret_cast(flight_box_max), sizeof(flight_box_max)); + outFile.write(reinterpret_cast(flight_box_min), sizeof(flight_box_min)); + } + // Store liquid data if need if (map.liquidMapOffset) { diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index 0c3b3780c16..bb6980507b7 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -219,6 +219,22 @@ struct adt_MH2O }; +struct adt_MFBO +{ + union + { + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + struct plane + { + int16 coords[9]; + }; + plane max; + plane min; +}; + #pragma pack(pop) #endif diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp index 39bbe5b1412..067683577f4 100644 --- a/src/tools/map_extractor/loadlib.cpp +++ b/src/tools/map_extractor/loadlib.cpp @@ -96,7 +96,8 @@ u_map_fcc InterestingChunks[] = { { 'K', 'N', 'C', 'M' } }, { { 'T', 'V', 'C', 'M' } }, { { 'O', 'M', 'W', 'M' } }, - { { 'Q', 'L', 'C', 'M' } } + { { 'Q', 'L', 'C', 'M' } }, + { { 'O', 'B', 'F', 'M' } } }; bool IsInterestingChunk(u_map_fcc const& fcc) diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 33832f8986d..c4a32882c1d 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.6"; + char const* MAP_VERSION_MAGIC = "v1.7"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } From f8de1ab354fccfbeab36755eb5e471c88446fc6b Mon Sep 17 00:00:00 2001 From: Carbenium Date: Tue, 9 Feb 2016 23:58:22 +0100 Subject: [PATCH 49/79] Core/PacketIO: Updated and enabled SMSG_CHAT_RESTRICTED --- src/server/game/Handlers/ChatHandler.cpp | 8 ++++---- src/server/game/Server/Packets/ChatPackets.cpp | 9 ++++++++- src/server/game/Server/Packets/ChatPackets.h | 14 ++++++++++++-- src/server/game/Server/Packets/SpellPackets.cpp | 2 +- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 11 ++++++----- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 2e91381b6e4..d96eb9b551e 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -658,9 +658,9 @@ void WorldSession::SendPlayerAmbiguousNotice(std::string const& name) SendPacket(packet.Write()); } -void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) +void WorldSession::SendChatRestricted(ChatRestrictionType restriction) { - WorldPacket data(SMSG_CHAT_RESTRICTED, 1); - data << uint8(restriction); - SendPacket(&data); + WorldPackets::Chat::ChatRestricted packet; + packet.Reason = restriction; + SendPacket(packet.Write()); } diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp index cfaa986eaaa..612b46ca919 100644 --- a/src/server/game/Server/Packets/ChatPackets.cpp +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -272,10 +272,17 @@ void WorldPackets::Chat::ChatReportIgnored::Read() _worldPacket >> Reason; } -WorldPacket const * WorldPackets::Chat::ChatPlayerAmbiguous::Write() +WorldPacket const* WorldPackets::Chat::ChatPlayerAmbiguous::Write() { _worldPacket.WriteBits(Name.length(), 9); _worldPacket.WriteString(Name); return &_worldPacket; } + +WorldPacket const* WorldPackets::Chat::ChatRestricted::Write() +{ + _worldPacket << uint8(Reason); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index e981feddb79..277892c1495 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -301,15 +301,25 @@ namespace WorldPackets uint8 Reason = 0; }; - class ChatPlayerAmbiguous : ServerPacket + class ChatPlayerAmbiguous final : public ServerPacket { public: - ChatPlayerAmbiguous() : ServerPacket(SMSG_CHAT_PLAYER_AMBIGUOUS, 2 + Name.length()) { } + ChatPlayerAmbiguous() : ServerPacket(SMSG_CHAT_PLAYER_AMBIGUOUS, 2 + Name.length()) { } WorldPacket const* Write() override; std::string Name; }; + + class ChatRestricted final : public ServerPacket + { + public: + ChatRestricted() : ServerPacket(SMSG_CHAT_RESTRICTED, 1) { } + + WorldPacket const* Write() override; + + uint8 Reason = 0; + }; } } diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index f1cb69c32db..3eea414f024 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -808,7 +808,7 @@ void WorldPackets::Spells::MissileTrajectoryCollision::Read() _worldPacket >> CollisionPos; } -WorldPacket const * WorldPackets::Spells::NotifyMissileTrajectoryCollision::Write() +WorldPacket const* WorldPackets::Spells::NotifyMissileTrajectoryCollision::Write() { _worldPacket << Caster; _worldPacket << uint8(CastID); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 15048b52537..b12948d7337 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -973,7 +973,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOTFOUND, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RECONNECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHEAT_IGNORE_DIMISHING_RETURNS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHECK_WARGAME_ENTRY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index efa1f4151ca..857988313d0 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -787,10 +787,11 @@ enum BFLeaveReason enum ChatRestrictionType { - ERR_CHAT_RESTRICTED = 0, - ERR_CHAT_THROTTLED = 1, - ERR_USER_SQUELCHED = 2, - ERR_YELL_RESTRICTED = 3 + ERR_CHAT_RESTRICTED = 0, + ERR_CHAT_THROTTLED = 1, + ERR_USER_SQUELCHED = 2, + ERR_YELL_RESTRICTED = 3, + ERR_CHAT_RAID_RESTRICTED = 4 }; enum CharterTypes @@ -1438,7 +1439,7 @@ class WorldSession void HandleChatMessageEmoteOpcode(WorldPackets::Chat::ChatMessageEmote& chatMessageEmote); void SendChatPlayerNotfoundNotice(std::string const& name); void SendPlayerAmbiguousNotice(std::string const& name); - void SendChatRestrictedNotice(ChatRestrictionType restriction); + void SendChatRestricted(ChatRestrictionType restriction); void HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet); void HandleChatIgnoredOpcode(WorldPackets::Chat::ChatReportIgnored& chatReportIgnored); From 9ddd596899e901b5644df200b7f2c31a780cfb11 Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Wed, 10 Feb 2016 02:47:55 -0200 Subject: [PATCH 50/79] Core/GameObject: Also send EventInform() calls for GAMEOBJECT_TYPE_CAMERA - This allows object and zone AI to process events called by camera objects as well (previously only possible through event_scripts) Closes #16506 (cherry-picked from commit 6904073c9cf2d6d1291bf976b8efff55edae74bc) --- src/server/game/Entities/GameObject/GameObject.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 02176cca13c..e27e59b723d 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1442,7 +1442,10 @@ void GameObject::Use(Unit* user) player->SendCinematicStart(info->camera.camera); if (info->camera.eventID) + { GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this); + EventInform(info->camera.eventID, user); + } return; } From c559a4762dda460f9181cfc22af9adb8a949f635 Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Wed, 10 Feb 2016 03:10:35 -0200 Subject: [PATCH 51/79] Scripts/Magister's Terrace: Script Kalecgos' appearance after using the Scryer's Orb - Added missing waypoints, spells, emotes, proper timing... and prevent him from being summoned multiple times Closes #13208, #16522 (cherry picked from 6a56ede1796b25cb66facc289e75cc0deceabfdd) --- sql/updates/world/2016_02_10_00_world.sql | 18 ++++ .../instance_magisters_terrace.cpp | 27 ++++++ .../MagistersTerrace/magisters_terrace.cpp | 93 +++++++++---------- .../MagistersTerrace/magisters_terrace.h | 19 +++- 4 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 sql/updates/world/2016_02_10_00_world.sql diff --git a/sql/updates/world/2016_02_10_00_world.sql b/sql/updates/world/2016_02_10_00_world.sql new file mode 100644 index 00000000000..872861b08dc --- /dev/null +++ b/sql/updates/world/2016_02_10_00_world.sql @@ -0,0 +1,18 @@ +-- Pathing for Kalecgos Entry: 24844 'TDB FORMAT' +SET @NPC := 24844; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,163.9735,-398.0906,2.083333,0,0,0,0,100,0), -- 16:16:43 +(@PATH,2,164.3802,-397.1771,2.083333,0,0,0,0,100,0), -- 16:16:43 +(@PATH,3,162.7923,-386.1964,15.67094,0,0,0,0,100,0), -- 16:16:43 +(@PATH,4,151.5555,-345.349,5.92646,0,0,0,0,100,0), -- 16:16:43 +(@PATH,5,162.2416,-299.8032,-5.436685,0,0,0,0,100,0), -- 16:16:43 +(@PATH,6,199.7482,-272.3315,-7.186677,0,0,0,0,100,0), -- 16:16:43 +(@PATH,7,199.7482,-272.3315,-7.186677,0,0,0,0,100,0), -- 16:16:43 +(@PATH,8,199.7482,-272.3315,-7.186677,0.06981317,0,0,0,100,0); -- 16:16:54 +-- 0x1C2F2C4920184300001F1D000038BF6E .go 163.9735 -398.0906 2.083333 + +DELETE FROM `creature_text` WHERE `entry` = 24844 AND `groupid` = 0; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(24844, 0, 0, 'Be still, mortals, and hearken to my words.', 14, 0, 100, 0, 0, 0, 23936, 3, 'Kalecgos - SAY_KALECGOS_SPAWN'); diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index c726461044b..cefbeb94924 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -36,6 +36,8 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END }; +Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f }; + class instance_magisters_terrace : public InstanceMapScript { public: @@ -93,6 +95,10 @@ class instance_magisters_terrace : public InstanceMapScript case NPC_DELRISSA: DelrissaGUID = creature->GetGUID(); break; + case NPC_KALECGOS: + case NPC_HUMAN_KALECGOS: + KalecgosGUID = creature->GetGUID(); + break; default: break; } @@ -139,6 +145,25 @@ class instance_magisters_terrace : public InstanceMapScript } } + void ProcessEvent(WorldObject* obj, uint32 eventId) override + { + if (eventId == EVENT_SPAWN_KALECGOS) + if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && events.Empty()) + events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1)); + } + + void Update(uint32 diff) override + { + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_SPAWN_KALECGOS) + if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos)) + { + kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false); + kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN); + } + } + bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) @@ -177,10 +202,12 @@ class instance_magisters_terrace : public InstanceMapScript } protected: + EventMap events; ObjectGuid SelinGUID; ObjectGuid DelrissaGUID; ObjectGuid KaelStatue[2]; ObjectGuid EscapeOrbGUID; + ObjectGuid KalecgosGUID; uint32 DelrissaDeathCount; }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp index e216a024468..82bb61c5afd 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp @@ -31,7 +31,7 @@ EndContentData */ #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "Player.h" -#include "SpellInfo.h" +#include "magisters_terrace.h" /*###### ## npc_kalecgos @@ -39,30 +39,29 @@ EndContentData */ enum Spells { - SPELL_TRANSFORM_TO_KAEL = 44670, + SPELL_KALECGOS_TRANSFORM = 44670, + SPELL_TRANSFORM_VISUAL = 24085, + SPELL_CAMERA_SHAKE = 44762, SPELL_ORB_KILL_CREDIT = 46307 }; -enum Creatures +enum MovementPoints { - NPC_KAEL = 24848 //human form entry + POINT_ID_PREPARE_LANDING = 6 }; -enum Misc +enum EventIds { - POINT_ID_LAND = 1 + EVENT_KALECGOS_TRANSFORM = 1, + EVENT_KALECGOS_LANDING = 2 }; -const float afKaelLandPoint[] = {225.045f, -276.236f, -5.434f}; - #define GOSSIP_ITEM_KAEL_1 "Who are you?" #define GOSSIP_ITEM_KAEL_2 "What can we do to assist you?" #define GOSSIP_ITEM_KAEL_3 "What brings you to the Sunwell?" #define GOSSIP_ITEM_KAEL_4 "You're not alone here?" #define GOSSIP_ITEM_KAEL_5 "What would Kil'jaeden want with a mortal woman?" -// This is friendly keal that appear after used Orb. -// If we assume DB handle summon, summon appear somewhere outside the platform where Orb is class npc_kalecgos : public CreatureScript { public: @@ -115,52 +114,46 @@ public: struct npc_kalecgosAI : public ScriptedAI { - npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) + npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) { } + + void MovementInform(uint32 type, uint32 pointId) override { - Initialize(); - } - - void Initialize() - { - m_uiTransformTimer = 0; - } - - uint32 m_uiTransformTimer; - - void Reset() override - { - Initialize(); - - // we must assume he appear as dragon somewhere outside the platform of orb, and then move directly to here - if (me->GetEntry() != NPC_KAEL) - me->GetMotionMaster()->MovePoint(POINT_ID_LAND, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); - } - - void MovementInform(uint32 uiType, uint32 uiPointId) override - { - if (uiType != POINT_MOTION_TYPE) + if (type != WAYPOINT_MOTION_TYPE) return; - if (uiPointId == POINT_ID_LAND) - m_uiTransformTimer = MINUTE*IN_MILLISECONDS; - } - - void UpdateAI(uint32 uiDiff) override - { - if (m_uiTransformTimer) + if (pointId == POINT_ID_PREPARE_LANDING) { - if (m_uiTransformTimer <= uiDiff) - { - DoCast(me, SPELL_ORB_KILL_CREDIT, true); - - // Transform and update entry, now ready for quest/read gossip - DoCast(me, SPELL_TRANSFORM_TO_KAEL, false); - me->UpdateEntry(NPC_KAEL); - - m_uiTransformTimer = 0; - } else m_uiTransformTimer -= uiDiff; + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->SetDisableGravity(false); + me->SetHover(false); + events.ScheduleEvent(EVENT_KALECGOS_LANDING, Seconds(2)); } } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case EVENT_KALECGOS_LANDING: + DoCastAOE(SPELL_CAMERA_SHAKE); + me->SetObjectScale(0.6f); + events.ScheduleEvent(EVENT_KALECGOS_TRANSFORM, Seconds(1)); + break; + case EVENT_KALECGOS_TRANSFORM: + DoCast(me, SPELL_ORB_KILL_CREDIT, true); + DoCast(me, SPELL_TRANSFORM_VISUAL, false); + DoCast(me, SPELL_KALECGOS_TRANSFORM, false); + me->UpdateEntry(NPC_HUMAN_KALECGOS); + break; + default: + break; + } + } + + private: + EventMap events; }; }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h index 917ad0eb50b..05718dfc1dd 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h @@ -42,7 +42,9 @@ enum CreatureIds { NPC_SELIN = 24723, NPC_DELRISSA = 24560, - NPC_FEL_CRYSTAL = 24722 + NPC_FEL_CRYSTAL = 24722, + NPC_KALECGOS = 24844, + NPC_HUMAN_KALECGOS = 24848 }; enum GameObjectIds @@ -57,4 +59,19 @@ enum GameObjectIds GO_ESCAPE_ORB = 188173 }; +enum InstanceEventIds +{ + EVENT_SPAWN_KALECGOS = 16547 +}; + +enum InstanceText +{ + SAY_KALECGOS_SPAWN = 0 +}; + +enum MovementData +{ + PATH_KALECGOS_FLIGHT = 248440 +}; + #endif From b8445bbc202cce31c8c91303b9f6cd8e5901d4eb Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Wed, 10 Feb 2016 03:21:49 -0200 Subject: [PATCH 52/79] Scripts: Fix no-PCH (cherry picked from commit 130f744c297008ed8b6f6536186513091f8f81fb) --- .../MagistersTerrace/instance_magisters_terrace.cpp | 11 ++++++----- .../MagistersTerrace/magisters_terrace.cpp | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index cefbeb94924..36a41e2f628 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "InstanceScript.h" #include "magisters_terrace.h" +#include "EventMap.h" /* 0 - Selin Fireheart @@ -148,15 +149,15 @@ class instance_magisters_terrace : public InstanceMapScript void ProcessEvent(WorldObject* obj, uint32 eventId) override { if (eventId == EVENT_SPAWN_KALECGOS) - if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && events.Empty()) - events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1)); + if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && Events.Empty()) + Events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1)); } void Update(uint32 diff) override { - events.Update(diff); + Events.Update(diff); - if (events.ExecuteEvent() == EVENT_SPAWN_KALECGOS) + if (Events.ExecuteEvent() == EVENT_SPAWN_KALECGOS) if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos)) { kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false); @@ -202,7 +203,7 @@ class instance_magisters_terrace : public InstanceMapScript } protected: - EventMap events; + EventMap Events; ObjectGuid SelinGUID; ObjectGuid DelrissaGUID; ObjectGuid KaelStatue[2]; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp index 82bb61c5afd..5b90ac8ccf4 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp @@ -32,6 +32,7 @@ EndContentData */ #include "ScriptedGossip.h" #include "Player.h" #include "magisters_terrace.h" +#include "EventMap.h" /*###### ## npc_kalecgos From 781152a30c526ff94638a2b10845d1686edb5e62 Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Wed, 10 Feb 2016 04:00:28 -0200 Subject: [PATCH 53/79] Scripts: Fix no-PCH build MKII Bah --- .../MagistersTerrace/instance_magisters_terrace.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index 36a41e2f628..0a88ba17877 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -16,6 +16,7 @@ */ #include "ScriptMgr.h" +#include "ScriptedCreature.h" #include "InstanceScript.h" #include "magisters_terrace.h" #include "EventMap.h" From 0113b0f6253fb403d12c54ae28ad0c5d447dd8e9 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 10 Feb 2016 15:33:39 +0100 Subject: [PATCH 54/79] Core/PacketIO: Updated and enabled SMSG_FISH_NOT_HOOKED --- src/server/game/Entities/GameObject/GameObject.cpp | 6 +++--- src/server/game/Server/Packets/GameObjectPackets.h | 8 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index e27e59b723d..e19f15ad80c 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1520,9 +1520,9 @@ void GameObject::Use(Unit* user) default: { SetLootState(GO_JUST_DEACTIVATED); - - WorldPacket data(SMSG_FISH_NOT_HOOKED, 0); - player->SendDirectMessage(&data); + + WorldPackets::GameObject::FishNotHooked notHooked; + player->SendDirectMessage(notHooked.Write()); break; } } diff --git a/src/server/game/Server/Packets/GameObjectPackets.h b/src/server/game/Server/Packets/GameObjectPackets.h index 65eb2c7bed8..a1c3f0e39f6 100644 --- a/src/server/game/Server/Packets/GameObjectPackets.h +++ b/src/server/game/Server/Packets/GameObjectPackets.h @@ -92,6 +92,14 @@ namespace WorldPackets int32 Damage = 0; int32 SpellID = 0; }; + + class FishNotHooked final : public ServerPacket + { + public: + FishNotHooked() : ServerPacket(SMSG_FISH_NOT_HOOKED, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; } } #endif // GOPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index b12948d7337..5a358b382dc 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1055,7 +1055,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FINAL_CHUNK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLIGHT_SPLINE_SYNC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From b1ea3df5e42112c38d3cb09d2cf55838a4e96b72 Mon Sep 17 00:00:00 2001 From: Rushor Date: Wed, 10 Feb 2016 20:41:46 +0100 Subject: [PATCH 55/79] DB/Creature: Ironforge Gryphon Riders Hovering * by Saben65 * closes #16220 --- sql/updates/world/2016_02_10_01_world.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 sql/updates/world/2016_02_10_01_world.sql diff --git a/sql/updates/world/2016_02_10_01_world.sql b/sql/updates/world/2016_02_10_01_world.sql new file mode 100644 index 00000000000..2b8cca7cfb0 --- /dev/null +++ b/sql/updates/world/2016_02_10_01_world.sql @@ -0,0 +1,4 @@ +-- DB/Creature: Ironforge Gryphon Riders Hovering +DELETE FROM `creature_template_addon` WHERE `entry`=51383; +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(51383, 0, 24688, 50331648, 257, 0, ''); -- 51383 From 43f245d4b763d7213e1cdd92206decc326578e05 Mon Sep 17 00:00:00 2001 From: Rushor Date: Wed, 10 Feb 2016 20:45:16 +0100 Subject: [PATCH 56/79] DB/Creature: Loot for NPC Tunneling Worm * by Shoxxo, Killyana, tkrokli * closes #14270 --- sql/updates/world/2016_02_10_02_world.sql | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 sql/updates/world/2016_02_10_02_world.sql diff --git a/sql/updates/world/2016_02_10_02_world.sql b/sql/updates/world/2016_02_10_02_world.sql new file mode 100644 index 00000000000..967295f1fec --- /dev/null +++ b/sql/updates/world/2016_02_10_02_world.sql @@ -0,0 +1,15 @@ +-- DB/Creature: Loot for NPC Tunneling Worm +UPDATE `creature_template` SET `lootid`= 34865 WHERE `entry`= 34865; +DELETE FROM `creature_loot_template` WHERE `entry`= 34865; +INSERT INTO `creature_loot_template` (`entry`,`item`,`Reference`,`Chance`,`QuestRequired`,`LootMode`,`GroupId`,`MinCount`,`MaxCount`,`Comment`) VALUES +(34865, 55973, 0, 75, 0,1,0,1,1,'Tunneling Worm - Inert Elemental Speck'), +(34865, 55983, 0, 25, 0,1,0,1,1,'Tunneling Worm - Inert Elemental Scintilla'), +(34865, 805, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Small Red Pouch'), +(34865, 828, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Small Blue Pouch'), +(34865, 1411, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Withered Staff'), +(34865, 1431, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Patchwork Pants'), +(34865, 2589, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Linen Cloth'), +(34865, 4469, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Rod of Order - Quest item'), +(34865, 5571, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Small Black Pouch'), +(34865, 5572, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Small Green Pouch'), +(34865, 23333, 0, 0.5, 0,1,0,1,1,'Tunneling Worm - Shattered Power Core'); From 6f07e9fcd5901053355ce9e0d4de643042714089 Mon Sep 17 00:00:00 2001 From: Rushor Date: Wed, 10 Feb 2016 20:56:32 +0100 Subject: [PATCH 57/79] DB/Creature: Nalpak Spawn * by Saben65 * closes #16114 --- sql/updates/world/2016_02_10_03_world.sql | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 sql/updates/world/2016_02_10_03_world.sql diff --git a/sql/updates/world/2016_02_10_03_world.sql b/sql/updates/world/2016_02_10_03_world.sql new file mode 100644 index 00000000000..9e53fa3431a --- /dev/null +++ b/sql/updates/world/2016_02_10_03_world.sql @@ -0,0 +1,5 @@ +-- DB/Creature: Nalpak Spawn +SET @CGUID := 452399; +DELETE FROM `creature` WHERE `guid`=@CGUID; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID, 5767, 43, 1, -150.298, 123.82, -75.95126, 3.228859, 7200, 0, 0); -- 5767 (Area: -1) From 16d386fe318707cd0d179e058739c4ceb17192ff Mon Sep 17 00:00:00 2001 From: Rushor Date: Wed, 10 Feb 2016 21:16:38 +0100 Subject: [PATCH 58/79] DB/Quest: Have They No Shame - AllowableRaces * by Alastyr * closes #16510 --- sql/updates/world/2016_02_10_04_world.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql/updates/world/2016_02_10_04_world.sql diff --git a/sql/updates/world/2016_02_10_04_world.sql b/sql/updates/world/2016_02_10_04_world.sql new file mode 100644 index 00000000000..e1dd6fa7603 --- /dev/null +++ b/sql/updates/world/2016_02_10_04_world.sql @@ -0,0 +1,3 @@ +-- +UPDATE `quest_template` SET `AllowableRaces` = 1 + 4 + 8 + 64 + 1024 + 2097152 + 16777216 WHERE id=13094; +UPDATE `quest_template` SET `AllowableRaces` = 2 + 16 + 32 + 128 + 256 + 512 + 33554432 WHERE id=13095; From fdfa210b46e761ee6099b9227f59f03341255074 Mon Sep 17 00:00:00 2001 From: Rushor Date: Wed, 10 Feb 2016 21:29:35 +0100 Subject: [PATCH 59/79] DB/Quest: Have They No Shame - AllowableRaces * fixup previous commit --- sql/updates/world/2016_02_10_04_world.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/updates/world/2016_02_10_04_world.sql b/sql/updates/world/2016_02_10_04_world.sql index e1dd6fa7603..00397623b90 100644 --- a/sql/updates/world/2016_02_10_04_world.sql +++ b/sql/updates/world/2016_02_10_04_world.sql @@ -1,3 +1,4 @@ -- -UPDATE `quest_template` SET `AllowableRaces` = 1 + 4 + 8 + 64 + 1024 + 2097152 + 16777216 WHERE id=13094; -UPDATE `quest_template` SET `AllowableRaces` = 2 + 16 + 32 + 128 + 256 + 512 + 33554432 WHERE id=13095; +UPDATE `quest_template` SET `AllowableRaces`=0 WHERE `id` IN (13094, 13095); +UPDATE `quest_template` SET `AllowableRaces`=`AllowableRaces`|1|4|8|64|1024|2097152|16777216 WHERE id=13094; +UPDATE `quest_template` SET `AllowableRaces`=`AllowableRaces`|2|16|32|128|256|512|33554432 WHERE id=13095; From c09f72a2c81ac349cf8fec05cdf48ffcf781dd57 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 10 Feb 2016 21:25:28 +0100 Subject: [PATCH 60/79] Core/Maps: Moved min height calculation to worldserver for more precise results Closes #16530 --- src/server/game/Maps/Map.cpp | 68 ++++++++++++++--- src/server/game/Maps/Map.h | 4 +- src/tools/map_extractor/System.cpp | 79 ++------------------ src/tools/mmaps_generator/TerrainBuilder.cpp | 2 +- 4 files changed, 66 insertions(+), 87 deletions(-) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 304f1ef7c2a..1e67e949773 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -40,7 +40,7 @@ #include "Weather.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','7'} }; +u_map_magic MapVersionMagic = { {'v','1','.','8'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1816,10 +1816,10 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) { - _maxHeight = new float[16 * 16]; - _minHeight = new float[16 * 16]; - if (fread(_maxHeight, sizeof(float), 16 * 16, in) != 16 * 16 || - fread(_minHeight, sizeof(float), 16 * 16, in) != 16 * 16) + _maxHeight = new int16[3 * 3]; + _minHeight = new int16[3 * 3]; + if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 || + fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3) return false; } @@ -2098,11 +2098,59 @@ float GridMap::getMinHeight(float x, float y) const if (!_minHeight) return -500.0f; - x = 16 * (CENTER_GRID_ID - x / SIZE_OF_GRIDS); - y = 16 * (CENTER_GRID_ID - y / SIZE_OF_GRIDS); - int lx = (int)x & 15; - int ly = (int)y & 15; - return _minHeight[lx * 16 + ly]; + static uint32 const indices[] = + { + 3, 0, 4, + 0, 1, 4, + 1, 2, 4, + 2, 5, 4, + 5, 8, 4, + 8, 7, 4, + 7, 6, 4, + 6, 3, 4 + }; + + static float const boundGridCoords[] = + { + 0.0f, 0.0f, + 0.0f, -266.66666f, + 0.0f, -533.33331f, + -266.66666f, 0.0f, + -266.66666f, -266.66666f, + -266.66666f, -533.33331f, + -533.33331f, 0.0f, + -533.33331f, -266.66666f, + -533.33331f, -533.33331f + }; + + Cell cell(x, y); + float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + + uint32 quarterIndex = 0; + if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2) + { + if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) + { + quarterIndex = 4 + (gy > gx); + } + else + quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy); + } + else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) + { + quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy); + } + else + quarterIndex = gx > gy; + + quarterIndex *= 3; + + return G3D::Plane( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]]) + ).distance(G3D::Vector3(gx, gy, 0.0f)); } float GridMap::getLiquidLevel(float x, float y) const diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index bf29a257419..34aa00e4bf9 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -169,8 +169,8 @@ class GridMap uint16* m_uint16_V8; uint8* m_uint8_V8; }; - float* _maxHeight; - float* _minHeight; + int16* _maxHeight; + int16* _minHeight; // Height level data float _gridHeight; float _gridIntHeightMultiplier; diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index a079ab42367..9b6f81a29af 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -353,7 +353,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.7"; +static char const* MAP_VERSION_MAGIC = "v1.8"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -445,8 +445,8 @@ bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8]; -float flight_box_max[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; -float flight_box_min[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +int16 flight_box_max[3][3]; +int16 flight_box_min[3][3]; bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8]) { @@ -705,77 +705,8 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (FileChunk* chunk = adt.GetChunk("MFBO")) { - static uint32 const indices[] = - { - 3, 0, 4, - 0, 1, 4, - 1, 2, 4, - 2, 5, 4, - 5, 8, 4, - 8, 7, 4, - 7, 6, 4, - 6, 3, 4 - }; - - static float const boundGridCoords[] = - { - 0.0f, 0.0f, - 0.0f, -266.66666f, - 0.0f, -533.33331f, - -266.66666f, 0.0f, - -266.66666f, -266.66666f, - -266.66666f, -533.33331f, - -533.33331f, 0.0f, - -533.33331f, -266.66666f, - -533.33331f, -533.33331f - }; - - adt_MFBO* mfbo = chunk->As(); - for (int gy = 0; gy < ADT_CELLS_PER_GRID; ++gy) - { - for (int gx = 0; gx < ADT_CELLS_PER_GRID; ++gx) - { - int32 quarterIndex = 0; - if (gy > ADT_CELLS_PER_GRID / 2) - { - if (gx > ADT_CELLS_PER_GRID / 2) - { - quarterIndex = 4 + gx < gy; - } - else - quarterIndex = 2; - } - else if (gx > ADT_CELLS_PER_GRID / 2) - { - quarterIndex = 7; - } - else - quarterIndex = gx > gy; - - quarterIndex *= 3; - G3D::Plane planeMax( - G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 0]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 1]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 2]]) - ); - - G3D::Plane planeMin( - G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 0]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 1]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 2]]) - ); - - auto non_nan_distance = [](G3D::Plane const& plane){ - auto d = plane.distance(G3D::Vector3(0.0f, 0.0f, 0.0f)); - assert(!G3D::isNaN(d)); - return d; - }; - - flight_box_max[gy][gx] = non_nan_distance(planeMax); - flight_box_min[gy][gx] = non_nan_distance(planeMin); - } - } - + memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max)); + memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min)); hasFlightBox = true; } diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index c4a32882c1d..5dd6bed30b0 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.7"; + char const* MAP_VERSION_MAGIC = "v1.8"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } From e24a6e52e99ca76f27b70feb086922ce46a0445e Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 10 Feb 2016 22:11:04 +0100 Subject: [PATCH 61/79] Build fixes --- src/server/game/Handlers/ChatHandler.cpp | 4 +--- src/server/game/Server/Packets/ChatPackets.h | 2 +- src/tools/map_extractor/CMakeLists.txt | 2 -- src/tools/map_extractor/System.cpp | 3 +-- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index d96eb9b551e..2c77d8df04d 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -653,9 +653,7 @@ void WorldSession::SendChatPlayerNotfoundNotice(std::string const& name) void WorldSession::SendPlayerAmbiguousNotice(std::string const& name) { - WorldPackets::Chat::ChatPlayerAmbiguous packet; - packet.Name = name; - SendPacket(packet.Write()); + SendPacket(WorldPackets::Chat::ChatPlayerAmbiguous(name).Write()); } void WorldSession::SendChatRestricted(ChatRestrictionType restriction) diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index 277892c1495..faa060b3c0f 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -304,7 +304,7 @@ namespace WorldPackets class ChatPlayerAmbiguous final : public ServerPacket { public: - ChatPlayerAmbiguous() : ServerPacket(SMSG_CHAT_PLAYER_AMBIGUOUS, 2 + Name.length()) { } + ChatPlayerAmbiguous(std::string const& name) : ServerPacket(SMSG_CHAT_PLAYER_AMBIGUOUS, 2 + name.length()), Name(name) { } WorldPacket const* Write() override; diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index 58435a51121..32fccaa2038 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -14,7 +14,6 @@ file(GLOB_RECURSE sources *.cpp *.h) include_directories ( ${CMAKE_SOURCE_DIR}/dep/CascLib/src ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/src/common ${CMAKE_SOURCE_DIR}/src/common/Utilities ${CMAKE_SOURCE_DIR}/src/server/shared @@ -32,7 +31,6 @@ target_link_libraries(mapextractor casc common format - g3dlib ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 9b6f81a29af..22a8cc72c3c 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -40,8 +40,6 @@ #include "adt.h" #include "wdt.h" -#include - namespace { const char* HumanReadableCASCError(int error) @@ -705,6 +703,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (FileChunk* chunk = adt.GetChunk("MFBO")) { + adt_MFBO* mfbo = chunk->As(); memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max)); memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min)); hasFlightBox = true; From bf186ec26d9016a99b24e400e25f0959eaaafbf9 Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 10 Feb 2016 15:22:47 +0100 Subject: [PATCH 62/79] Core/PacketIO: Updated and enabled SMSG_FISH_ESCAPED --- src/server/game/Entities/GameObject/GameObject.cpp | 4 ++-- src/server/game/Server/Packets/GameObjectPackets.h | 8 ++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index e19f15ad80c..2202c079de1 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -464,8 +464,8 @@ void GameObject::Update(uint32 diff) { caster->ToPlayer()->RemoveGameObject(this, false); - WorldPacket data(SMSG_FISH_ESCAPED, 0); - caster->ToPlayer()->SendDirectMessage(&data); + WorldPackets::GameObject::FishEscaped escaped; + caster->ToPlayer()->SendDirectMessage(escaped.Write()); } // can be delete m_lootState = GO_JUST_DEACTIVATED; diff --git a/src/server/game/Server/Packets/GameObjectPackets.h b/src/server/game/Server/Packets/GameObjectPackets.h index a1c3f0e39f6..5261beede13 100644 --- a/src/server/game/Server/Packets/GameObjectPackets.h +++ b/src/server/game/Server/Packets/GameObjectPackets.h @@ -100,6 +100,14 @@ namespace WorldPackets WorldPacket const* Write() override { return &_worldPacket; } }; + + class FishEscaped final : public ServerPacket + { + public: + FishEscaped() : ServerPacket(SMSG_FISH_ESCAPED, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; } } #endif // GOPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 5a358b382dc..c4969959247 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1054,7 +1054,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FINAL_CHUNK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLIGHT_SPLINE_SYNC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); From 541c125c2c3cec0714ef5c5cf28afa22df48ff7a Mon Sep 17 00:00:00 2001 From: Carbenium Date: Thu, 11 Feb 2016 00:56:39 +0100 Subject: [PATCH 63/79] Codestyle --- src/server/game/Entities/GameObject/GameObject.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 2202c079de1..050217996ee 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -463,9 +463,7 @@ void GameObject::Update(uint32 diff) if (caster && caster->GetTypeId() == TYPEID_PLAYER) { caster->ToPlayer()->RemoveGameObject(this, false); - - WorldPackets::GameObject::FishEscaped escaped; - caster->ToPlayer()->SendDirectMessage(escaped.Write()); + caster->ToPlayer()->SendDirectMessage(WorldPackets::GameObject::FishEscaped().Write()); } // can be delete m_lootState = GO_JUST_DEACTIVATED; @@ -1520,9 +1518,7 @@ void GameObject::Use(Unit* user) default: { SetLootState(GO_JUST_DEACTIVATED); - - WorldPackets::GameObject::FishNotHooked notHooked; - player->SendDirectMessage(notHooked.Write()); + player->SendDirectMessage(WorldPackets::GameObject::FishNotHooked().Write()); break; } } From f809e5e13eac66add49d361ffb1634ff2ba6d4aa Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 11 Feb 2016 16:35:42 +0100 Subject: [PATCH 64/79] Core/Scripts: Fixed calling UnitScript hooks Closes #16543 --- src/server/game/Scripting/ScriptMgr.cpp | 33 ++++++++----------------- src/server/game/Scripting/ScriptMgr.h | 4 --- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 774c4e279d0..38ca4911a21 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -37,7 +37,6 @@ // namespace // { - UnusedScriptContainer UnusedScripts; UnusedScriptNamesContainer UnusedScriptNames; // } @@ -107,8 +106,9 @@ class ScriptRegistry // The actual list of scripts. This will be accessed concurrently, so it must not be modified // after server startup. static ScriptMap ScriptPointerList; + static std::vector Scripts; - static void AddScript(TScript* const script) + static void AddScript(TScript* const script, bool addToDeleteContainer = true) { ASSERT(script); @@ -126,6 +126,8 @@ class ScriptRegistry } AddScript(is_script_database_bound{}, script); + if (addToDeleteContainer) + Scripts.push_back(script); } // Gets a script by its ID (assigned by ObjectMgr). @@ -186,11 +188,6 @@ class ScriptRegistry { // The script uses a script name from database, but isn't assigned to anything. TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", script->GetName().c_str()); - - // Avoid calling "delete script;" because we are currently in the script constructor - // In a valid scenario this will not happen because every script has a name assigned in the database - UnusedScripts.push_back(script); - return; } } @@ -210,6 +207,7 @@ class ScriptRegistry #define SCR_REG_MAP(T) ScriptRegistry::ScriptMap #define SCR_REG_ITR(T) ScriptRegistry::ScriptMapIterator #define SCR_REG_LST(T) ScriptRegistry::ScriptPointerList +#define SCR_REG_VEC(T) ScriptRegistry::Scripts // Utility macros for looping over scripts. #define FOR_SCRIPTS(T, C, E) \ @@ -266,17 +264,15 @@ void ScriptMgr::Initialize() } #endif - UnloadUnusedScripts(); - TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); } void ScriptMgr::Unload() { #define SCR_CLEAR(T) \ - for (SCR_REG_ITR(T) itr = SCR_REG_LST(T).begin(); itr != SCR_REG_LST(T).end(); ++itr) \ - delete itr->second; \ - SCR_REG_LST(T).clear(); + for (T* scr : SCR_REG_VEC(T)) \ + delete scr; \ + SCR_REG_VEC(T).clear(); // Clear scripts for every script type. SCR_CLEAR(SpellScriptLoader); @@ -308,19 +304,10 @@ void ScriptMgr::Unload() #undef SCR_CLEAR - UnloadUnusedScripts(); - delete[] SpellSummary; delete[] UnitAI::AISpellInfo; } -void ScriptMgr::UnloadUnusedScripts() -{ - for (size_t i = 0; i < UnusedScripts.size(); ++i) - delete UnusedScripts[i]; - UnusedScripts.clear(); -} - void ScriptMgr::LoadDatabase() { sScriptSystemMgr->LoadScriptWaypoints(); @@ -1558,8 +1545,7 @@ FormulaScript::FormulaScript(const char* name) UnitScript::UnitScript(const char* name, bool addToScripts) : ScriptObject(name) { - if (addToScripts) - ScriptRegistry::AddScript(this); + ScriptRegistry::AddScript(this, addToScripts); } WorldMapScript::WorldMapScript(const char* name, uint32 mapId) @@ -1699,6 +1685,7 @@ GroupScript::GroupScript(const char* name) // Instantiate static members of ScriptRegistry. template std::map ScriptRegistry::ScriptPointerList; +template std::vector ScriptRegistry::Scripts; template uint32 ScriptRegistry::_scriptIdCounter = 0; // Specialize for each script type class like so: diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 49d561f8885..aac2cdeabfa 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -842,10 +842,7 @@ class GroupScript : public ScriptObject // namespace // { - typedef std::vector UnusedScriptContainer; typedef std::list UnusedScriptNamesContainer; - - extern UnusedScriptContainer UnusedScripts; extern UnusedScriptNamesContainer UnusedScriptNames; // } @@ -877,7 +874,6 @@ class ScriptMgr public: /* Unloading */ void Unload(); - void UnloadUnusedScripts(); public: /* SpellScriptLoader */ From 2c53b678f78241b379b73cc95b48c1bdac6d789f Mon Sep 17 00:00:00 2001 From: Rushor Date: Thu, 11 Feb 2016 18:02:10 +0100 Subject: [PATCH 65/79] DB/Spell: Challenge mode teleport spell_target_positions * by Foldor * closes #16115 --- sql/updates/world/2016_02_11_00_world.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 sql/updates/world/2016_02_11_00_world.sql diff --git a/sql/updates/world/2016_02_11_00_world.sql b/sql/updates/world/2016_02_11_00_world.sql new file mode 100644 index 00000000000..929f34154de --- /dev/null +++ b/sql/updates/world/2016_02_11_00_world.sql @@ -0,0 +1,11 @@ +-- +DELETE FROM `spell_target_position` WHERE `ID` IN (159895,159896,159897,159898,159899,159900,159901,159902); +INSERT INTO `spell_target_position` (`ID`,`EffectIndex`,`MapID`,`PositionX`,`PositionY`,`PositionZ`,`VerifiedBuild`) VALUES +(159895, 0, 1116, 7263.71, 4453.39, 129.221, 20779), -- Path of the Bloodmaul +(159896, 0, 1116, 8850.58, 1370.09, 97.097, 20779), -- Path of the Iron Prow +(159897, 0, 1116, 1489.18, 3075.6, 109.725, 20779), -- Path of the Vigilant +(159898, 0, 1116, 32.4602, 2527.42, 103.606, 20779), -- Path of the Skies +(159899, 0, 1116, 762.092, 130.033, 7.53102, 20779), -- Path of the Crescent Moon +(159900, 0, 1116, 7811.06, 542.615, 122.757, 20779), -- Path of the Dark Rail +(159901, 0, 1116, 7117.57, 197.1, 145.211, 20779), -- Path of the Verdant +(159902, 0, 0,-7508.83,-1326.77, 301.364, 20779); -- Path of the Burning Mountain From e45e900bdf1bd2915aaaceec9c25a26de7b8ea9a Mon Sep 17 00:00:00 2001 From: Rushor Date: Thu, 11 Feb 2016 18:05:57 +0100 Subject: [PATCH 66/79] DB/Gameobject: Delete multiple elevelator spawns * closes #16285 * by msoky --- sql/updates/world/2016_02_11_01_world.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql/updates/world/2016_02_11_01_world.sql diff --git a/sql/updates/world/2016_02_11_01_world.sql b/sql/updates/world/2016_02_11_01_world.sql new file mode 100644 index 00000000000..5a13d28f34b --- /dev/null +++ b/sql/updates/world/2016_02_11_01_world.sql @@ -0,0 +1,3 @@ +-- +-- delete multiple spawns +DELETE FROM `gameobject` WHERE `guid` IN (218987,232480,234051,218986,232479,234050,218988,218989,200969,203095,212811,216447,220558,200970,203096,212810,216448,220557,200968,203094,212812,216446,220559,200972,203101,212808,216450,220552,200971,203100,212809,216449,220553,200973,203102,212804,216451,220551,200975,203098,212800,216453,220555,200974,203099,212802,216452,220554,200976,203097,212799,216454,220556,218990,232504,234053,218991,232503,234052,203060,212761,216473,220569,203061,212763,216474,220568,218955,201000,203066,212765,216471,220564,200995,203067,212769,216470,220562,219016,219017,234295,219015,234296,219010,234315,219008,219013,200998,203065,212766,216469,220565,200997,203064,212767,216468,220566,219025,219018); From 52758c1a0b8e37e198d744803460e34600d115b5 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 12 Feb 2016 20:39:25 +0100 Subject: [PATCH 67/79] Core/Maps: Use map.dbc zone fallback if no area is found in grid files, not only if grid files don't exist Closes #16583 Closes #16584 Extracting new maps is NOT needed. (cherry picked from commit fa3f106693733e7db8061fbd44295b0168a94614) --- src/server/game/Maps/Map.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 1e67e949773..fb7043d9574 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2447,8 +2447,9 @@ uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const { if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) areaId = gmap->getArea(x, y); + // this used while not all *.map files generated (instances) - else + if (!areaId) areaId = i_mapEntry->AreaTableID; } From 019d15591cd7049407d65d1fb15fa71ac09a45f9 Mon Sep 17 00:00:00 2001 From: w5860363 Date: Sat, 13 Feb 2016 11:43:29 -0200 Subject: [PATCH 68/79] Scripts/TheEye: Add spell Rend to advisor Thaladred the Darkener Closes #16594 Closes #15915 (cherry picked from commit e28cc7161af3929d7aa066b409dfe446705444b5) --- .../Outland/TempestKeep/Eye/boss_kaelthas.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 66cd00489f8..fceeb108ebf 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -144,6 +144,7 @@ enum Spells // Thaladred the Darkener spells SPELL_PSYCHIC_BLOW = 10689, SPELL_SILENCE = 30225, + SPELL_REND = 36965, // Lord Sanguinar spells SPELL_BELLOWING_ROAR = 40636, // Grand Astromancer Capernian spells @@ -880,11 +881,13 @@ class boss_thaladred_the_darkener : public CreatureScript { Gaze_Timer = 100; Silence_Timer = 20000; + Rend_Timer = 4000; PsychicBlow_Timer = 10000; } uint32 Gaze_Timer; uint32 Silence_Timer; + uint32 Rend_Timer; uint32 PsychicBlow_Timer; void Reset() override @@ -938,6 +941,15 @@ class boss_thaladred_the_darkener : public CreatureScript else Silence_Timer -= diff; + //Rend_Timer + if (Rend_Timer <= diff) + { + DoCastVictim(SPELL_REND); + Rend_Timer = 4000; + } + else + Rend_Timer -= diff; + //PsychicBlow_Timer if (PsychicBlow_Timer <= diff) { From beb394bad4175ed2e2e10c8fb9e96eacf75460f5 Mon Sep 17 00:00:00 2001 From: Rochet2 Date: Sun, 14 Feb 2016 22:36:05 +0200 Subject: [PATCH 69/79] Fix build failing since https://github.com/TrinityCore/TrinityCore/commit/52758c1a0b8e37e198d744803460e34600d115b5 /TrinityCore/src/server/game/Maps/Map.cpp:2448:22: fatal error: variable 'areaId' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized] if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) --- src/server/game/Maps/Map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index fb7043d9574..9335539bc6e 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2439,7 +2439,7 @@ uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const atEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); } - uint32 areaId; + uint32 areaId = 0; if (atEntry) areaId = atEntry->ID; From 36a1b1ccd5d42b143c5dac23ae0e81c0b5b519f5 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 16 Feb 2016 00:14:59 +0100 Subject: [PATCH 70/79] Core/Bnet: Moved expiring bans to background task running every minute by default (configurable) - no longer executed during login. --- src/server/bnetserver/Main.cpp | 30 ++++++++++++++++++++---- src/server/bnetserver/Server/Session.cpp | 15 ------------ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index 3d1481fae9e..740a0efa438 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -71,13 +71,16 @@ void ServiceStatusWatcher(boost::system::error_code const& error); bool StartDB(); void StopDB(); -void SignalHandler(const boost::system::error_code& error, int signalNumber); -void KeepDatabaseAliveHandler(const boost::system::error_code& error); +void SignalHandler(boost::system::error_code const& error, int signalNumber); +void KeepDatabaseAliveHandler(boost::system::error_code const& error); +void BanExpiryHandler(boost::system::error_code const& error); variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService); static boost::asio::io_service* _ioService; static boost::asio::deadline_timer* _dbPingTimer; static uint32 _dbPingInterval; +static boost::asio::deadline_timer* _banExpiryCheckTimer; +static uint32 _banExpiryCheckInterval; LoginDatabaseWorkerPool LoginDatabase; int main(int argc, char** argv) @@ -180,6 +183,11 @@ int main(int argc, char** argv) _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval)); _dbPingTimer->async_wait(KeepDatabaseAliveHandler); + _banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60); + _banExpiryCheckTimer = new boost::asio::deadline_timer(*_ioService); + _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval)); + _banExpiryCheckTimer->async_wait(BanExpiryHandler); + sComponentMgr->Load(); sModuleMgr->Load(); @@ -195,6 +203,7 @@ int main(int argc, char** argv) // Start the io service worker loop _ioService->run(); + _banExpiryCheckTimer->cancel(); _dbPingTimer->cancel(); sSessionMgr.StopNetwork(); @@ -210,6 +219,7 @@ int main(int argc, char** argv) signals.cancel(); + delete _banExpiryCheckTimer; delete _dbPingTimer; delete _ioService; return 0; @@ -240,13 +250,13 @@ void StopDB() MySQL::Library_End(); } -void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/) +void SignalHandler(boost::system::error_code const& error, int /*signalNumber*/) { if (!error) _ioService->stop(); } -void KeepDatabaseAliveHandler(const boost::system::error_code& error) +void KeepDatabaseAliveHandler(boost::system::error_code const& error) { if (!error) { @@ -258,6 +268,18 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) } } +void BanExpiryHandler(boost::system::error_code const& error) +{ + if (!error) + { + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval)); + _banExpiryCheckTimer->async_wait(BanExpiryHandler); + } +} + #if PLATFORM == PLATFORM_WINDOWS void ServiceStatusWatcher(boost::system::error_code const& error) { diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 51a50b48a5b..a5ede8d6524 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -615,18 +615,6 @@ void Battlenet::Session::Start() std::string ip_address = GetRemoteIpAddress().to_string(); TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str()); - if (_queryCallback) - { - Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); - logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST); - AsyncWrite(logonResponse); - TC_LOG_DEBUG("session", "[Session::Start] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str()); - return; - } - - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); @@ -827,9 +815,6 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke return false; } - //set expired game account bans to inactive - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - BigNumber M; sha.Initialize(); sha.UpdateBigNumbers(&A, &M1, &K, NULL); From 494480239964fb677f16433b3172e22b5b4e5e87 Mon Sep 17 00:00:00 2001 From: DDuarte Date: Wed, 17 Feb 2016 19:53:19 +0000 Subject: [PATCH 71/79] Add a Github issue template https://github.com/TrinityCore/TrinityCore/issues/new --- issue_template.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 issue_template.md diff --git a/issue_template.md b/issue_template.md new file mode 100644 index 00000000000..ccda1ce24ff --- /dev/null +++ b/issue_template.md @@ -0,0 +1,27 @@ +### Actual behaviour + +Tell us what happens + +### Expected behaviour + +Tell us what should happen instead + +### Steps to reproduce the problem + +1. +2. +3. + +### Aditional info + + + +### Versions + +**Branch**: 335/6x + +**TC hash/commit**: + +**TDB version**: + +**Operating system**: From a624b4523fb5da4929b299a35293833d1740ee03 Mon Sep 17 00:00:00 2001 From: DDuarte Date: Wed, 17 Feb 2016 20:22:12 +0000 Subject: [PATCH 72/79] Fix typos and shortify issue template --- issue_template.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/issue_template.md b/issue_template.md index ccda1ce24ff..9f655f7acf9 100644 --- a/issue_template.md +++ b/issue_template.md @@ -1,27 +1,18 @@ -### Actual behaviour +**Description**: -Tell us what happens +**Current behaviour**: Tell us what happens -### Expected behaviour +**Expected behaviour**: Tell us what should happen instead -Tell us what should happen instead +**Steps to reproduce the problem**: -### Steps to reproduce the problem - -1. -2. -3. - -### Aditional info - - - -### Versions - -**Branch**: 335/6x +**Branch(es)**: 335/6x **TC hash/commit**: **TDB version**: **Operating system**: + +[//]: # (This template is for problem reports, for other type of reports edit it accordingly) +[//]: # (If this is a crash report, include the crashlog with https://gist.github.com/) From 08e6294c803db4cedf5cdd38be383abff819283e Mon Sep 17 00:00:00 2001 From: DDuarte Date: Wed, 17 Feb 2016 20:33:23 +0000 Subject: [PATCH 73/79] Also add a template for new Github pull requests https://github.com/blog/2111-issue-and-pull-request-templates --- pull_request_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 pull_request_template.md diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 00000000000..7438ed561cf --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,13 @@ +**Changes proposed**: + +- +- +- + +**Target branch(es)**: 335/6x + +**Issues addressed**: Fixes # + +**Tests performed**: (Does it build? Tested in-game?) + +**Known issues and TODO list**: From b6b5665158ca5c52ddd429c0feb85885aaa283d5 Mon Sep 17 00:00:00 2001 From: DDuarte Date: Wed, 17 Feb 2016 20:59:05 +0000 Subject: [PATCH 74/79] Give emphasis to the steps part of issue_template.md --- issue_template.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/issue_template.md b/issue_template.md index 9f655f7acf9..87f2e21af41 100644 --- a/issue_template.md +++ b/issue_template.md @@ -6,6 +6,10 @@ **Steps to reproduce the problem**: +1. +2. +3. + **Branch(es)**: 335/6x **TC hash/commit**: @@ -14,5 +18,6 @@ **Operating system**: + [//]: # (This template is for problem reports, for other type of reports edit it accordingly) [//]: # (If this is a crash report, include the crashlog with https://gist.github.com/) From 5e06fdfcc354e30f074e8cafd9f88db09e0ca669 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 17 Feb 2016 23:41:26 +0100 Subject: [PATCH 75/79] Core/Configuration: Set default value of "Expansion" config to CURRENT_EXPANSION (whatever the value at the moment is) and prevent setting LOCALE_none as dbc locale --- src/server/game/World/World.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 972860f790f..331c2114b4e 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -427,9 +427,9 @@ void World::LoadConfigSettings(bool reload) m_defaultDbcLocale = LocaleConstant(sConfigMgr->GetIntDefault("DBC.Locale", 0)); - if (m_defaultDbcLocale >= TOTAL_LOCALES || m_defaultDbcLocale < LOCALE_enUS) + if (m_defaultDbcLocale >= TOTAL_LOCALES || m_defaultDbcLocale < LOCALE_enUS || m_defaultDbcLocale == LOCALE_none) { - TC_LOG_ERROR("server.loading", "Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)", TOTAL_LOCALES); + TC_LOG_ERROR("server.loading", "Incorrect DBC.Locale! Must be >= 0 and < %d and not %d (set to 0)", TOTAL_LOCALES, LOCALE_none); m_defaultDbcLocale = LOCALE_enUS; } @@ -1044,12 +1044,12 @@ void World::LoadConfigSettings(bool reload) if (reload) { - uint32 val = sConfigMgr->GetIntDefault("Expansion", 2); + uint32 val = sConfigMgr->GetIntDefault("Expansion", CURRENT_EXPANSION); if (val != m_int_configs[CONFIG_EXPANSION]) TC_LOG_ERROR("server.loading", "Expansion option can't be changed at worldserver.conf reload, using current value (%u).", m_int_configs[CONFIG_EXPANSION]); } else - m_int_configs[CONFIG_EXPANSION] = sConfigMgr->GetIntDefault("Expansion", 2); + m_int_configs[CONFIG_EXPANSION] = sConfigMgr->GetIntDefault("Expansion", CURRENT_EXPANSION); m_int_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfigMgr->GetIntDefault("ChatFlood.MessageCount", 10); m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfigMgr->GetIntDefault("ChatFlood.MessageDelay", 1); From 06ec1b8fe8dfe9bb8a225ed57a053eb546d386ad Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 18 Feb 2016 00:03:52 +0100 Subject: [PATCH 76/79] Build fix - who the hell places semicolons after preprocessor defines?! --- src/server/game/Miscellaneous/SharedDefines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 88b9190af6f..238c39ed2c9 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -85,7 +85,7 @@ enum Expansions MAX_EXPANSIONS = 6 }; -#define CURRENT_EXPANSION EXPANSION_WARLORDS_OF_DRAENOR; +#define CURRENT_EXPANSION EXPANSION_WARLORDS_OF_DRAENOR enum Gender { From 97a79af4701621ec04b88c8b548dbc35d120e99e Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 19 Feb 2016 19:23:04 +0100 Subject: [PATCH 77/79] Core/Networking: Rewrite networking threading model Each network thread has its own io_service - this means that all operations on a given socket except queueing packets run from a single thread, removing the need for locking Sending packets now writes to a lockfree intermediate queue directly, encryption is applied in network thread if it was required at the time of sending the packet --- src/common/Threading/MPSCQueue.h | 83 ++++++++++++++ src/server/bnetserver/Server/Session.cpp | 38 +++++-- src/server/bnetserver/Server/Session.h | 8 ++ .../bnetserver/Server/SessionManager.cpp | 7 +- src/server/bnetserver/Server/SessionManager.h | 2 +- src/server/game/Server/WorldSocket.cpp | 105 ++++++++++-------- src/server/game/Server/WorldSocket.h | 6 +- src/server/game/Server/WorldSocketMgr.cpp | 15 ++- src/server/game/Server/WorldSocketMgr.h | 2 +- src/server/game/World/World.cpp | 39 ++++--- src/server/game/World/World.h | 6 +- src/server/shared/Networking/AsyncAcceptor.h | 26 +++-- src/server/shared/Networking/MessageBuffer.h | 2 +- src/server/shared/Networking/NetworkThread.h | 94 +++++++++------- src/server/shared/Networking/Socket.h | 75 ++----------- src/server/shared/Networking/SocketMgr.h | 27 +++-- 16 files changed, 325 insertions(+), 210 deletions(-) create mode 100644 src/common/Threading/MPSCQueue.h diff --git a/src/common/Threading/MPSCQueue.h b/src/common/Threading/MPSCQueue.h new file mode 100644 index 00000000000..09648b844be --- /dev/null +++ b/src/common/Threading/MPSCQueue.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2016 TrinityCore + * + * 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 . + */ + +#ifndef MPSCQueue_h__ +#define MPSCQueue_h__ + +#include +#include + +// C++ implementation of Dmitry Vyukov's lock free MPSC queue +// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue +template +class MPSCQueue +{ +public: + MPSCQueue() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed)) + { + Node* front = _head.load(std::memory_order_relaxed); + front->Next.store(nullptr, std::memory_order_relaxed); + } + + ~MPSCQueue() + { + T* output; + while (this->Dequeue(output)) + ; + + Node* front = _head.load(std::memory_order_relaxed); + delete front; + } + + void Enqueue(T* input) + { + Node* node = new Node(input); + Node* prevHead = _head.exchange(node, std::memory_order_acq_rel); + prevHead->Next.store(node, std::memory_order_release); + } + + bool Dequeue(T*& result) + { + Node* tail = _tail.load(std::memory_order_relaxed); + Node* next = tail->Next.load(std::memory_order_acquire); + if (!next) + return false; + + result = next->Data; + _tail.store(next, std::memory_order_release); + delete tail; + return true; + } + +private: + struct Node + { + Node() = default; + explicit Node(T* data) : Data(data) { Next.store(nullptr, std::memory_order_relaxed); } + + T* Data; + std::atomic Next; + }; + + std::atomic _head; + std::atomic _tail; + + MPSCQueue(MPSCQueue const&) = delete; + MPSCQueue& operator=(MPSCQueue const&) = delete; +}; + +#endif // MPSCQueue_h__ diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index a5ede8d6524..4d54562501f 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -654,12 +654,37 @@ void Battlenet::Session::CheckIpCallback(PreparedQueryResult result) bool Battlenet::Session::Update() { + EncryptableBuffer* queued; + MessageBuffer buffer((std::size_t(BufferSizes::Read))); + while (_bufferQueue.Dequeue(queued)) + { + std::size_t packetSize = queued->Buffer.GetActiveSize(); + if (queued->Encrypt) + _crypt.EncryptSend(queued->Buffer.GetReadPointer(), packetSize); + + if (buffer.GetRemainingSpace() < packetSize) + { + QueuePacket(std::move(buffer)); + buffer.Resize(std::size_t(BufferSizes::Read)); + } + + if (buffer.GetRemainingSpace() >= packetSize) + buffer.Write(queued->Buffer.GetReadPointer(), packetSize); + else // single packet larger than 16384 bytes - client will reject. + QueuePacket(std::move(queued->Buffer)); + + delete queued; + } + + if (buffer.GetActiveSize() > 0) + QueuePacket(std::move(buffer)); + if (!BattlenetSocket::Update()) return false; if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - auto callback = std::move(_queryCallback); + auto callback = _queryCallback; _queryCallback = nullptr; callback(_queryFuture.get()); } @@ -679,15 +704,12 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet) packet->Write(); - MessageBuffer buffer; - buffer.Write(packet->GetData(), packet->GetSize()); + EncryptableBuffer* buffer = new EncryptableBuffer(); + buffer->Buffer.Write(packet->GetData(), packet->GetSize()); + buffer->Encrypt = _crypt.IsInitialized(); delete packet; - std::unique_lock guard(_writeLock); - - _crypt.EncryptSend(buffer.GetReadPointer(), buffer.GetActiveSize()); - - QueuePacket(std::move(buffer), guard); + _bufferQueue.Enqueue(buffer); } inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 75c30096417..2443d694a80 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -23,6 +23,7 @@ #include "Socket.h" #include "BigNumber.h" #include "Callback.h" +#include "MPSCQueue.h" #include #include @@ -174,6 +175,13 @@ namespace Battlenet std::queue _modulesWaitingForData; + struct EncryptableBuffer + { + MessageBuffer Buffer; + bool Encrypt; + }; + + MPSCQueue _bufferQueue; PacketCrypt _crypt; bool _authed; bool _subscribedToRealmListUpdates; diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index 8201f4869b4..c53214495d4 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -22,7 +22,8 @@ bool Battlenet::SessionManager::StartNetwork(boost::asio::io_service& service, s if (!BaseSocketMgr::StartNetwork(service, bindIp, port)) return false; - _acceptor->AsyncAcceptManaged(&OnSocketAccept); + _acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this)); + _acceptor->AsyncAcceptWithCallback<&OnSocketAccept>(); return true; } @@ -31,9 +32,9 @@ NetworkThread* Battlenet::SessionManager::CreateThreads() co return new NetworkThread[GetNetworkThreadCount()]; } -void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock) +void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock, uint32 threadIndex) { - sSessionMgr.OnSocketOpen(std::forward(sock)); + sSessionMgr.OnSocketOpen(std::forward(sock), threadIndex); } void Battlenet::SessionManager::AddSession(Session* session) diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index fe262b29f4e..5cf0b199f15 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -75,7 +75,7 @@ namespace Battlenet NetworkThread* CreateThreads() const override; private: - static void OnSocketAccept(tcp::socket&& sock); + static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex); SessionMap _sessions; SessionByAccountMap _sessionsByAccountId; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 8f8c9d89502..acec25a7363 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -38,6 +38,17 @@ struct CompressedWorldPacket uint32 CompressedAdler; }; +class EncryptablePacket : public WorldPacket +{ +public: + EncryptablePacket(WorldPacket const& packet, bool encrypt) : WorldPacket(packet), _encrypt(encrypt) { } + + bool NeedsEncryption() const { return _encrypt; } + +private: + bool _encrypt; +}; + #pragma pack(pop) using boost::asio::ip::tcp; @@ -76,11 +87,8 @@ void WorldSocket::Start() stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); - { - std::lock_guard guard(_queryLock); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1)); - _queryFuture = LoginDatabase.AsyncQuery(stmt); - } + _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); } void WorldSocket::CheckIpCallback(PreparedQueryResult result) @@ -116,23 +124,50 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result) initializer.Write(&header, sizeof(header.Setup.Size)); initializer.Write(ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length()); - std::unique_lock guard(_writeLock); - QueuePacket(std::move(initializer), guard); + // - io_service.run thread, safe. + QueuePacket(std::move(initializer)); } bool WorldSocket::Update() { + EncryptablePacket* queued; + MessageBuffer buffer; + while (_bufferQueue.Dequeue(queued)) + { + uint32 sizeOfHeader = SizeOfServerHeader[queued->NeedsEncryption()]; + uint32 packetSize = queued->size(); + if (packetSize > MinSizeForCompression && queued->NeedsEncryption()) + packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); + + if (buffer.GetRemainingSpace() < packetSize + sizeOfHeader) + { + QueuePacket(std::move(buffer)); + buffer.Resize(4096); + } + + if (buffer.GetRemainingSpace() >= packetSize + sizeOfHeader) + WritePacketToBuffer(*queued, buffer); + else // single packet larger than 4096 bytes + { + MessageBuffer packetBuffer(packetSize + sizeOfHeader); + WritePacketToBuffer(*queued, packetBuffer); + QueuePacket(std::move(packetBuffer)); + } + + delete queued; + } + + if (buffer.GetActiveSize() > 0) + QueuePacket(std::move(buffer)); + if (!BaseSocket::Update()) return false; + if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - std::lock_guard guard(_queryLock); - if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - auto callback = std::move(_queryCallback); - _queryCallback = nullptr; - callback(_queryFuture.get()); - } + auto callback = _queryCallback; + _queryCallback = nullptr; + callback(_queryFuture.get()); } return true; @@ -428,29 +463,13 @@ void WorldSocket::SendPacket(WorldPacket const& packet) if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort(), GetConnectionType()); - uint32 packetSize = packet.size(); - uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; - if (packetSize > MinSizeForCompression && _authCrypt.IsInitialized()) - packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); - - std::unique_lock guard(_writeLock); - -#ifndef TC_SOCKET_USE_IOCP - if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize) - WritePacketToBuffer(packet, _writeBuffer); - else -#endif - { - MessageBuffer buffer(sizeOfHeader + packetSize); - WritePacketToBuffer(packet, buffer); - QueuePacket(std::move(buffer), guard); - } + _bufferQueue.Enqueue(new EncryptablePacket(packet, _authCrypt.IsInitialized())); } -void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer) +void WorldSocket::WritePacketToBuffer(EncryptablePacket const& packet, MessageBuffer& buffer) { ServerPktHeader header; - uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; + uint32 sizeOfHeader = SizeOfServerHeader[packet.NeedsEncryption()]; uint32 opcode = packet.GetOpcode(); uint32 packetSize = packet.size(); @@ -458,7 +477,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* headerPos = buffer.GetWritePointer(); buffer.WriteCompleted(sizeOfHeader); - if (packetSize > MinSizeForCompression && _authCrypt.IsInitialized()) + if (packetSize > MinSizeForCompression && packet.NeedsEncryption()) { CompressedWorldPacket cmp; cmp.UncompressedSize = packetSize + 4; @@ -481,7 +500,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& else if (!packet.empty()) buffer.Write(packet.contents(), packet.size()); - if (_authCrypt.IsInitialized()) + if (packet.NeedsEncryption()) { header.Normal.Size = packetSize; header.Normal.Command = opcode; @@ -598,11 +617,8 @@ void WorldSocket::HandleAuthSession(std::shared_ptrsetInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->Account); - { - std::lock_guard guard(_queryLock); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)); - _queryFuture = LoginDatabase.AsyncQuery(stmt); - } + _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) @@ -768,7 +784,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptrInitWarden(&account.Game.SessionKey, account.BattleNet.OS); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1)); + _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1); _queryFuture = _worldSession->LoadPermissionsAsync(); AsyncRead(); } @@ -801,11 +817,8 @@ void WorldSocket::HandleAuthContinuedSession(std::shared_ptrsetUInt32(0, accountId); - { - std::lock_guard guard(_queryLock); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1)); - _queryFuture = LoginDatabase.AsyncQuery(stmt); - } + _queryCallback = std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); } void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index d6d29fb2826..205494ca4ea 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -26,11 +26,13 @@ #include "Util.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "MPSCQueue.h" #include #include using boost::asio::ip::tcp; struct z_stream_s; +class EncryptablePacket; namespace WorldPackets { @@ -111,7 +113,7 @@ private: void LogOpcodeText(OpcodeClient opcode, std::unique_lock const& guard) const; /// sends and logs network.opcode without accessing WorldSession void SendPacketAndLogOpcode(WorldPacket const& packet); - void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer); + void WritePacketToBuffer(EncryptablePacket const& packet, MessageBuffer& buffer); uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); void HandleSendAuthSession(); @@ -142,12 +144,12 @@ private: MessageBuffer _headerBuffer; MessageBuffer _packetBuffer; + MPSCQueue _bufferQueue; z_stream_s* _compressionStream; bool _initialized; - std::mutex _queryLock; PreparedQueryResultFuture _queryFuture; std::function _queryCallback; std::string _ipCountry; diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 937483e1179..94c5a8f6979 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -24,9 +24,9 @@ #include -static void OnSocketAccept(tcp::socket&& sock) +static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex) { - sWorldSocketMgr.OnSocketOpen(std::forward(sock)); + sWorldSocketMgr.OnSocketOpen(std::forward(sock), threadIndex); } class WorldSocketThread : public NetworkThread @@ -73,8 +73,11 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string BaseSocketMgr::StartNetwork(service, bindIp, port); _instanceAcceptor = new AsyncAcceptor(service, bindIp, uint16(sWorld->getIntConfig(CONFIG_PORT_INSTANCE))); - _acceptor->AsyncAcceptManaged(&OnSocketAccept); - _instanceAcceptor->AsyncAcceptManaged(&OnSocketAccept); + _acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this)); + _instanceAcceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this)); + + _acceptor->AsyncAcceptWithCallback<&OnSocketAccept>(); + _instanceAcceptor->AsyncAcceptWithCallback<&OnSocketAccept>(); sScriptMgr->OnNetworkStart(); return true; @@ -87,7 +90,7 @@ void WorldSocketMgr::StopNetwork() sScriptMgr->OnNetworkStop(); } -void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock) +void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) { // set some options here if (_socketSendBufferSize >= 0) @@ -115,7 +118,7 @@ void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock) //sock->m_OutBufferSize = static_cast (m_SockOutUBuff); - BaseSocketMgr::OnSocketOpen(std::forward(sock)); + BaseSocketMgr::OnSocketOpen(std::forward(sock), threadIndex); } NetworkThread* WorldSocketMgr::CreateThreads() const diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index d4bf4115deb..2079b62d14f 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -49,7 +49,7 @@ public: /// Stops all network threads, It will wait for all running threads . void StopNetwork() override; - void OnSocketOpen(tcp::socket&& sock) override; + void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) override; protected: WorldSocketMgr(); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 331c2114b4e..d2ccb025165 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -227,7 +227,7 @@ void World::AddSession(WorldSession* s) addSessQueue.add(s); } -void World::AddInstanceSocket(std::shared_ptr sock, uint64 connectToKey) +void World::AddInstanceSocket(std::weak_ptr sock, uint64 connectToKey) { _linkSocketQueue.add(std::make_pair(sock, connectToKey)); } @@ -298,25 +298,28 @@ void World::AddSession_(WorldSession* s) } } -void World::ProcessLinkInstanceSocket(std::pair, uint64> linkInfo) +void World::ProcessLinkInstanceSocket(std::pair, uint64> linkInfo) { - if (!linkInfo.first->IsOpen()) - return; - - WorldSession::ConnectToKey key; - key.Raw = linkInfo.second; - - WorldSession* session = FindSession(uint32(key.Fields.AccountId)); - if (!session || session->GetConnectToInstanceKey() != linkInfo.second) + if (std::shared_ptr sock = linkInfo.first.lock()) { - linkInfo.first->SendAuthResponseError(AUTH_SESSION_EXPIRED); - linkInfo.first->DelayedCloseSocket(); - return; - } + if (!sock->IsOpen()) + return; - linkInfo.first->SetWorldSession(session); - session->AddInstanceConnection(linkInfo.first); - session->HandleContinuePlayerLogin(); + WorldSession::ConnectToKey key; + key.Raw = linkInfo.second; + + WorldSession* session = FindSession(uint32(key.Fields.AccountId)); + if (!session || session->GetConnectToInstanceKey() != linkInfo.second) + { + sock->SendAuthResponseError(AUTH_SESSION_EXPIRED); + sock->DelayedCloseSocket(); + return; + } + + sock->SetWorldSession(session); + session->AddInstanceConnection(sock); + session->HandleContinuePlayerLogin(); + } } bool World::HasRecentlyDisconnected(WorldSession* session) @@ -2821,7 +2824,7 @@ void World::SendServerMessage(ServerMessageType messageID, std::string stringPar void World::UpdateSessions(uint32 diff) { - std::pair, uint64> linkInfo; + std::pair, uint64> linkInfo; while (_linkSocketQueue.next(linkInfo)) ProcessLinkInstanceSocket(std::move(linkInfo)); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index d28738ffc8c..0f9a27c733f 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -568,7 +568,7 @@ class World WorldSession* FindSession(uint32 id) const; void AddSession(WorldSession* s); - void AddInstanceSocket(std::shared_ptr sock, uint64 connectToKey); + void AddInstanceSocket(std::weak_ptr sock, uint64 connectToKey); void SendAutoBroadcast(); bool RemoveSession(uint32 id); /// Get the number of current active sessions @@ -878,8 +878,8 @@ class World void AddSession_(WorldSession* s); LockedQueue addSessQueue; - void ProcessLinkInstanceSocket(std::pair, uint64> linkInfo); - LockedQueue, uint64>> _linkSocketQueue; + void ProcessLinkInstanceSocket(std::pair, uint64> linkInfo); + LockedQueue, uint64>> _linkSocketQueue; // used versions std::string m_DBVersion; diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index 2fa1e448ff8..d21801a64ac 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -20,34 +20,39 @@ #include "Log.h" #include +#include using boost::asio::ip::tcp; class AsyncAcceptor { public: - typedef void(*ManagerAcceptHandler)(tcp::socket&& newSocket); + typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex); AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) : _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)), - _socket(ioService), _closed(false) + _socket(ioService), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this)) { } - template + template void AsyncAccept(); - void AsyncAcceptManaged(ManagerAcceptHandler mgrHandler) + template + void AsyncAcceptWithCallback() { - _acceptor.async_accept(_socket, [this, mgrHandler](boost::system::error_code error) + tcp::socket* socket; + uint32 threadIndex; + std::tie(socket, threadIndex) = _socketFactory(); + _acceptor.async_accept(*socket, [this, socket, threadIndex](boost::system::error_code error) { if (!error) { try { - _socket.non_blocking(true); + socket->non_blocking(true); - mgrHandler(std::move(_socket)); + acceptCallback(std::move(*socket), threadIndex); } catch (boost::system::system_error const& err) { @@ -56,7 +61,7 @@ public: } if (!_closed) - AsyncAcceptManaged(mgrHandler); + this->AsyncAcceptWithCallback(); }); } @@ -69,10 +74,15 @@ public: _acceptor.close(err); } + void SetSocketFactory(std::function()> func) { _socketFactory = func; } + private: + std::pair DefeaultSocketFactory() { return std::make_pair(&_socket, 0); } + tcp::acceptor _acceptor; tcp::socket _socket; std::atomic _closed; + std::function()> _socketFactory; }; template diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index a6ed9b31e8f..42b65be8398 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -105,7 +105,7 @@ public: return std::move(_storage); } - MessageBuffer& operator=(MessageBuffer& right) + MessageBuffer& operator=(MessageBuffer const& right) { if (this != &right) { diff --git a/src/server/shared/Networking/NetworkThread.h b/src/server/shared/Networking/NetworkThread.h index e183209e989..5eb2fcb2f6a 100644 --- a/src/server/shared/Networking/NetworkThread.h +++ b/src/server/shared/Networking/NetworkThread.h @@ -22,6 +22,8 @@ #include "Errors.h" #include "Log.h" #include "Timer.h" +#include +#include #include #include #include @@ -29,11 +31,14 @@ #include #include +using boost::asio::ip::tcp; + template class NetworkThread { public: - NetworkThread() : _connections(0), _stopped(false), _thread(nullptr) + NetworkThread() : _connections(0), _stopped(false), _thread(nullptr), + _acceptSocket(_io_service), _updateTimer(_io_service) { } @@ -50,6 +55,7 @@ public: void Stop() { _stopped = true; + _io_service.stop(); } bool Start() @@ -80,10 +86,12 @@ public: std::lock_guard lock(_newSocketsLock); ++_connections; - _newSockets.insert(sock); + _newSockets.push_back(sock); SocketAdded(sock); } + tcp::socket* GetSocketForAccept() { return &_acceptSocket; } + protected: virtual void SocketAdded(std::shared_ptr /*sock*/) { } virtual void SocketRemoved(std::shared_ptr /*sock*/) { } @@ -95,16 +103,15 @@ protected: if (_newSockets.empty()) return; - for (typename SocketSet::const_iterator i = _newSockets.begin(); i != _newSockets.end(); ++i) + for (std::shared_ptr sock : _newSockets) { - if (!(*i)->IsOpen()) + if (!sock->IsOpen()) { - SocketRemoved(*i); - + SocketRemoved(sock); --_connections; } else - _Sockets.insert(*i); + _sockets.push_back(sock); } _newSockets.clear(); @@ -114,55 +121,58 @@ protected: { TC_LOG_DEBUG("misc", "Network Thread Starting"); - typename SocketSet::iterator i, t; - - uint32 sleepTime = 10; - uint32 tickStart = 0, diff = 0; - while (!_stopped) - { - std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); - - tickStart = getMSTime(); - - AddNewSockets(); - - for (i = _Sockets.begin(); i != _Sockets.end();) - { - if (!(*i)->Update()) - { - if ((*i)->IsOpen()) - (*i)->CloseSocket(); - - SocketRemoved(*i); - - --_connections; - _Sockets.erase(i++); - } - else - ++i; - } - - diff = GetMSTimeDiffToNow(tickStart); - sleepTime = diff > 10 ? 0 : 10 - diff; - } + _updateTimer.expires_from_now(boost::posix_time::milliseconds(10)); + _updateTimer.async_wait(std::bind(&NetworkThread::Update, this)); + _io_service.run(); TC_LOG_DEBUG("misc", "Network Thread exits"); _newSockets.clear(); - _Sockets.clear(); + _sockets.clear(); + } + + void Update() + { + if (_stopped) + return; + + _updateTimer.expires_from_now(boost::posix_time::milliseconds(10)); + _updateTimer.async_wait(std::bind(&NetworkThread::Update, this)); + + AddNewSockets(); + + _sockets.erase(std::remove_if(_sockets.begin(), _sockets.end(), [this](std::shared_ptr sock) + { + if (!sock->Update()) + { + if (sock->IsOpen()) + sock->CloseSocket(); + + SocketRemoved(sock); + + --_connections; + return true; + } + + return false; + }), _sockets.end()); } private: - typedef std::set > SocketSet; + typedef std::vector> SocketContainer; std::atomic _connections; std::atomic _stopped; std::thread* _thread; - SocketSet _Sockets; + SocketContainer _sockets; std::mutex _newSocketsLock; - SocketSet _newSockets; + SocketContainer _newSockets; + + boost::asio::io_service _io_service; + tcp::socket _acceptSocket; + boost::asio::deadline_timer _updateTimer; }; #endif // NetworkThread_h__ diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index 34ee50eb84e..07f427652aa 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -21,15 +21,11 @@ #include "MessageBuffer.h" #include "Log.h" #include -#include -#include #include #include #include #include #include -#include -#include using boost::asio::ip::tcp; @@ -63,14 +59,10 @@ public: return false; #ifndef TC_SOCKET_USE_IOCP - std::unique_lock guard(_writeLock); - if (!guard) + if (_isWritingAsync || _writeQueue.empty()) return true; - if (_isWritingAsync || (!_writeBuffer.GetActiveSize() && _writeQueue.empty())) - return true; - - for (; WriteHandler(guard);) + for (; HandleQueue();) ; #endif @@ -98,14 +90,12 @@ public: std::bind(&Socket::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } - void QueuePacket(MessageBuffer&& buffer, std::unique_lock& guard) + void QueuePacket(MessageBuffer&& buffer) { _writeQueue.push(std::move(buffer)); #ifdef TC_SOCKET_USE_IOCP - AsyncProcessQueue(guard); -#else - (void)guard; + AsyncProcessQueue(); #endif } @@ -135,7 +125,7 @@ protected: virtual void ReadHandler() = 0; - bool AsyncProcessQueue(std::unique_lock&) + bool AsyncProcessQueue() { if (_isWritingAsync) return false; @@ -157,19 +147,12 @@ protected: void SetNoDelay(bool enable) { boost::system::error_code err; - _socket.set_option(boost::asio::ip::tcp::no_delay(enable), err); + _socket.set_option(tcp::no_delay(enable), err); if (err) TC_LOG_DEBUG("network", "Socket::SetNoDelay: failed to set_option(boost::asio::ip::tcp::no_delay) for %s - %d (%s)", GetRemoteIpAddress().to_string().c_str(), err.value(), err.message().c_str()); } - std::mutex _writeLock; - std::queue _writeQueue; -#ifndef TC_SOCKET_USE_IOCP - MessageBuffer _writeBuffer; -#endif - - boost::asio::io_service& io_service() { return _socket.get_io_service(); } private: void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes) @@ -190,15 +173,13 @@ private: { if (!error) { - std::unique_lock deleteGuard(_writeLock); - _isWritingAsync = false; _writeQueue.front().ReadCompleted(transferedBytes); if (!_writeQueue.front().GetActiveSize()) _writeQueue.pop(); if (!_writeQueue.empty()) - AsyncProcessQueue(deleteGuard); + AsyncProcessQueue(); else if (_closing) CloseSocket(); } @@ -210,48 +191,15 @@ private: void WriteHandlerWrapper(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/) { - std::unique_lock guard(_writeLock); _isWritingAsync = false; - WriteHandler(guard); + HandleQueue(); } - bool WriteHandler(std::unique_lock& guard) + bool HandleQueue() { if (!IsOpen()) return false; - std::size_t bytesToSend = _writeBuffer.GetActiveSize(); - - if (bytesToSend == 0) - return HandleQueue(guard); - - boost::system::error_code error; - std::size_t bytesWritten = _socket.write_some(boost::asio::buffer(_writeBuffer.GetReadPointer(), bytesToSend), error); - - if (error) - { - if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) - return AsyncProcessQueue(guard); - - return false; - } - else if (bytesWritten == 0) - return false; - else if (bytesWritten < bytesToSend) - { - _writeBuffer.ReadCompleted(bytesWritten); - _writeBuffer.Normalize(); - return AsyncProcessQueue(guard); - } - - // now bytesWritten == bytesToSend - _writeBuffer.Reset(); - - return HandleQueue(guard); - } - - bool HandleQueue(std::unique_lock& guard) - { if (_writeQueue.empty()) return false; @@ -265,7 +213,7 @@ private: if (error) { if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) - return AsyncProcessQueue(guard); + return AsyncProcessQueue(); _writeQueue.pop(); return false; @@ -278,7 +226,7 @@ private: else if (bytesSent < bytesToSend) // now n > 0 { queuedMessage.ReadCompleted(bytesSent); - return AsyncProcessQueue(guard); + return AsyncProcessQueue(); } _writeQueue.pop(); @@ -293,6 +241,7 @@ private: uint16 _remotePort; MessageBuffer _readBuffer; + std::queue _writeQueue; std::atomic _closed; std::atomic _closing; diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h index 4037c85baa1..b14aac4ca47 100644 --- a/src/server/shared/Networking/SocketMgr.h +++ b/src/server/shared/Networking/SocketMgr.h @@ -90,20 +90,14 @@ public: _threads[i].Wait(); } - virtual void OnSocketOpen(tcp::socket&& sock) + virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) { - size_t min = 0; - - for (int32 i = 1; i < _threadCount; ++i) - if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount()) - min = i; - try { std::shared_ptr newSocket = std::make_shared(std::move(sock)); newSocket->Start(); - _threads[min].AddSocket(newSocket); + _threads[threadIndex].AddSocket(newSocket); } catch (boost::system::system_error const& err) { @@ -113,6 +107,23 @@ public: int32 GetNetworkThreadCount() const { return _threadCount; } + uint32 SelectThreadWithMinConnections() const + { + uint32 min = 0; + + for (int32 i = 1; i < _threadCount; ++i) + if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount()) + min = i; + + return min; + } + + std::pair GetSocketForAccept() + { + uint32 threadIndex = SelectThreadWithMinConnections(); + return std::make_pair(_threads[threadIndex].GetSocketForAccept(), threadIndex); + } + protected: SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(1) { From 2a186f29f4e5fd31b7ac2aa9eb2701d190259eb5 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 20 Feb 2016 12:57:38 +0100 Subject: [PATCH 78/79] Core/Networking: Close the instance socket acceptor on shutdown --- src/server/game/Server/WorldSocketMgr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 94c5a8f6979..4f42e943245 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -49,7 +49,7 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _instanceAcceptor(nullptr), WorldSocketMgr::~WorldSocketMgr() { - delete _instanceAcceptor; + ASSERT(!_instanceAcceptor, "StopNetwork must be called prior to WorldSocketMgr destruction"); } bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) @@ -85,8 +85,12 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string void WorldSocketMgr::StopNetwork() { + _instanceAcceptor->Close(); BaseSocketMgr::StopNetwork(); + delete _instanceAcceptor; + _instanceAcceptor = nullptr; + sScriptMgr->OnNetworkStop(); } From 716c952cb9f7bc0f75308bb4a716cdfe7de17281 Mon Sep 17 00:00:00 2001 From: Naios Date: Sat, 20 Feb 2016 20:18:42 +0100 Subject: [PATCH 79/79] Core/Updater: Use a different method for file reading * Current method causes issues under CentOS 6 and could possibly lead to cutted buffer content when reading in textmode. * Closes #16209 (cherry picked from commit ae1a5c6c2b82918850cb7b851e2f7dff33a40c57) --- src/server/database/Updater/UpdateFetcher.cpp | 12 +++++------- src/server/database/Updater/UpdateFetcher.h | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index fd0dbdd4b5a..001fdf20610 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -142,14 +142,12 @@ UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path co std::ifstream in(file.c_str()); WPFatal(in.is_open(), "Could not read an update file."); - auto const start_pos = in.tellg(); - in.ignore(std::numeric_limits::max()); - auto const char_count = in.gcount(); - in.seekg(start_pos); + auto update = [&in] { + std::ostringstream ss; + ss << in.rdbuf(); + return Trinity::make_unique(ss.str()); + }(); - SQLUpdate const update(new std::string(char_count, char{})); - - in.read(&(*update)[0], update->size()); in.close(); return update; } diff --git a/src/server/database/Updater/UpdateFetcher.h b/src/server/database/Updater/UpdateFetcher.h index 22a0d08c7f8..32f8516413d 100644 --- a/src/server/database/Updater/UpdateFetcher.h +++ b/src/server/database/Updater/UpdateFetcher.h @@ -103,7 +103,7 @@ private: typedef std::unordered_map HashToFileNameStorage; typedef std::unordered_map AppliedFileStorage; typedef std::vector DirectoryStorage; - typedef std::shared_ptr SQLUpdate; + typedef std::unique_ptr SQLUpdate; LocaleFileStorage GetFileList() const; void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const;