Merge branch 'main' into cdclient-rework

This commit is contained in:
David Markowitz
2023-07-27 20:03:12 -07:00
1177 changed files with 21192 additions and 13777 deletions

View File

@@ -3,21 +3,27 @@
#include "BrickDatabase.h"
#include "Game.h"
#include "AssetManager.h"
#include "tinyxml2.h"
#include "Brick.h"
std::vector<Brick> BrickDatabase::emptyCache{};
BrickDatabase* BrickDatabase::m_Address = nullptr;
const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) {
static std::unordered_map<LxfmlPath, BrickList> m_Cache;
static const BrickList emptyCache;
BrickDatabase::BrickDatabase() = default;
BrickDatabase::~BrickDatabase() = default;
std::vector<Brick>& BrickDatabase::GetBricks(const std::string& lxfmlPath) {
const auto cached = m_Cache.find(lxfmlPath);
if (cached != m_Cache.end()) {
return cached->second;
}
std::ifstream file(lxfmlPath);
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer((lxfmlPath).c_str());
if (!buffer.m_Success) {
return emptyCache;
}
std::istream file(&buffer);
if (!file.good()) {
return emptyCache;
}
@@ -25,16 +31,19 @@ std::vector<Brick>& BrickDatabase::GetBricks(const std::string& lxfmlPath) {
std::stringstream data;
data << file.rdbuf();
if (data.str().empty()) {
buffer.close();
return emptyCache;
}
buffer.close();
auto* doc = new tinyxml2::XMLDocument();
if (doc->Parse(data.str().c_str(), data.str().size()) != 0) {
delete doc;
return emptyCache;
}
std::vector<Brick> parts;
BrickList parts;
auto* lxfml = doc->FirstChildElement("LXFML");
auto* bricks = lxfml->FirstChildElement("Bricks");

View File

@@ -1,29 +1,16 @@
#ifndef __BRICKDATABASE__H__
#define __BRICKDATABASE__H__
#pragma once
#include "Entity.h"
class BrickDatabase
{
public:
static BrickDatabase* Instance() {
if (m_Address == nullptr) {
m_Address = new BrickDatabase();
}
class Brick;
using BrickList = std::vector<Brick>;
using LxfmlPath = std::string;
return m_Address;
}
std::vector<Brick>& GetBricks(const std::string& lxfmlPath);
explicit BrickDatabase();
~BrickDatabase();
private:
std::unordered_map<std::string, std::vector<Brick>> m_Cache;
static std::vector<Brick> emptyCache;
static BrickDatabase* m_Address; //For singleton method
/* data */
namespace BrickDatabase {
const BrickList& GetBricks(const LxfmlPath& lxfmlPath);
};
#endif //!__BRICKDATABASE__H__

View File

@@ -1,6 +1,4 @@
set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp"
"dLocale.cpp"
"GameConfig.cpp"
"GUID.cpp"
"Loot.cpp"
"Mail.cpp"

View File

@@ -1,50 +0,0 @@
#include "GameConfig.h"
#include <sstream>
std::map<std::string, std::string> GameConfig::m_Config{};
std::string GameConfig::m_EmptyString{};
void GameConfig::Load(const std::string& filepath) {
m_EmptyString = "";
std::ifstream in(filepath);
if (!in.good()) return;
std::string line;
while (std::getline(in, line)) {
if (line.length() > 0) {
if (line[0] != '#') ProcessLine(line);
}
}
}
const std::string& GameConfig::GetValue(const std::string& key) {
const auto& it = m_Config.find(key);
if (it != m_Config.end()) {
return it->second;
}
return m_EmptyString;
}
void GameConfig::SetValue(const std::string& key, const std::string& value) {
m_Config.insert_or_assign(key, value);
}
void GameConfig::ProcessLine(const std::string& line) {
std::stringstream ss(line);
std::string segment;
std::vector<std::string> seglist;
while (std::getline(ss, segment, '=')) {
seglist.push_back(segment);
}
if (seglist.size() != 2) return;
//Make sure that on Linux, we remove special characters:
if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r')
seglist[1].erase(seglist[1].size() - 1);
m_Config.insert_or_assign(seglist[0], seglist[1]);
}

View File

@@ -1,38 +0,0 @@
#pragma once
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include "GeneralUtils.h"
class GameConfig {
public:
static void Load(const std::string& filepath);
static const std::string& GetValue(const std::string& key);
static void SetValue(const std::string& key, const std::string& value);
template <typename T>
static T GetValue(const std::string& key) {
T value;
if (GeneralUtils::TryParse(GetValue(key), value)) {
return value;
}
return T();
}
template <typename T>
static void SetValue(const std::string& key, const T& value) {
SetValue(key, std::to_string(value));
}
private:
static void ProcessLine(const std::string& line);
static std::map<std::string, std::string> m_Config;
static std::string m_EmptyString;
};

View File

@@ -7,19 +7,23 @@
#include "CDLootMatrixTable.h"
#include "CDLootTableTable.h"
#include "CDRarityTableTable.h"
#include "CDActivityRewardsTable.h"
#include "CDCurrencyTableTable.h"
#include "Character.h"
#include "Entity.h"
#include "GameMessages.h"
#include "GeneralUtils.h"
#include "InventoryComponent.h"
#include "MissionComponent.h"
#include "eMissionState.h"
#include "eReplicaComponentType.h"
LootGenerator::LootGenerator() {
CDLootTableTable* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable<CDItemComponentTable>("ItemComponent");
CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
CDRarityTableTable* rarityTableTable = CDClientManager::Instance()->GetTable<CDRarityTableTable>("RarityTable");
CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable<CDLootTableTable>();
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable<CDLootMatrixTable>();
CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable<CDRarityTableTable>();
// ==============================
// Cache Item Rarities
@@ -36,7 +40,7 @@ LootGenerator::LootGenerator() {
uniqueItems.erase(std::unique(uniqueItems.begin(), uniqueItems.end()), uniqueItems.end());
for (const uint32_t itemID : uniqueItems) {
uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, COMPONENT_TYPE_ITEM);
uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, eReplicaComponentType::ITEM);
const CDItemComponent& item = itemComponentTable->GetItemComponentByID(itemComponentID);
m_ItemRarities.insert({ itemID, item.rarity });
@@ -186,13 +190,13 @@ std::unordered_map<LOT, int32_t> LootGenerator::RollLootMatrix(Entity* player, u
// convert faction token proxy
if (drop.itemID == 13763) {
if (missionComponent->GetMissionState(545) == MissionState::MISSION_STATE_COMPLETE)
if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE)
drop.itemID = 8318; // "Assembly Token"
else if (missionComponent->GetMissionState(556) == MissionState::MISSION_STATE_COMPLETE)
else if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE)
drop.itemID = 8321; // "Venture League Token"
else if (missionComponent->GetMissionState(567) == MissionState::MISSION_STATE_COMPLETE)
else if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE)
drop.itemID = 8319; // "Sentinels Token"
else if (missionComponent->GetMissionState(578) == MissionState::MISSION_STATE_COMPLETE)
else if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE)
drop.itemID = 8320; // "Paradox Token"
}
@@ -290,7 +294,7 @@ void LootGenerator::GiveLoot(Entity* player, std::unordered_map<LOT, int32_t>& r
}
void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) {
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable<CDActivityRewardsTable>("ActivityRewards");
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); });
const CDActivityRewards* selectedReward = nullptr;
@@ -306,7 +310,7 @@ void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t ac
uint32_t minCoins = 0;
uint32_t maxCoins = 0;
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable<CDCurrencyTableTable>("CurrencyTable");
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); });
if (currencyTable.size() > 0) {
@@ -314,13 +318,13 @@ void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t ac
maxCoins = currencyTable[0].maxvalue;
}
GiveLoot(player, selectedReward->LootMatrixIndex, eLootSourceType::LOOT_SOURCE_ACTIVITY);
GiveLoot(player, selectedReward->LootMatrixIndex, eLootSourceType::ACTIVITY);
uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber<float>(0, 1) * (maxCoins - minCoins));
auto* character = player->GetCharacter();
character->SetCoins(character->GetCoins() + coins, eLootSourceType::LOOT_SOURCE_ACTIVITY);
character->SetCoins(character->GetCoins() + coins, eLootSourceType::ACTIVITY);
}
void LootGenerator::DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) {
@@ -360,7 +364,7 @@ void LootGenerator::DropLoot(Entity* player, Entity* killedObject, std::unordere
}
void LootGenerator::DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) {
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable<CDActivityRewardsTable>("ActivityRewards");
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); });
const CDActivityRewards* selectedReward = nullptr;
@@ -377,7 +381,7 @@ void LootGenerator::DropActivityLoot(Entity* player, Entity* source, uint32_t ac
uint32_t minCoins = 0;
uint32_t maxCoins = 0;
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable<CDCurrencyTableTable>("CurrencyTable");
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); });
if (currencyTable.size() > 0) {

View File

@@ -47,8 +47,8 @@ public:
std::unordered_map<LOT, int32_t> RollLootMatrix(Entity* player, uint32_t matrixIndex);
std::unordered_map<LOT, int32_t> RollLootMatrix(uint32_t matrixIndex);
void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE);
void GiveLoot(Entity* player, std::unordered_map<LOT, int32_t>& result, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE);
void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::NONE);
void GiveLoot(Entity* player, std::unordered_map<LOT, int32_t>& result, eLootSourceType lootSourceType = eLootSourceType::NONE);
void GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0);
void DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins);
void DropLoot(Entity* player, Entity* killedObject, std::unordered_map<LOT, int32_t>& result, uint32_t minCoins, uint32_t maxCoins);

