Core/Garrisons: Added more building checks and implemented canceling building construction

This commit is contained in:
Shauren
2015-05-11 18:23:43 +02:00
parent 3c79914e7b
commit 9d4c568596
9 changed files with 267 additions and 27 deletions

View File

@@ -210,6 +210,15 @@ Garrison::Plot* Garrison::GetPlot(uint32 garrPlotInstanceId)
return nullptr;
}
Garrison::Plot const* Garrison::GetPlot(uint32 garrPlotInstanceId) const
{
auto itr = _plots.find(garrPlotInstanceId);
if (itr != _plots.end())
return &itr->second;
return nullptr;
}
void Garrison::LearnBlueprint(uint32 garrBuildingId)
{
WorldPackets::Garrison::GarrisonLearnBlueprintResult learnBlueprintResult;
@@ -253,33 +262,88 @@ void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId)
placeBuildingResult.BuildingInfo.TimeBuilt = time(nullptr);
Plot* plot = GetPlot(garrPlotInstanceId);
uint32 oldBuildingId = 0;
Map* map = FindMap();
GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId);
if (map)
plot->DeleteGameObject(map);
if (Map* map = FindMap())
if (plot->BuildingInfo.PacketInfo)
{
if (!plot->BuildingInfo.Guid.IsEmpty())
{
if (GameObject* oldBuilding = map->GetGameObject(plot->BuildingInfo.Guid))
oldBuilding->AddObjectToRemoveList();
oldBuildingId = plot->BuildingInfo.PacketInfo->GarrBuildingID;
if (sGarrBuildingStore.AssertEntry(oldBuildingId)->Type != building->Type)
plot->ClearBuildingInfo(_owner);
}
plot->BuildingInfo.Guid.Clear();
}
plot->BuildingInfo.PacketInfo = placeBuildingResult.BuildingInfo;
plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
if (map)
if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
{
map->AddToMap(go);
GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId);
_owner->ModifyCurrency(building->CostCurrencyID, -building->CostCurrencyAmount, false, true);
_owner->ModifyMoney(-building->CostMoney, false);
}
else
plot->BuildingInfo.PacketInfo = boost::none;
_owner->ModifyCurrency(building->CostCurrencyID, -building->CostCurrencyAmount, false, true);
_owner->ModifyMoney(-building->CostMoney * GOLD, false);
if (oldBuildingId)
{
WorldPackets::Garrison::GarrisonBuildingRemoved buildingRemoved;
buildingRemoved.Result = GARRISON_SUCCESS;
buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
buildingRemoved.GarrBuildingID = oldBuildingId;
_owner->SendDirectMessage(buildingRemoved.Write());
}
}
_owner->SendDirectMessage(placeBuildingResult.Write());
}
void Garrison::CancelBuildingConstruction(uint32 garrPlotInstanceId)
{
WorldPackets::Garrison::GarrisonBuildingRemoved buildingRemoved;
buildingRemoved.Result = CheckBuildingRemoval(garrPlotInstanceId);
if (buildingRemoved.Result == GARRISON_SUCCESS)
{
Plot* plot = GetPlot(garrPlotInstanceId);
buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
buildingRemoved.GarrBuildingID = plot->BuildingInfo.PacketInfo->GarrBuildingID;
Map* map = FindMap();
if (map)
plot->DeleteGameObject(map);
plot->ClearBuildingInfo(_owner);
_owner->SendDirectMessage(buildingRemoved.Write());
GarrBuildingEntry const* constructing = sGarrBuildingStore.AssertEntry(buildingRemoved.GarrBuildingID);
// Refund construction/upgrade cost
_owner->ModifyCurrency(constructing->CostCurrencyID, constructing->CostCurrencyAmount, false, true);
_owner->ModifyMoney(constructing->CostMoney * GOLD, false);
if (constructing->Level > 1)
{
// Restore previous level building
GarrBuildingEntry const* restored = sGarrisonMgr.GetPreviousLevelBuilding(constructing->Type, constructing->Level);
ASSERT(restored);
WorldPackets::Garrison::GarrisonPlaceBuildingResult placeBuildingResult;
placeBuildingResult.Result = GARRISON_SUCCESS;
placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId;
placeBuildingResult.BuildingInfo.GarrBuildingID = restored->ID;
placeBuildingResult.BuildingInfo.TimeBuilt = time(nullptr);
placeBuildingResult.BuildingInfo.Active = true;
plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
_owner->SendDirectMessage(placeBuildingResult.Write());
}
if (map)
if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
map->AddToMap(go);
}
else
_owner->SendDirectMessage(buildingRemoved.Write());
}
void Garrison::SendInfo()
{
WorldPackets::Garrison::GetGarrisonInfoResult garrisonInfo;
@@ -347,7 +411,8 @@ Map* Garrison::FindMap() const
GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const
{
GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId);
if (!plotInstance || !_plots.count(garrPlotInstanceId))
Plot const* plot = GetPlot(garrPlotInstanceId);
if (!plotInstance || !plot)
return GARRISON_ERROR_INVALID_PLOT;
GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(garrBuildingId);
@@ -357,9 +422,13 @@ GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32
if (!sGarrisonMgr.IsPlotMatchingBuilding(plotInstance->GarrPlotID, garrBuildingId))
return GARRISON_ERROR_INVALID_PLOT_BUILDING;
// Cannot place buldings of higher level than garrison level
if (building->Level > _siteLevel->Level)
return GARRISON_ERROR_INVALID_BUILDINGID;
if (building->Flags & GARRISON_BUILDING_FLAG_NEEDS_PLAN)
{
if (_knownBuildings.count(garrBuildingId))
if (!_knownBuildings.count(garrBuildingId))
return GARRISON_ERROR_BLUEPRINT_NOT_KNOWN;
}
else // Building is built as a quest reward
@@ -373,7 +442,7 @@ GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32
{
existingBuilding = sGarrBuildingStore.AssertEntry(p.second.BuildingInfo.PacketInfo->GarrBuildingID);
if (existingBuilding->Type == building->Type)
if (p.first != garrPlotInstanceId || existingBuilding->Level != building->Level + 1) // check if its an upgrade in same plot
if (p.first != garrPlotInstanceId || existingBuilding->Level + 1 != building->Level) // check if its an upgrade in same plot
return GARRISON_ERROR_BUILDING_EXISTS;
}
}
@@ -381,9 +450,29 @@ GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32
if (!_owner->HasCurrency(building->CostCurrencyID, building->CostCurrencyAmount))
return GARRISON_ERROR_NOT_ENOUGH_CURRENCY;
if (!_owner->HasEnoughMoney(uint64(building->CostMoney)))
if (!_owner->HasEnoughMoney(uint64(building->CostMoney * GOLD)))
return GARRISON_ERROR_NOT_ENOUGH_GOLD;
// New building cannot replace another building currently under construction
if (plot->BuildingInfo.PacketInfo)
if (!plot->BuildingInfo.PacketInfo->Active)
return GARRISON_ERROR_NO_BUILDING;
return GARRISON_SUCCESS;
}
GarrisonError Garrison::CheckBuildingRemoval(uint32 garrPlotInstanceId) const
{
Plot const* plot = GetPlot(garrPlotInstanceId);
if (!plot)
return GARRISON_ERROR_INVALID_PLOT;
if (!plot->BuildingInfo.PacketInfo)
return GARRISON_ERROR_NO_BUILDING;
if (plot->BuildingInfo.CanActivate())
return GARRISON_ERROR_BUILDING_EXISTS;
return GARRISON_SUCCESS;
}
@@ -395,7 +484,7 @@ GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex fact
GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.AssertEntry(PacketInfo.GarrPlotInstanceID);
GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID);
GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID);
if (BuildingInfo.PacketInfo->TimeBuilt + building->BuildDuration <= time(nullptr) && BuildingInfo.PacketInfo->Active)
if (BuildingInfo.PacketInfo->Active)
entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID;
else
entry = faction == GARRISON_FACTION_INDEX_HORDE ? plot->HordeConstructionGameObjectID : plot->AllianceConstructionGameObjectID;
@@ -419,3 +508,47 @@ GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex fact
BuildingInfo.Guid = go->GetGUID();
return go;
}
void Garrison::Plot::DeleteGameObject(Map* map)
{
if (BuildingInfo.Guid.IsEmpty())
return;
if (GameObject* oldBuilding = map->GetGameObject(BuildingInfo.Guid))
oldBuilding->Delete();
BuildingInfo.Guid.Clear();
}
void Garrison::Plot::ClearBuildingInfo(Player* owner)
{
WorldPackets::Garrison::GarrisonPlotPlaced plotPlaced;
plotPlaced.PlotInfo = &PacketInfo;
owner->SendDirectMessage(plotPlaced.Write());
BuildingInfo.PacketInfo = boost::none;
}
void Garrison::Plot::SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner)
{
if (!BuildingInfo.PacketInfo)
{
WorldPackets::Garrison::GarrisonPlotRemoved plotRemoved;
plotRemoved.GarrPlotInstanceID = PacketInfo.GarrPlotInstanceID;
owner->SendDirectMessage(plotRemoved.Write());
}
BuildingInfo.PacketInfo = buildingInfo;
}
bool Garrison::Building::CanActivate() const
{
if (PacketInfo)
{
GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(PacketInfo->GarrBuildingID);
if (PacketInfo->TimeBuilt + building->BuildDuration <= time(nullptr))
return true;
}
return false;
}

