mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-14 11:52:25 +00:00
Add expedition event loot api
Add SetLootEventByNPCTypeID and SetLootEventBySpawnID quest apis These associate events with npcs or entities inside the dz to prevent them from being looted by characters that didn't receive the event lockout from the current expedition. This fixes an exploit that allowed a player that already had a lockout from another expedition being added to loot after the event is complete
This commit is contained in:
parent
06d84b83de
commit
f97cc7cdec
@ -38,6 +38,7 @@ Child of the Mob class.
|
||||
|
||||
#include "corpse.h"
|
||||
#include "entity.h"
|
||||
#include "expedition.h"
|
||||
#include "groups.h"
|
||||
#include "mob.h"
|
||||
#include "raids.h"
|
||||
@ -1275,6 +1276,20 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
// expeditions may prevent looting based on client's lockouts
|
||||
auto expedition = Expedition::FindCachedExpeditionByInstanceID(zone->GetInstanceID());
|
||||
if (expedition && !expedition->CanClientLootCorpse(client, GetNPCTypeID(), GetID()))
|
||||
{
|
||||
client->MessageString(Chat::Red, LOOT_NOT_ALLOWED, inst->GetItem()->Name);
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
ResetLooter();
|
||||
delete inst;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// do we want this to have a fail option too?
|
||||
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
|
||||
|
||||
@ -363,13 +363,17 @@ Expedition* Expedition::FindCachedExpeditionByID(uint32_t expedition_id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Expedition* Expedition::FindExpeditionByInstanceID(uint32_t instance_id)
|
||||
Expedition* Expedition::FindCachedExpeditionByInstanceID(uint32_t instance_id)
|
||||
{
|
||||
if (instance_id)
|
||||
if (instance_id && zone)
|
||||
{
|
||||
// ask database since it may have expired
|
||||
auto expedition_id = ExpeditionDatabase::GetExpeditionIDFromInstanceID(instance_id);
|
||||
return Expedition::FindCachedExpeditionByID(expedition_id);
|
||||
for (const auto& cached_expedition : zone->expedition_cache)
|
||||
{
|
||||
if (cached_expedition.second->GetInstanceID() == instance_id)
|
||||
{
|
||||
return cached_expedition.second.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -1891,3 +1895,82 @@ void Expedition::SetDzZoneInLocation(float x, float y, float z, float heading, b
|
||||
SendWorldDzLocationUpdate(ServerOP_ExpeditionDzZoneIn, location);
|
||||
}
|
||||
}
|
||||
|
||||
bool Expedition::CanClientLootCorpse(Client* client, uint32_t npc_type_id, uint32_t spawn_id)
|
||||
{
|
||||
if (client && m_dynamiczone.IsCurrentZoneDzInstance())
|
||||
{
|
||||
// entity id takes priority, falls back to checking by npc type if not set
|
||||
std::string event_name = GetLootEventBySpawnID(spawn_id);
|
||||
if (event_name.empty())
|
||||
{
|
||||
event_name = GetLootEventByNPCTypeID(npc_type_id);
|
||||
}
|
||||
|
||||
if (!event_name.empty())
|
||||
{
|
||||
auto client_lockout = client->GetExpeditionLockout(GetName(), event_name);
|
||||
if (!client_lockout || client_lockout->GetExpeditionUUID() != GetUUID())
|
||||
{
|
||||
// client lockout not received in this expedition, prevent looting
|
||||
LogExpeditions(
|
||||
"Character [{}] denied looting npc [{}] spawn [{}] for lockout event [{}]",
|
||||
client->CharacterID(), npc_type_id, spawn_id, event_name
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Expedition::SetLootEventByNPCTypeID(uint32_t npc_type_id, const std::string& event_name)
|
||||
{
|
||||
if (npc_type_id && m_dynamiczone.IsCurrentZoneDzInstance())
|
||||
{
|
||||
LogExpeditions("Setting loot event [{}] for npc type id [{}]", event_name, npc_type_id);
|
||||
m_npc_loot_events[npc_type_id] = event_name;
|
||||
}
|
||||
}
|
||||
|
||||
void Expedition::SetLootEventBySpawnID(uint32_t spawn_id, const std::string& event_name)
|
||||
{
|
||||
if (spawn_id && m_dynamiczone.IsCurrentZoneDzInstance())
|
||||
{
|
||||
LogExpeditions("Setting loot event [{}] for entity id [{}]", event_name, spawn_id);
|
||||
m_spawn_loot_events[spawn_id] = event_name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Expedition::GetLootEventByNPCTypeID(uint32_t npc_type_id)
|
||||
{
|
||||
std::string event_name;
|
||||
|
||||
if (npc_type_id && m_dynamiczone.IsCurrentZoneDzInstance())
|
||||
{
|
||||
auto it = m_npc_loot_events.find(npc_type_id);
|
||||
if (it != m_npc_loot_events.end())
|
||||
{
|
||||
event_name = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return event_name;
|
||||
}
|
||||
|
||||
std::string Expedition::GetLootEventBySpawnID(uint32_t spawn_id)
|
||||
{
|
||||
std::string event_name;
|
||||
|
||||
if (spawn_id && m_dynamiczone.IsCurrentZoneDzInstance())
|
||||
{
|
||||
auto it = m_spawn_loot_events.find(spawn_id);
|
||||
if (it != m_spawn_loot_events.end())
|
||||
{
|
||||
event_name = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return event_name;
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ public:
|
||||
static Expedition* FindCachedExpeditionByCharacterID(uint32_t character_id);
|
||||
static Expedition* FindCachedExpeditionByCharacterName(const std::string& char_name);
|
||||
static Expedition* FindCachedExpeditionByID(uint32_t expedition_id);
|
||||
static Expedition* FindExpeditionByInstanceID(uint32_t instance_id);
|
||||
static Expedition* FindCachedExpeditionByInstanceID(uint32_t instance_id);
|
||||
static void RemoveCharacterLockouts(std::string character_name, std::string expedition_name = {}, std::string event_name = {});
|
||||
static void HandleWorldMessage(ServerPacket* pack);
|
||||
|
||||
@ -110,6 +110,12 @@ public:
|
||||
void RemoveLockout(const std::string& event_name);
|
||||
void SetReplayLockoutOnMemberJoin(bool add_on_join, bool update_db = false);
|
||||
|
||||
bool CanClientLootCorpse(Client* client, uint32_t npc_type_id, uint32_t spawn_id);
|
||||
std::string GetLootEventByNPCTypeID(uint32_t npc_id);
|
||||
std::string GetLootEventBySpawnID(uint32_t spawn_id);
|
||||
void SetLootEventByNPCTypeID(uint32_t npc_type_id, const std::string& event_name);
|
||||
void SetLootEventBySpawnID(uint32_t spawn_id, const std::string& event_name);
|
||||
|
||||
void SendClientExpeditionInfo(Client* client);
|
||||
void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name);
|
||||
|
||||
@ -184,6 +190,8 @@ private:
|
||||
ExpeditionMember m_leader;
|
||||
std::vector<ExpeditionMember> m_members;
|
||||
std::unordered_map<std::string, ExpeditionLockoutTimer> m_lockouts;
|
||||
std::unordered_map<uint32_t, std::string> m_npc_loot_events; // only valid inside dz zone
|
||||
std::unordered_map<uint32_t, std::string> m_spawn_loot_events; // only valid inside dz zone
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -429,24 +429,6 @@ uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_i
|
||||
return expedition_id;
|
||||
}
|
||||
|
||||
uint32_t ExpeditionDatabase::GetExpeditionIDFromInstanceID(uint32_t instance_id)
|
||||
{
|
||||
LogExpeditionsDetail("Getting expedition id for instance [{}]", instance_id);
|
||||
|
||||
uint32_t expedition_id = 0;
|
||||
auto query = fmt::format(
|
||||
"SELECT id FROM expedition_details WHERE instance_id = {};", instance_id
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() > 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
expedition_id = std::strtoul(row[0], nullptr, 10);
|
||||
}
|
||||
return expedition_id;
|
||||
}
|
||||
|
||||
ExpeditionMember ExpeditionDatabase::GetExpeditionLeader(uint32_t expedition_id)
|
||||
{
|
||||
LogExpeditionsDetail("Getting expedition leader for expedition [{}]", expedition_id);
|
||||
|
||||
@ -59,7 +59,6 @@ namespace ExpeditionDatabase
|
||||
void DeletePendingLockouts(uint32_t character_id);
|
||||
void DeleteAllMembersPendingLockouts(const std::vector<ExpeditionMember>& members);
|
||||
uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id);
|
||||
uint32_t GetExpeditionIDFromInstanceID(uint32_t instance_id);
|
||||
ExpeditionMember GetExpeditionLeader(uint32_t expedition_id);
|
||||
void InsertCharacterLockouts(
|
||||
uint32_t character_id, const std::vector<ExpeditionLockoutTimer>& lockouts,
|
||||
|
||||
@ -66,6 +66,16 @@ luabind::object Lua_Expedition::GetLockouts(lua_State* L) {
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetLootEventByNPCTypeID(uint32_t npc_type_id) {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetLootEventByNPCTypeID(npc_type_id);
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetLootEventBySpawnID(uint32_t spawn_id) {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetLootEventBySpawnID(spawn_id);
|
||||
}
|
||||
|
||||
uint32_t Lua_Expedition::GetMemberCount() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetMemberCount();
|
||||
@ -140,6 +150,16 @@ void Lua_Expedition::SetLocked(bool lock_expedition) {
|
||||
self->SetLocked(lock_expedition, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLootEventByNPCTypeID(uint32_t npc_type_id, std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLootEventByNPCTypeID(npc_type_id, event_name);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLootEventBySpawnID(uint32_t spawn_id, std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLootEventBySpawnID(spawn_id, event_name);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetReplayLockoutOnMemberJoin(bool enable) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetReplayLockoutOnMemberJoin(enable, true);
|
||||
@ -171,6 +191,8 @@ luabind::scope lua_register_expedition() {
|
||||
.def("GetInstanceID", (int(Lua_Expedition::*)(void))&Lua_Expedition::GetInstanceID)
|
||||
.def("GetLeaderName", (std::string(Lua_Expedition::*)(void))&Lua_Expedition::GetLeaderName)
|
||||
.def("GetLockouts", &Lua_Expedition::GetLockouts)
|
||||
.def("GetLootEventByNPCTypeID", (std::string(Lua_Expedition::*)(uint32_t))&Lua_Expedition::GetLootEventByNPCTypeID)
|
||||
.def("GetLootEventBySpawnID", (std::string(Lua_Expedition::*)(uint32_t))&Lua_Expedition::GetLootEventBySpawnID)
|
||||
.def("GetMemberCount", (uint32_t(Lua_Expedition::*)(void))&Lua_Expedition::GetMemberCount)
|
||||
.def("GetMembers", &Lua_Expedition::GetMembers)
|
||||
.def("GetName", (std::string(Lua_Expedition::*)(void))&Lua_Expedition::GetName)
|
||||
@ -184,6 +206,8 @@ luabind::scope lua_register_expedition() {
|
||||
.def("SetCompass", (void(Lua_Expedition::*)(uint32_t, float, float, float))&Lua_Expedition::SetCompass)
|
||||
.def("SetCompass", (void(Lua_Expedition::*)(std::string, float, float, float))&Lua_Expedition::SetCompass)
|
||||
.def("SetLocked", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetLocked)
|
||||
.def("SetLootEventByNPCTypeID", (void(Lua_Expedition::*)(uint32_t, std::string))&Lua_Expedition::SetLootEventByNPCTypeID)
|
||||
.def("SetLootEventBySpawnID", (void(Lua_Expedition::*)(uint32_t, std::string))&Lua_Expedition::SetLootEventBySpawnID)
|
||||
.def("SetReplayLockoutOnMemberJoin", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetReplayLockoutOnMemberJoin)
|
||||
.def("SetSafeReturn", (void(Lua_Expedition::*)(uint32_t, float, float, float, float))&Lua_Expedition::SetSafeReturn)
|
||||
.def("SetSafeReturn", (void(Lua_Expedition::*)(std::string, float, float, float, float))&Lua_Expedition::SetSafeReturn)
|
||||
|
||||
@ -58,6 +58,8 @@ public:
|
||||
int GetInstanceID();
|
||||
std::string GetLeaderName();
|
||||
luabind::object GetLockouts(lua_State* L);
|
||||
std::string GetLootEventByNPCTypeID(uint32_t npc_type_id);
|
||||
std::string GetLootEventBySpawnID(uint32_t spawn_id);
|
||||
uint32_t GetMemberCount();
|
||||
luabind::object GetMembers(lua_State* L);
|
||||
std::string GetName();
|
||||
@ -71,6 +73,8 @@ public:
|
||||
void SetCompass(uint32_t zone_id, float x, float y, float z);
|
||||
void SetCompass(std::string zone_name, float x, float y, float z);
|
||||
void SetLocked(bool lock_expedition);
|
||||
void SetLootEventByNPCTypeID(uint32_t npc_type_id, std::string event_name);
|
||||
void SetLootEventBySpawnID(uint32_t spawn_id, std::string event_name);
|
||||
void SetReplayLockoutOnMemberJoin(bool enable);
|
||||
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading);
|
||||
void SetSafeReturn(std::string zone_name, float x, float y, float z, float heading);
|
||||
|
||||
@ -4336,14 +4336,14 @@ Expedition* QuestManager::GetExpeditionByCharID(uint32 char_id)
|
||||
|
||||
Expedition* QuestManager::GetExpeditionByInstanceID(uint32 instance_id)
|
||||
{
|
||||
return Expedition::FindExpeditionByInstanceID(instance_id);
|
||||
return Expedition::FindCachedExpeditionByInstanceID(instance_id);
|
||||
}
|
||||
|
||||
Expedition* QuestManager::GetExpeditionForCurrentInstance()
|
||||
{
|
||||
if (zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
return Expedition::FindExpeditionByInstanceID(zone->GetInstanceID());
|
||||
return Expedition::FindCachedExpeditionByInstanceID(zone->GetInstanceID());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1492,7 +1492,7 @@ bool Zone::Process() {
|
||||
if(Instance_Timer->Check())
|
||||
{
|
||||
// if this is a dynamic zone instance notify system associated with it
|
||||
Expedition* expedition = Expedition::FindExpeditionByInstanceID(GetInstanceID());
|
||||
Expedition* expedition = Expedition::FindCachedExpeditionByInstanceID(GetInstanceID());
|
||||
if (expedition)
|
||||
{
|
||||
expedition->RemoveAllMembers(false); // entity list will teleport clients out immediately
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user