View File

@@ -13,7 +13,6 @@
#include "Entity.h"
#include "Character.h"
#include "PacketUtils.h"
#include "dMessageIdentifiers.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "InventoryComponent.h"
@@ -22,6 +21,11 @@
#include "MissionComponent.h"
#include "ChatPackets.h"
#include "Character.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
#include "eMissionTaskType.h"
#include "eReplicaComponentType.h"
#include "eConnectionType.h"
void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment,
const uint16_t attachmentCount) {
@@ -74,12 +78,12 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ
auto* ins = Database::CreatePreppedStmt("INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, sender);
ins->setString(2, senderName);
ins->setString(2, senderName.c_str());
ins->setUInt(3, recipient);
ins->setString(4, recipientName.c_str());
ins->setUInt64(5, time(nullptr));
ins->setString(6, subject);
ins->setString(7, body);
ins->setString(6, subject.c_str());
ins->setString(7, body.c_str());
ins->setUInt(8, 0);
ins->setInt(9, attachment);
ins->setInt(10, 0);
@@ -126,7 +130,7 @@ void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAd
int mailStuffID = 0;
packet->Read(mailStuffID);
std::async(std::launch::async, [packet, &sysAddr, entity, mailStuffID]() {
auto returnVal = std::async(std::launch::async, [packet, &sysAddr, entity, mailStuffID]() {
Mail::MailMessageID stuffID = MailMessageID(mailStuffID);
switch (stuffID) {
case MailMessageID::AttachmentCollect:
@@ -163,7 +167,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
if (!character) return;
if (character->HasPermission(PermissionMap::RestrictedMailAccess)) {
if (character->HasPermission(ePermissionMap::RestrictedMailAccess)) {
// Send a message to the player
ChatPackets::SendSystemMessage(
sysAddr,
@@ -191,15 +195,15 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
uint32_t itemID = static_cast<uint32_t>(attachmentID);
LOT itemLOT = 0;
//Inventory::InventoryType itemType;
int mailCost = 25;
int mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee;
int stackSize = 0;
auto inv = static_cast<InventoryComponent*>(entity->GetComponent(COMPONENT_TYPE_INVENTORY));
auto inv = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY));
Item* item = nullptr;
if (itemID > 0 && attachmentCount > 0 && inv) {
item = inv->FindItemById(attachmentID);
if (item) {
mailCost += (item->GetInfo().baseValue * 0.1f);
mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee);
stackSize = item->GetCount();
itemLOT = item->GetLot();
} else {
@@ -255,7 +259,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::Success);
entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::LOOT_SOURCE_MAIL);
entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL);
Game::logger->Log("Mail", "Seeing if we need to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT);
@@ -266,7 +270,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
auto* missionCompoent = entity->GetComponent<MissionComponent>();
if (missionCompoent != nullptr) {
missionCompoent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount);
missionCompoent->Progress(eMissionTaskType::GATHER, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount);
}
}
@@ -279,7 +283,7 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys
sql::ResultSet* res = stmt->executeQuery();
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::MailData));
bitStream.Write(int(0));
@@ -352,10 +356,10 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres
attachmentCount = res->getInt(2);
}
auto inv = static_cast<InventoryComponent*>(player->GetComponent(COMPONENT_TYPE_INVENTORY));
auto inv = static_cast<InventoryComponent*>(player->GetComponent(eReplicaComponentType::INVENTORY));
if (!inv) return;
inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::LOOT_SOURCE_MAIL);
inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL);
Mail::SendAttachmentRemoveConfirm(sysAddr, mailID);
@@ -389,7 +393,7 @@ void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) {
std::async(std::launch::async, [&]() {
auto returnVal = std::async(std::launch::async, [&]() {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM mail WHERE receiver_id=? AND was_read=0");
stmt->setUInt(1, objectID);
sql::ResultSet* res = stmt->executeQuery();
@@ -402,7 +406,7 @@ void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t obje
void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::SendResponse));
bitStream.Write(int(response));
Game::server->Send(&bitStream, sysAddr, false);
@@ -410,7 +414,7 @@ void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse respo
void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
uint64_t messageType = 2;
uint64_t s1 = 0;
uint64_t s2 = 0;
@@ -429,7 +433,7 @@ void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) {
void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::AttachmentCollectConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);
@@ -438,7 +442,7 @@ void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t ma
void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::MailDeleteConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);
@@ -452,7 +456,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO
void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::MailReadConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);