View File

@@ -62,6 +62,8 @@ class Garrison
public:
struct Building
{
bool CanActivate() const;
ObjectGuid Guid;
Optional<WorldPackets::Garrison::GarrisonBuildingInfo> PacketInfo;
};
@@ -69,6 +71,9 @@ public:
struct Plot
{
GameObject* CreateGameObject(Map* map, GarrisonFactionIndex faction);
void DeleteGameObject(Map* map);
void ClearBuildingInfo(Player* owner);
void SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner);
WorldPackets::Garrison::GarrisonPlotInfo PacketInfo;
uint32 EmptyGameObjectId = 0;
@@ -90,10 +95,12 @@ public:
GarrisonFactionIndex GetFaction() const;
std::vector<Plot*> GetPlots();
Plot* GetPlot(uint32 garrPlotInstanceId);
Plot const* GetPlot(uint32 garrPlotInstanceId) const;
void LearnBlueprint(uint32 garrBuildingId);
void UnlearnBlueprint(uint32 garrBuildingId);
void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId);
void CancelBuildingConstruction(uint32 garrPlotInstanceId);
void SendInfo();
void SendRemoteInfo() const;
@@ -106,6 +113,7 @@ private:
Map* FindMap() const;
void InitializePlots();
GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const;
GarrisonError CheckBuildingRemoval(uint32 garrPlotInstanceId) const;
Player* _owner;
GarrSiteLevelEntry const* _siteLevel;
uint32 _followerActivationsRemainingToday;

