mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-24 22:43:34 +00:00
455f9470a5
* Move EntityManager to Game namespace * move initialization to later Need to wait for dZoneManager to be initialized. * Fix bugs - Cannot delete from a RandomAccessIterator while in a range based for loop. Touchup zone manager initialize replace magic numbers with better named constants replace magic zonecontrol id with a more readable hex alternative condense stack variables move initializers closer to their use initialize entity manager with zone control change initialize timings If zone is not zero we expect to initialize the entity manager during zone manager initialization Add constexpr for zone control LOT * Add proper error handling * revert vanity changes * Update WorldServer.cpp * Update dZoneManager.cpp
286 lines
8.2 KiB
C++
286 lines
8.2 KiB
C++
#include "TradingManager.h"
|
|
#include "EntityManager.h"
|
|
#include "GameMessages.h"
|
|
#include "InventoryComponent.h"
|
|
#include "../dWorldServer/ObjectIDManager.h"
|
|
#include "Game.h"
|
|
#include "dLogger.h"
|
|
#include "Item.h"
|
|
#include "Character.h"
|
|
#include "CharacterComponent.h"
|
|
#include "MissionComponent.h"
|
|
#include "eMissionTaskType.h"
|
|
|
|
TradingManager* TradingManager::m_Address = nullptr;
|
|
|
|
Trade::Trade(LWOOBJID tradeId, LWOOBJID participantA, LWOOBJID participantB) {
|
|
m_TradeId = tradeId;
|
|
m_ParticipantA = participantA;
|
|
m_ParticipantB = participantB;
|
|
}
|
|
|
|
Trade::~Trade() {
|
|
|
|
}
|
|
|
|
LWOOBJID Trade::GetTradeId() const {
|
|
return m_TradeId;
|
|
}
|
|
|
|
bool Trade::IsParticipant(LWOOBJID playerId) const {
|
|
return m_ParticipantA == playerId || m_ParticipantB == playerId;
|
|
}
|
|
|
|
LWOOBJID Trade::GetParticipantA() const {
|
|
return m_ParticipantA;
|
|
}
|
|
|
|
LWOOBJID Trade::GetParticipantB() const {
|
|
return m_ParticipantB;
|
|
}
|
|
|
|
Entity* Trade::GetParticipantAEntity() const {
|
|
return Game::entityManager->GetEntity(m_ParticipantA);
|
|
}
|
|
|
|
Entity* Trade::GetParticipantBEntity() const {
|
|
return Game::entityManager->GetEntity(m_ParticipantB);
|
|
}
|
|
|
|
void Trade::SetCoins(LWOOBJID participant, uint64_t coins) {
|
|
if (participant == m_ParticipantA) {
|
|
m_CoinsA = coins;
|
|
} else if (participant == m_ParticipantB) {
|
|
m_CoinsB = coins;
|
|
}
|
|
}
|
|
|
|
void Trade::SetItems(LWOOBJID participant, std::vector<TradeItem> items) {
|
|
if (participant == m_ParticipantA) {
|
|
m_ItemsA = items;
|
|
} else if (participant == m_ParticipantB) {
|
|
m_ItemsB = items;
|
|
}
|
|
}
|
|
|
|
void Trade::SetAccepted(LWOOBJID participant, bool value) {
|
|
if (participant == m_ParticipantA) {
|
|
m_AcceptedA = !value;
|
|
|
|
Game::logger->Log("Trade", "Accepted from A (%d), B: (%d)", value, m_AcceptedB);
|
|
|
|
auto* entityB = GetParticipantBEntity();
|
|
|
|
if (entityB != nullptr) {
|
|
GameMessages::SendServerTradeAccept(m_ParticipantB, value, entityB->GetSystemAddress());
|
|
}
|
|
} else if (participant == m_ParticipantB) {
|
|
m_AcceptedB = !value;
|
|
|
|
Game::logger->Log("Trade", "Accepted from B (%d), A: (%d)", value, m_AcceptedA);
|
|
|
|
auto* entityA = GetParticipantAEntity();
|
|
|
|
if (entityA != nullptr) {
|
|
GameMessages::SendServerTradeAccept(m_ParticipantA, value, entityA->GetSystemAddress());
|
|
}
|
|
}
|
|
|
|
if (m_AcceptedA && m_AcceptedB) {
|
|
auto* entityB = GetParticipantBEntity();
|
|
|
|
if (entityB != nullptr) {
|
|
GameMessages::SendServerTradeAccept(m_ParticipantB, false, entityB->GetSystemAddress());
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
auto* entityA = GetParticipantAEntity();
|
|
|
|
if (entityA != nullptr) {
|
|
GameMessages::SendServerTradeAccept(m_ParticipantA, false, entityA->GetSystemAddress());
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
Complete();
|
|
TradingManager::Instance()->CancelTrade(m_TradeId);
|
|
}
|
|
}
|
|
|
|
void Trade::Complete() {
|
|
auto* entityA = GetParticipantAEntity();
|
|
auto* entityB = GetParticipantBEntity();
|
|
|
|
if (entityA == nullptr || entityB == nullptr) return;
|
|
|
|
auto* inventoryA = entityA->GetComponent<InventoryComponent>();
|
|
auto* inventoryB = entityB->GetComponent<InventoryComponent>();
|
|
auto* missionsA = entityA->GetComponent<MissionComponent>();
|
|
auto* missionsB = entityB->GetComponent<MissionComponent>();
|
|
auto* characterA = entityA->GetCharacter();
|
|
auto* characterB = entityB->GetCharacter();
|
|
|
|
if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return;
|
|
|
|
// First verify both players have the coins and items requested for the trade.
|
|
if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) {
|
|
Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade.");
|
|
return;
|
|
}
|
|
|
|
for (const auto& tradeItem : m_ItemsA) {
|
|
auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId);
|
|
if (itemToRemove) {
|
|
if (itemToRemove->GetCount() < tradeItem.itemCount) {
|
|
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str());
|
|
return;
|
|
}
|
|
} else {
|
|
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str());
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (const auto& tradeItem : m_ItemsB) {
|
|
auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId);
|
|
if (itemToRemove) {
|
|
if (itemToRemove->GetCount() < tradeItem.itemCount) {
|
|
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str());
|
|
return;
|
|
}
|
|
} else {
|
|
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str());
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Now actually do the trade.
|
|
characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::TRADE);
|
|
characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::TRADE);
|
|
|
|
for (const auto& tradeItem : m_ItemsA) {
|
|
auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId);
|
|
if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount);
|
|
missionsA->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount);
|
|
inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::TRADE);
|
|
}
|
|
|
|
for (const auto& tradeItem : m_ItemsB) {
|
|
auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId);
|
|
if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount);
|
|
missionsB->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount);
|
|
inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::TRADE);
|
|
}
|
|
|
|
characterA->SaveXMLToDatabase();
|
|
characterB->SaveXMLToDatabase();
|
|
return;
|
|
}
|
|
|
|
void Trade::Cancel() {
|
|
auto* entityA = GetParticipantAEntity();
|
|
auto* entityB = GetParticipantBEntity();
|
|
|
|
if (entityA == nullptr || entityB == nullptr) return;
|
|
|
|
GameMessages::SendServerTradeCancel(entityA->GetObjectID(), entityA->GetSystemAddress());
|
|
GameMessages::SendServerTradeCancel(entityB->GetObjectID(), entityB->GetSystemAddress());
|
|
}
|
|
|
|
void Trade::SendUpdateToOther(LWOOBJID participant) {
|
|
Entity* other = nullptr;
|
|
Entity* self = nullptr;
|
|
uint64_t coins;
|
|
std::vector<TradeItem> itemIds;
|
|
|
|
Game::logger->Log("Trade", "Attempting to send trade update");
|
|
|
|
if (participant == m_ParticipantA) {
|
|
other = GetParticipantBEntity();
|
|
self = GetParticipantAEntity();
|
|
coins = m_CoinsA;
|
|
itemIds = m_ItemsA;
|
|
} else if (participant == m_ParticipantB) {
|
|
other = GetParticipantAEntity();
|
|
self = GetParticipantBEntity();
|
|
coins = m_CoinsB;
|
|
itemIds = m_ItemsB;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (other == nullptr || self == nullptr) return;
|
|
|
|
std::vector<TradeItem> items{};
|
|
|
|
auto* inventoryComponent = self->GetComponent<InventoryComponent>();
|
|
|
|
if (inventoryComponent == nullptr) return;
|
|
|
|
for (const auto tradeItem : itemIds) {
|
|
auto* item = inventoryComponent->FindItemById(tradeItem.itemId);
|
|
|
|
if (item == nullptr) return;
|
|
|
|
if (tradeItem.itemCount > item->GetCount()) return;
|
|
|
|
items.push_back(tradeItem);
|
|
}
|
|
|
|
Game::logger->Log("Trade", "Sending trade update");
|
|
|
|
GameMessages::SendServerTradeUpdate(other->GetObjectID(), coins, items, other->GetSystemAddress());
|
|
}
|
|
|
|
TradingManager::TradingManager() {
|
|
}
|
|
|
|
TradingManager::~TradingManager() {
|
|
for (const auto& pair : trades) {
|
|
delete pair.second;
|
|
}
|
|
|
|
trades.clear();
|
|
}
|
|
|
|
Trade* TradingManager::GetTrade(LWOOBJID tradeId) const {
|
|
const auto& pair = trades.find(tradeId);
|
|
|
|
if (pair == trades.end()) return nullptr;
|
|
|
|
return pair->second;
|
|
}
|
|
|
|
Trade* TradingManager::GetPlayerTrade(LWOOBJID playerId) const {
|
|
for (const auto& pair : trades) {
|
|
if (pair.second->IsParticipant(playerId)) {
|
|
return pair.second;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void TradingManager::CancelTrade(LWOOBJID tradeId) {
|
|
auto* trade = GetTrade(tradeId);
|
|
|
|
if (trade == nullptr) return;
|
|
|
|
delete trade;
|
|
|
|
trades.erase(tradeId);
|
|
}
|
|
|
|
Trade* TradingManager::NewTrade(LWOOBJID participantA, LWOOBJID participantB) {
|
|
const LWOOBJID tradeId = ObjectIDManager::Instance()->GenerateObjectID();
|
|
|
|
auto* trade = new Trade(tradeId, participantA, participantB);
|
|
|
|
trades[tradeId] = trade;
|
|
|
|
Game::logger->Log("TradingManager", "Created new trade between (%llu) <-> (%llu)", participantA, participantB);
|
|
|
|
return trade;
|
|
}
|