View File

@@ -12,7 +12,7 @@
#include "LevelProgressionComponent.h"
#include "DestroyableComponent.h"
#include "GameMessages.h"
#include "eMissionState.h"
std::map<uint32_t, Precondition*> Preconditions::cache = {};
@@ -142,19 +142,19 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat
case PreconditionType::HasAchievement:
mission = missionComponent->GetMission(value);
return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE;
return mission == nullptr || mission->GetMissionState() >= eMissionState::COMPLETE;
case PreconditionType::MissionAvailable:
mission = missionComponent->GetMission(value);
return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_AVAILABLE;
return mission == nullptr || mission->GetMissionState() >= eMissionState::AVAILABLE;
case PreconditionType::OnMission:
mission = missionComponent->GetMission(value);
return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_ACTIVE;
return mission == nullptr || mission->GetMissionState() >= eMissionState::ACTIVE;
case PreconditionType::MissionComplete:
mission = missionComponent->GetMission(value);
return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE;
return mission == nullptr ? false : mission->GetMissionState() >= eMissionState::COMPLETE;
case PreconditionType::PetDeployed:
return false; // TODO
case PreconditionType::HasFlag:
@@ -277,11 +277,6 @@ bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const {
return true;
}
if (player->GetGMLevel() >= 9) // Developers can skip this for testing
{
return true;
}
const auto a = Preconditions::Check(player, condition, evaluateCosts);
if (!a) {

File diff suppressed because it is too large Load Diff

View File

@@ -13,8 +13,6 @@ class Entity;
namespace SlashCommandHandler {
void HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr);
bool CheckIfAccessibleZone(const unsigned int zoneID);
void SendAnnouncement(const std::string& title, const std::string& message);
};