View File

@@ -32,6 +32,9 @@ void GarrisonMgr::Initialize()
for (GarrBuildingPlotInstEntry const* buildingPlotInst : sGarrBuildingPlotInstStore)
_garrisonBuildingPlotInstances[MAKE_PAIR64(buildingPlotInst->GarrBuildingID, buildingPlotInst->GarrSiteLevelPlotInstID)] = buildingPlotInst->ID;
for (GarrBuildingEntry const* building : sGarrBuildingStore)
_garrisonBuildingsByType[building->Type].push_back(building);
}
GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const
@@ -82,3 +85,14 @@ uint32 GarrisonMgr::GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSi
return 0;
}
GarrBuildingEntry const* GarrisonMgr::GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const
{
auto itr = _garrisonBuildingsByType.find(buildingType);
if (itr != _garrisonBuildingsByType.end())
for (GarrBuildingEntry const* building : itr->second)
if (building->Level == currentLevel - 1)
return building;
return nullptr;
}

View File

@@ -38,12 +38,14 @@ public:
GameObjectsEntry const* GetPlotGameObject(uint32 mapId, uint32 garrPlotInstanceId) const;
bool IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const;
uint32 GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const;
GarrBuildingEntry const* GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const;
private:
std::unordered_map<uint32 /*garrSiteId*/, std::vector<GarrSiteLevelPlotInstEntry const*>> _garrisonPlotInstBySiteLevel;
std::unordered_map<uint32 /*mapId*/, std::unordered_map<uint32 /*garrPlotId*/, GameObjectsEntry const*>> _garrisonPlots;
std::unordered_map<uint32 /*garrPlotId*/, std::unordered_set<uint32/*garrBuildingId*/>> _garrisonBuildingsByPlot;
std::unordered_map<uint64 /*garrBuildingId | garrSiteLevelPlotInstId << 32*/, uint32 /*garrBuildingPlotInstId*/> _garrisonBuildingPlotInstances;
std::unordered_map<uint32 /*buildingType*/, std::vector<GarrBuildingEntry const*>> _garrisonBuildingsByType;
};
#define sGarrisonMgr GarrisonMgr::Instance()

View File