View File

@@ -13,6 +13,8 @@
#include "tinyxml2.h"
#include "Game.h"
#include "dLogger.h"
#include "BinaryPathFinder.h"
#include "EntityInfo.h"
#include <fstream>
@@ -27,7 +29,7 @@ void VanityUtilities::SpawnVanity() {
const uint32_t zoneID = Game::server->GetZoneID();
ParseXML("./vanity/NPC.xml");
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string());
// Loop through all parties
for (const auto& party : m_Parties) {
@@ -63,17 +65,21 @@ void VanityUtilities::SpawnVanity() {
npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1);
}
const auto& npc = npcList[npcIndex];
auto& npc = npcList[npcIndex];
taken.push_back(npcIndex);
// Spawn the NPC
std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>(
u"syncLDF", { u"custom_script_client" }),
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") };
Game::logger->Log("VanityUtilities", "ldf size is %i", npc.ldf.size());
if (npc.ldf.empty()) {
npc.ldf = {
new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }),
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua")
};
}
// Spawn the NPC
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, data);
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases);
@@ -84,11 +90,11 @@ void VanityUtilities::SpawnVanity() {
}
// Loop through all NPCs
for (const auto& pair : m_NPCs) {
if (pair.m_Locations.find(Game::server->GetZoneID()) == pair.m_Locations.end())
for (auto& npc : m_NPCs) {
if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end())
continue;
const std::vector<VanityNPCLocation>& locations = pair.m_Locations.at(Game::server->GetZoneID());
const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID());
// Pick a random location
const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>(
@@ -99,27 +105,30 @@ void VanityUtilities::SpawnVanity() {
continue;
}
std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>(
u"syncLDF", { u"custom_script_client" }),
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") };
if (npc.ldf.empty()) {
npc.ldf = {
new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }),
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua")
};
}
// Spawn the NPC
auto* npc = SpawnNPC(pair.m_LOT, pair.m_Name, location.m_Position, location.m_Rotation, pair.m_Equipment, data);
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
npc->SetVar<std::vector<std::string>>(u"chats", pair.m_Phrases);
npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases);
auto* scriptComponent = npc->GetComponent<ScriptComponent>();
auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>();
if (scriptComponent != nullptr) {
scriptComponent->SetScript(pair.m_Script);
if (scriptComponent && !npc.m_Script.empty()) {
scriptComponent->SetScript(npc.m_Script);
scriptComponent->SetSerialized(false);
for (const auto& pair : pair.m_Flags) {
npc->SetVar<bool>(GeneralUtils::ASCIIToUTF16(pair.first), pair.second);
for (const auto& npc : npc.m_Flags) {
npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second);
}
}
SetupNPCTalk(npc);
SetupNPCTalk(npcEntity);
}
if (zoneID == 1200) {
@@ -128,14 +137,14 @@ void VanityUtilities::SpawnVanity() {
info.lot = 8139;
info.pos = { 259.5f, 246.4f, -705.2f };
info.rot = { 0.0f, 0.0f, 1.0f, 0.0f };
info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID();
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
info.settings = { new LDFData<bool>(u"hasCustomText", true),
new LDFData<std::string>(u"customText", ParseMarkdown("./vanity/TESTAMENT.md")) };
new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) };
auto* entity = EntityManager::Instance()->CreateEntity(info);
auto* entity = Game::entityManager->CreateEntity(info);
EntityManager::Instance()->ConstructEntity(entity);
Game::entityManager->ConstructEntity(entity);
}
}
}
@@ -146,15 +155,15 @@ Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoin
info.lot = lot;
info.pos = position;
info.rot = rotation;
info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID();
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
info.settings = ldf;
auto* entity = EntityManager::Instance()->CreateEntity(info);
auto* entity = Game::entityManager->CreateEntity(info);
entity->SetVar(u"npcName", name);
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
if (inventoryComponent != nullptr) {
if (inventoryComponent && !inventory.empty()) {
inventoryComponent->SetNPCItems(inventory);
}
@@ -166,7 +175,7 @@ Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoin
destroyableComponent->SetHealth(0);
}
EntityManager::Instance()->ConstructEntity(entity);
Game::entityManager->ConstructEntity(entity);
return entity;
}
@@ -264,10 +273,7 @@ void VanityUtilities::ParseXML(const std::string& file) {
// Get the NPC name
auto* name = npc->Attribute("name");
if (name == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC name");
continue;
}
if (!name) name = "";
// Get the NPC lot
auto* lot = npc->Attribute("lot");
@@ -279,71 +285,76 @@ void VanityUtilities::ParseXML(const std::string& file) {
// Get the equipment
auto* equipment = npc->FirstChildElement("equipment");
if (equipment == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC equipment");
continue;
}
auto* text = equipment->GetText();
std::vector<LOT> inventory;
if (text != nullptr) {
std::string equipmentString(text);
if (equipment) {
auto* text = equipment->GetText();
std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ',');
if (text != nullptr) {
std::string equipmentString(text);
for (auto& item : splitEquipment) {
inventory.push_back(std::stoi(item));
std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ',');
for (auto& item : splitEquipment) {
inventory.push_back(std::stoi(item));
}
}
}
// Get the phrases
auto* phrases = npc->FirstChildElement("phrases");
if (phrases == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC phrases");
continue;
}
std::vector<std::string> phraseList = {};
std::vector<std::string> phraseList;
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
phrase = phrase->NextSiblingElement("phrase")) {
// Get the phrase
auto* text = phrase->GetText();
if (text == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase");
continue;
if (phrases) {
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
phrase = phrase->NextSiblingElement("phrase")) {
// Get the phrase
auto* text = phrase->GetText();
if (text == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase");
continue;
}
phraseList.push_back(text);
}
phraseList.push_back(text);
}
// Get the script
auto* scriptElement = npc->FirstChildElement("script");
std::string scriptName;
std::string scriptName = "";
if (scriptElement != nullptr) {
auto* scriptNameAttribute = scriptElement->Attribute("name");
if (scriptNameAttribute == nullptr) {
Game::logger->Log("VanityUtilities", "Failed to parse NPC script name");
continue;
}
scriptName = scriptNameAttribute;
if (scriptNameAttribute) scriptName = scriptNameAttribute;
}
auto* ldfElement = npc->FirstChildElement("ldf");
std::vector<std::u16string> keys = {};
std::vector<LDFBaseData*> ldf = {};
if(ldfElement) {
for (auto* entry = ldfElement->FirstChildElement("entry"); entry != nullptr;
entry = entry->NextSiblingElement("entry")) {
// Get the ldf data
auto* data = entry->Attribute("data");
if (!data) continue;
LDFBaseData* ldfData = LDFBaseData::DataFromString(data);
keys.push_back(ldfData->GetKey());
ldf.push_back(ldfData);
}
}
if (!keys.empty()) ldf.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys));
VanityNPC npcData;
npcData.m_Name = name;
npcData.m_LOT = std::stoi(lot);
npcData.m_Equipment = inventory;
npcData.m_Phrases = phraseList;
npcData.m_Script = scriptName;
npcData.ldf = ldf;
// Get flags
auto* flags = npc->FirstChildElement("flags");
@@ -524,7 +535,7 @@ void VanityUtilities::NPCTalk(Entity* npc) {
npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS);
}
EntityManager::Instance()->SerializeEntity(npc);
Game::entityManager->SerializeEntity(npc);
const float nextTime = GeneralUtils::GenerateRandomNumber<float>(15, 60);

View File

@@ -20,6 +20,7 @@ struct VanityNPC
std::string m_Script;
std::map<std::string, bool> m_Flags;
std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations;
std::vector<LDFBaseData*> ldf;
};
struct VanityParty

View File

@@ -1,81 +0,0 @@
#include "dLocale.h"
#include <clocale>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include "tinyxml2.h"
#include "Game.h"
#include "dConfig.h"
dLocale::dLocale() {
if (Game::config->GetValue("locale_enabled") != "1") {
return;
}
std::ifstream file(m_LocalePath);
if (!file.good()) {
return;
}
std::stringstream data;
data << file.rdbuf();
if (data.str().empty()) {
return;
}
auto* doc = new tinyxml2::XMLDocument();
if (doc == nullptr) {
return;
}
if (doc->Parse(data.str().c_str(), data.str().size()) != 0) {
return;
}
std::hash<std::string> hash;
auto* localization = doc->FirstChildElement("localization");
auto* phrases = localization->FirstChildElement("phrases");
auto* phrase = phrases->FirstChildElement("phrase");
while (phrase != nullptr) {
// Add the phrase hash to the vector
m_Phrases.push_back(hash(phrase->Attribute("id")));
phrase = phrase->NextSiblingElement("phrase");
}
file.close();
delete doc;
}
dLocale::~dLocale() = default;
std::string dLocale::GetTemplate(const std::string& phraseID) {
return "%[" + phraseID + "]";
}
bool dLocale::HasPhrase(const std::string& phraseID) {
if (Game::config->GetValue("locale_enabled") != "1") {
return true;
}
// Compute the hash and see if it's in the vector
std::hash<std::string> hash;
std::size_t hashValue = hash(phraseID);
return std::find(m_Phrases.begin(), m_Phrases.end(), hashValue) != m_Phrases.end();
}
/*std::string dLocale::GetPhrase(const std::string& phraseID) {
if (m_Phrases.find(phraseID) == m_Phrases.end()) {
return "";
}
return m_Phrases[phraseID];
}*/

View File

@@ -1,19 +0,0 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include <cstdint>
class dLocale {
public:
dLocale();
~dLocale();
static std::string GetTemplate(const std::string& phraseID);
bool HasPhrase(const std::string& phraseID);
//std::string GetPhrase(const std::string& phraseID);
private:
std::string m_LocalePath = "./locale/locale.xml";
std::string m_Locale = "en_US"; // TODO: add to config
std::vector<std::size_t> m_Phrases;
};