@@ -34,6 +34,15 @@ void WorldSession::HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::Garris
garrison->PlaceBuilding(garrisonPurchaseBuilding.PlotInstanceID, garrisonPurchaseBuilding.BuildingID);
}
void WorldSession::HandleGarrisonCancelConstruction(WorldPackets::Garrison::GarrisonCancelConstruction& garrisonCancelConstruction)
{
if (!_player->GetNPCIfCanInteractWith(garrisonCancelConstruction.NpcGUID, UNIT_NPC_FLAG_GARRISON_ARCHITECT))
return;
if (Garrison* garrison = _player->GetGarrison())
garrison->CancelBuildingConstruction(garrisonCancelConstruction.PlotInstanceID);
}
void WorldSession::HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& /*garrisonRequestBlueprintAndSpecializationData*/)
{
if (Garrison* garrison = _player->GetGarrison())

View File

@@ -155,12 +155,27 @@ WorldPacket const* WorldPackets::Garrison::GarrisonPlaceBuildingResult::Write()
{
_worldPacket << uint32(Result);
_worldPacket << BuildingInfo;
_worldPacket.WriteBit(Active);
_worldPacket.WriteBit(PlayActivationCinematic);
_worldPacket.FlushBits();
return &_worldPacket;
}
void WorldPackets::Garrison::GarrisonCancelConstruction::Read()
{
_worldPacket >> NpcGUID;
_worldPacket >> PlotInstanceID;
}
WorldPacket const* WorldPackets::Garrison::GarrisonBuildingRemoved::Write()
{
_worldPacket << uint32(Result);
_worldPacket << uint32(GarrPlotInstanceID);
_worldPacket << uint32(GarrBuildingID);
return &_worldPacket;
}
WorldPacket const* WorldPackets::Garrison::GarrisonLearnBlueprintResult::Write()
{
_worldPacket << uint32(Result);
@@ -208,3 +223,17 @@ WorldPacket const* WorldPackets::Garrison::GarrisonBuildingLandmarks::Write()
return &_worldPacket;
}
WorldPacket const* WorldPackets::Garrison::GarrisonPlotPlaced::Write()
{
_worldPacket << *PlotInfo;
return &_worldPacket;
}
WorldPacket const* WorldPackets::Garrison::GarrisonPlotRemoved::Write()
{
_worldPacket << uint32(GarrPlotInstanceID);
return &_worldPacket;
}

View File

@@ -154,7 +154,30 @@ namespace WorldPackets
uint32 Result = 0;
GarrisonBuildingInfo BuildingInfo;
bool Active = false;
bool PlayActivationCinematic = false;
};
class GarrisonCancelConstruction final : public ClientPacket
{
public:
GarrisonCancelConstruction(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_CANCEL_CONSTRUCTION, std::move(packet)) { }
void Read() override;
ObjectGuid NpcGUID;
uint32 PlotInstanceID = 0;
};
class GarrisonBuildingRemoved final : public ServerPacket
{
public:
GarrisonBuildingRemoved() : ServerPacket(SMSG_GARRISON_BUILDING_REMOVED, 4 + 4 + 4) { }
WorldPacket const* Write() override;
uint32 Result = 0;
uint32 GarrPlotInstanceID = 0;
uint32 GarrBuildingID = 0;
};
class GarrisonLearnBlueprintResult final : public ServerPacket
@@ -224,6 +247,26 @@ namespace WorldPackets
std::vector<GarrisonBuildingLandmark> Landmarks;
};
class GarrisonPlotPlaced final : public ServerPacket
{
public:
GarrisonPlotPlaced() : ServerPacket(SMSG_GARRISON_PLOT_PLACED) { }
WorldPacket const* Write() override;
GarrisonPlotInfo* PlotInfo = nullptr;
};
class GarrisonPlotRemoved final : public ServerPacket
{
public:
GarrisonPlotRemoved() : ServerPacket(SMSG_GARRISON_PLOT_REMOVED, 4) { }
WorldPacket const* Write() override;
uint32 GarrPlotInstanceID = 0;
};
}
}

View File

@@ -370,7 +370,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_GAME_OBJ_REPORT_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjReportUse, &WorldSession::HandleGameobjectReportUse);
DEFINE_HANDLER(CMSG_GAME_OBJ_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjUse, &WorldSession::HandleGameObjectUseOpcode);
DEFINE_HANDLER(CMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GARRISON_CANCEL_CONSTRUCTION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GARRISON_CANCEL_CONSTRUCTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonCancelConstruction, &WorldSession::HandleGarrisonCancelConstruction);
DEFINE_HANDLER(CMSG_GARRISON_CHECK_UPGRADEABLE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GARRISON_COMPLETE_MISSION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GARRISON_GENERATE_RECRUITS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL);
@@ -1114,7 +1114,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_ACTIVATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_LANDMARKS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_SET_ACTIVE_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_CREATE_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
@@ -1134,8 +1134,8 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_LAST_USED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_USED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUITMENT_FOLLOWERS_GENERATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);

View File

@@ -218,6 +218,7 @@ namespace WorldPackets
{
class GetGarrisonInfo;
class GarrisonPurchaseBuilding;
class GarrisonCancelConstruction;
class GarrisonRequestBlueprintAndSpecializationData;
class GarrisonGetBuildingLandmarks;
}
@@ -1475,6 +1476,7 @@ class WorldSession
// Garrison
void HandleGetGarrisonInfo(WorldPackets::Garrison::GetGarrisonInfo& getGarrisonInfo);
void HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::GarrisonPurchaseBuilding& garrisonPurchaseBuilding);
void HandleGarrisonCancelConstruction(WorldPackets::Garrison::GarrisonCancelConstruction& garrisonCancelConstruction);
void HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& garrisonRequestBlueprintAndSpecializationData);
void HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& garrisonGetBuildingLandmarks);