mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-10-14 03:19:56 +00:00
Merge branch 'main' into fix/cmake-libs-2
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
#include "Database.h"
|
||||
#include "Entity.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "Player.h"
|
||||
#include "Game.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Character.h"
|
||||
@@ -59,13 +58,13 @@ void LogAndSaveFailedAntiCheatCheck(const LWOOBJID& id, const SystemAddress& sys
|
||||
player->GetCharacter()->GetName().c_str(), player->GetObjectID(),
|
||||
sysAddr.ToString(),
|
||||
entity->GetCharacter()->GetName().c_str(), entity->GetObjectID());
|
||||
toReport = player->GetParentUser();
|
||||
if (player->GetCharacter()) toReport = player->GetCharacter()->GetParentUser();
|
||||
// In the case that the target entity id did not exist, just log the player info.
|
||||
} else if (player) {
|
||||
LOG("Player (%s) (%llu) at system address (%s) with sending player (%llu) does not match their own.",
|
||||
player->GetCharacter()->GetName().c_str(), player->GetObjectID(),
|
||||
sysAddr.ToString(), id);
|
||||
toReport = player->GetParentUser();
|
||||
if (player->GetCharacter()) toReport = player->GetCharacter()->GetParentUser();
|
||||
// In the rare case that the player does not exist, just log the system address and who the target id was.
|
||||
} else {
|
||||
LOG("Player at system address (%s) with sending player (%llu) does not match their own.",
|
||||
|
@@ -13,12 +13,12 @@ GUID::GUID(const std::string& guid) {
|
||||
&this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]);
|
||||
}
|
||||
|
||||
void GUID::Serialize(RakNet::BitStream* outBitStream) {
|
||||
outBitStream->Write(GetData1());
|
||||
outBitStream->Write(GetData2());
|
||||
outBitStream->Write(GetData3());
|
||||
void GUID::Serialize(RakNet::BitStream& outBitStream) {
|
||||
outBitStream.Write(GetData1());
|
||||
outBitStream.Write(GetData2());
|
||||
outBitStream.Write(GetData3());
|
||||
for (const auto& guidSubPart : GetData4()) {
|
||||
outBitStream->Write(guidSubPart);
|
||||
outBitStream.Write(guidSubPart);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@ class GUID {
|
||||
public:
|
||||
explicit GUID();
|
||||
explicit GUID(const std::string& guid);
|
||||
void Serialize(RakNet::BitStream* outBitStream);
|
||||
void Serialize(RakNet::BitStream& outBitStream);
|
||||
|
||||
uint32_t GetData1() const {
|
||||
return data1;
|
||||
|
@@ -28,11 +28,11 @@ void Loot::CacheMatrix(uint32_t matrixIndex) {
|
||||
return;
|
||||
}
|
||||
CachedMatrices.insert(matrixIndex);
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable<CDRarityTableTable>();
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::GetTable<CDRarityTableTable>();
|
||||
|
||||
const auto& matrix = lootMatrixTable->GetMatrix(matrixIndex);
|
||||
|
||||
@@ -47,11 +47,11 @@ void Loot::CacheMatrix(uint32_t matrixIndex) {
|
||||
}
|
||||
|
||||
std::unordered_map<LOT, int32_t> Loot::RollLootMatrix(Entity* player, uint32_t matrixIndex) {
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable<CDRarityTableTable>();
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::GetTable<CDRarityTableTable>();
|
||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||
|
||||
std::unordered_map<LOT, int32_t> drops;
|
||||
@@ -134,11 +134,11 @@ std::unordered_map<LOT, int32_t> Loot::RollLootMatrix(Entity* player, uint32_t m
|
||||
}
|
||||
|
||||
std::unordered_map<LOT, int32_t> Loot::RollLootMatrix(uint32_t matrixIndex) {
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable<CDRarityTableTable>();
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
CDLootMatrixTable* lootMatrixTable = CDClientManager::GetTable<CDLootMatrixTable>();
|
||||
CDLootTableTable* lootTableTable = CDClientManager::GetTable<CDLootTableTable>();
|
||||
CDRarityTableTable* rarityTableTable = CDClientManager::GetTable<CDRarityTableTable>();
|
||||
std::unordered_map<LOT, int32_t> drops;
|
||||
|
||||
const auto& matrix = lootMatrixTable->GetMatrix(matrixIndex);
|
||||
@@ -216,7 +216,7 @@ void Loot::GiveLoot(Entity* player, std::unordered_map<LOT, int32_t>& result, eL
|
||||
}
|
||||
|
||||
void Loot::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) {
|
||||
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
||||
CDActivityRewardsTable* activityRewardsTable = CDClientManager::GetTable<CDActivityRewardsTable>();
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); });
|
||||
|
||||
const CDActivityRewards* selectedReward = nullptr;
|
||||
@@ -232,7 +232,7 @@ void Loot::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID,
|
||||
uint32_t minCoins = 0;
|
||||
uint32_t maxCoins = 0;
|
||||
|
||||
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
|
||||
CDCurrencyTableTable* currencyTableTable = CDClientManager::GetTable<CDCurrencyTableTable>();
|
||||
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); });
|
||||
|
||||
if (currencyTable.size() > 0) {
|
||||
@@ -286,7 +286,7 @@ void Loot::DropLoot(Entity* player, Entity* killedObject, std::unordered_map<LOT
|
||||
}
|
||||
|
||||
void Loot::DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) {
|
||||
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
||||
CDActivityRewardsTable* activityRewardsTable = CDClientManager::GetTable<CDActivityRewardsTable>();
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); });
|
||||
|
||||
const CDActivityRewards* selectedReward = nullptr;
|
||||
@@ -303,7 +303,7 @@ void Loot::DropActivityLoot(Entity* player, Entity* source, uint32_t activityID,
|
||||
uint32_t minCoins = 0;
|
||||
uint32_t maxCoins = 0;
|
||||
|
||||
CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
|
||||
CDCurrencyTableTable* currencyTableTable = CDClientManager::GetTable<CDCurrencyTableTable>();
|
||||
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); });
|
||||
|
||||
if (currencyTable.size() > 0) {
|
||||
|
@@ -95,39 +95,39 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ
|
||||
}
|
||||
|
||||
//Because we need it:
|
||||
std::string ReadWStringAsString(RakNet::BitStream* bitStream, uint32_t size) {
|
||||
std::string ReadWStringAsString(RakNet::BitStream& bitStream, uint32_t size) {
|
||||
std::string toReturn = "";
|
||||
uint8_t buffer;
|
||||
bool isFinishedReading = false;
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
bitStream->Read(buffer);
|
||||
bitStream.Read(buffer);
|
||||
if (!isFinishedReading) toReturn.push_back(buffer);
|
||||
if (buffer == '\0') isFinishedReading = true; //so we don't continue to read garbage as part of the string.
|
||||
bitStream->Read(buffer); //Read the null term
|
||||
bitStream.Read(buffer); //Read the null term
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void WriteStringAsWString(RakNet::BitStream* bitStream, std::string str, uint32_t size) {
|
||||
void WriteStringAsWString(RakNet::BitStream& bitStream, std::string str, uint32_t size) {
|
||||
uint32_t sizeToFill = size - str.size();
|
||||
|
||||
for (uint32_t i = 0; i < str.size(); ++i) {
|
||||
bitStream->Write(str[i]);
|
||||
bitStream->Write(uint8_t(0));
|
||||
bitStream.Write(str[i]);
|
||||
bitStream.Write(uint8_t(0));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sizeToFill; ++i) {
|
||||
bitStream->Write(uint16_t(0));
|
||||
bitStream.Write(uint16_t(0));
|
||||
}
|
||||
}
|
||||
|
||||
void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity) {
|
||||
void Mail::HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) {
|
||||
int mailStuffID = 0;
|
||||
packet->Read(mailStuffID);
|
||||
packet.Read(mailStuffID);
|
||||
|
||||
auto returnVal = 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:
|
||||
@@ -154,7 +154,7 @@ void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAd
|
||||
});
|
||||
}
|
||||
|
||||
void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity) {
|
||||
void Mail::HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) {
|
||||
//std::string subject = GeneralUtils::WStringToString(ReadFromPacket(packet, 50));
|
||||
//std::string body = GeneralUtils::WStringToString(ReadFromPacket(packet, 400));
|
||||
//std::string recipient = GeneralUtils::WStringToString(ReadFromPacket(packet, 32));
|
||||
@@ -186,9 +186,9 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
|
||||
LWOOBJID attachmentID;
|
||||
uint16_t attachmentCount;
|
||||
|
||||
packet->Read(unknown64);
|
||||
packet->Read(attachmentID);
|
||||
packet->Read(attachmentCount); //We don't care about the rest of the packet.
|
||||
packet.Read(unknown64);
|
||||
packet.Read(attachmentID);
|
||||
packet.Read(attachmentCount); //We don't care about the rest of the packet.
|
||||
uint32_t itemID = static_cast<uint32_t>(attachmentID);
|
||||
LOT itemLOT = 0;
|
||||
//Inventory::InventoryType itemType;
|
||||
@@ -261,7 +261,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
|
||||
character->SaveXMLToDatabase();
|
||||
}
|
||||
|
||||
void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) {
|
||||
void Mail::HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) {
|
||||
auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20);
|
||||
|
||||
RakNet::BitStream bitStream;
|
||||
@@ -275,9 +275,9 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys
|
||||
for (const auto& mail : playerMail) {
|
||||
bitStream.Write(mail.id); //MailID
|
||||
|
||||
WriteStringAsWString(&bitStream, mail.subject.c_str(), 50); //subject
|
||||
WriteStringAsWString(&bitStream, mail.body.c_str(), 400); //body
|
||||
WriteStringAsWString(&bitStream, mail.senderUsername.c_str(), 32); //sender
|
||||
WriteStringAsWString(bitStream, mail.subject.c_str(), 50); //subject
|
||||
WriteStringAsWString(bitStream, mail.body.c_str(), 400); //body
|
||||
WriteStringAsWString(bitStream, mail.senderUsername.c_str(), 32); //sender
|
||||
|
||||
bitStream.Write(uint32_t(0));
|
||||
bitStream.Write(uint64_t(0));
|
||||
@@ -303,16 +303,16 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys
|
||||
bitStream.Write(uint32_t(0));
|
||||
}
|
||||
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
}
|
||||
|
||||
void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) {
|
||||
void Mail::HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) {
|
||||
int unknown;
|
||||
uint64_t mailID;
|
||||
LWOOBJID playerID;
|
||||
packet->Read(unknown);
|
||||
packet->Read(mailID);
|
||||
packet->Read(playerID);
|
||||
packet.Read(unknown);
|
||||
packet.Read(mailID);
|
||||
packet.Read(playerID);
|
||||
|
||||
if (mailID > 0 && playerID == player->GetObjectID()) {
|
||||
auto playerMail = Database::Get()->GetMail(mailID);
|
||||
@@ -336,22 +336,22 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres
|
||||
}
|
||||
}
|
||||
|
||||
void Mail::HandleMailDelete(RakNet::BitStream* packet, const SystemAddress& sysAddr) {
|
||||
void Mail::HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr) {
|
||||
int unknown;
|
||||
uint64_t mailID;
|
||||
LWOOBJID playerID;
|
||||
packet->Read(unknown);
|
||||
packet->Read(mailID);
|
||||
packet->Read(playerID);
|
||||
packet.Read(unknown);
|
||||
packet.Read(mailID);
|
||||
packet.Read(playerID);
|
||||
|
||||
if (mailID > 0) Mail::SendDeleteConfirm(sysAddr, mailID, playerID);
|
||||
}
|
||||
|
||||
void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAddr) {
|
||||
void Mail::HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr) {
|
||||
int unknown;
|
||||
uint64_t mailID;
|
||||
packet->Read(unknown);
|
||||
packet->Read(mailID);
|
||||
packet.Read(unknown);
|
||||
packet.Read(mailID);
|
||||
|
||||
if (mailID > 0) Mail::SendReadConfirm(sysAddr, mailID);
|
||||
}
|
||||
@@ -367,7 +367,7 @@ void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse respo
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
|
||||
bitStream.Write(int(MailMessageID::SendResponse));
|
||||
bitStream.Write(int(response));
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
}
|
||||
|
||||
void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) {
|
||||
@@ -386,7 +386,7 @@ void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) {
|
||||
bitStream.Write(s4);
|
||||
bitStream.Write(mailCount);
|
||||
bitStream.Write(int(0)); //Unknown
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
}
|
||||
|
||||
void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
|
||||
@@ -395,7 +395,7 @@ void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t ma
|
||||
bitStream.Write(int(MailMessageID::AttachmentCollectConfirm));
|
||||
bitStream.Write(int(0)); //unknown
|
||||
bitStream.Write(mailID);
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
}
|
||||
|
||||
void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) {
|
||||
@@ -404,7 +404,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO
|
||||
bitStream.Write(int(MailMessageID::MailDeleteConfirm));
|
||||
bitStream.Write(int(0)); //unknown
|
||||
bitStream.Write(mailID);
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
|
||||
Database::Get()->DeleteMail(mailID);
|
||||
}
|
||||
@@ -415,7 +415,7 @@ void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
|
||||
bitStream.Write(int(MailMessageID::MailReadConfirm));
|
||||
bitStream.Write(int(0)); //unknown
|
||||
bitStream.Write(mailID);
|
||||
Game::server->Send(&bitStream, sysAddr, false);
|
||||
Game::server->Send(bitStream, sysAddr, false);
|
||||
|
||||
Database::Get()->MarkMailRead(mailID);
|
||||
}
|
||||
|
@@ -79,12 +79,12 @@ namespace Mail {
|
||||
const SystemAddress& sysAddr
|
||||
);
|
||||
|
||||
void HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity);
|
||||
void HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity);
|
||||
void HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player);
|
||||
void HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player);
|
||||
void HandleMailDelete(RakNet::BitStream* packet, const SystemAddress& sysAddr);
|
||||
void HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAddr);
|
||||
void HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity);
|
||||
void HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity);
|
||||
void HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player);
|
||||
void HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player);
|
||||
void HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr);
|
||||
void HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr);
|
||||
void HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID);
|
||||
|
||||
void SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response);
|
||||
|
@@ -40,10 +40,8 @@ Precondition::Precondition(const uint32_t condition) {
|
||||
std::string token;
|
||||
|
||||
while (std::getline(stream, token, ',')) {
|
||||
uint32_t value;
|
||||
if (GeneralUtils::TryParse(token, value)) {
|
||||
this->values.push_back(value);
|
||||
}
|
||||
const auto validToken = GeneralUtils::TryParse<uint32_t>(token);
|
||||
if (validToken) this->values.push_back(validToken.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -22,18 +22,42 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
std::vector<VanityNPC> VanityUtilities::m_NPCs = {};
|
||||
std::vector<VanityParty> VanityUtilities::m_Parties = {};
|
||||
std::vector<std::string> VanityUtilities::m_PartyPhrases = {};
|
||||
|
||||
namespace {
|
||||
std::vector<VanityObject> objects;
|
||||
std::set<std::string> loadedFiles;
|
||||
}
|
||||
|
||||
void SetupNPCTalk(Entity* npc);
|
||||
void NPCTalk(Entity* npc);
|
||||
void ParseXml(const std::string& file);
|
||||
LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location);
|
||||
Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& location);
|
||||
VanityObject* GetObject(const std::string& name);
|
||||
|
||||
void VanityUtilities::SpawnVanity() {
|
||||
if (Game::config->GetValue("disable_vanity") == "1") {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t zoneID = Game::server->GetZoneID();
|
||||
|
||||
for (const auto& npc : m_NPCs) {
|
||||
if (zoneID == 1200) {
|
||||
{
|
||||
EntityInfo info;
|
||||
info.lot = 8139;
|
||||
info.pos = { 259.5f, 246.4f, -705.2f };
|
||||
info.rot = { 0.0f, 0.0f, 1.0f, 0.0f };
|
||||
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
||||
info.settings = {
|
||||
new LDFData<bool>(u"hasCustomText", true),
|
||||
new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string()))
|
||||
};
|
||||
|
||||
auto* entity = Game::entityManager->CreateEntity(info);
|
||||
Game::entityManager->ConstructEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game::config->GetValue("disable_vanity") == "1") return;
|
||||
|
||||
for (const auto& npc : objects) {
|
||||
if (npc.m_ID == LWOOBJID_EMPTY) continue;
|
||||
if (npc.m_LOT == 176){
|
||||
Game::zoneManager->RemoveSpawner(npc.m_ID);
|
||||
@@ -44,174 +68,73 @@ void VanityUtilities::SpawnVanity() {
|
||||
}
|
||||
}
|
||||
|
||||
m_NPCs.clear();
|
||||
m_Parties.clear();
|
||||
m_PartyPhrases.clear();
|
||||
objects.clear();
|
||||
loadedFiles.clear();
|
||||
|
||||
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string());
|
||||
ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity/root.xml").string());
|
||||
|
||||
// Loop through all parties
|
||||
for (const auto& party : m_Parties) {
|
||||
const auto chance = party.m_Chance;
|
||||
const auto zone = party.m_Zone;
|
||||
// Loop through all objects
|
||||
for (auto& object : objects) {
|
||||
if (object.m_Locations.find(Game::server->GetZoneID()) == object.m_Locations.end()) continue;
|
||||
|
||||
if (zone != Game::server->GetZoneID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (chance < rate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy m_NPCs into a new vector
|
||||
std::vector<VanityNPC> npcList = m_NPCs;
|
||||
std::vector<uint32_t> taken = {};
|
||||
|
||||
LOG("Spawning party with %i locations", party.m_Locations.size());
|
||||
|
||||
// Loop through all locations
|
||||
for (const auto& location : party.m_Locations) {
|
||||
rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (0.75f < rate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a random NPC
|
||||
auto npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1);
|
||||
|
||||
while (std::find(taken.begin(), taken.end(), npcIndex) != taken.end()) {
|
||||
npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1);
|
||||
}
|
||||
|
||||
auto& npc = npcList[npcIndex];
|
||||
// Skip spawners
|
||||
if (npc.m_LOT == 176) continue;
|
||||
|
||||
taken.push_back(npcIndex);
|
||||
|
||||
LOG("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
|
||||
if (npc.m_LOT == 176){
|
||||
npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf);
|
||||
} else {
|
||||
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
|
||||
if (!npc.m_Phrases.empty()) {
|
||||
npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases);
|
||||
SetupNPCTalk(npcEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all NPCs
|
||||
for (auto& npc : m_NPCs) {
|
||||
if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end())
|
||||
continue;
|
||||
|
||||
const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID());
|
||||
const std::vector<VanityObjectLocation>& locations = object.m_Locations.at(Game::server->GetZoneID());
|
||||
|
||||
// Pick a random location
|
||||
const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>(
|
||||
static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))];
|
||||
|
||||
float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (location.m_Chance < rate) {
|
||||
continue;
|
||||
}
|
||||
if (location.m_Chance < rate) continue;
|
||||
|
||||
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")
|
||||
};
|
||||
}
|
||||
if (npc.m_LOT == 176){
|
||||
npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf);
|
||||
if (object.m_LOT == 176){
|
||||
object.m_ID = SpawnSpawner(object, location);
|
||||
} else {
|
||||
// Spawn the NPC
|
||||
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
|
||||
if (!npcEntity) continue;
|
||||
npc.m_ID = npcEntity->GetObjectID();
|
||||
if (!npc.m_Phrases.empty()){
|
||||
npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases);
|
||||
|
||||
auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>();
|
||||
|
||||
if (scriptComponent && !npc.m_Script.empty()) {
|
||||
scriptComponent->SetScript(npc.m_Script);
|
||||
scriptComponent->SetSerialized(false);
|
||||
|
||||
for (const auto& npc : npc.m_Flags) {
|
||||
npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second);
|
||||
}
|
||||
}
|
||||
SetupNPCTalk(npcEntity);
|
||||
auto* objectEntity = SpawnObject(object, location);
|
||||
if (!objectEntity) continue;
|
||||
object.m_ID = objectEntity->GetObjectID();
|
||||
if (!object.m_Phrases.empty()){
|
||||
objectEntity->SetVar<std::vector<std::string>>(u"chats", object.m_Phrases);
|
||||
SetupNPCTalk(objectEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneID == 1200) {
|
||||
{
|
||||
EntityInfo info;
|
||||
info.lot = 8139;
|
||||
info.pos = { 259.5f, 246.4f, -705.2f };
|
||||
info.rot = { 0.0f, 0.0f, 1.0f, 0.0f };
|
||||
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
||||
|
||||
info.settings = { new LDFData<bool>(u"hasCustomText", true),
|
||||
new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) };
|
||||
|
||||
auto* entity = Game::entityManager->CreateEntity(info);
|
||||
|
||||
Game::entityManager->ConstructEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LWOOBJID VanityUtilities::SpawnSpawner(LOT lot, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LDFBaseData*>& ldf){
|
||||
LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location) {
|
||||
SceneObject obj;
|
||||
obj.lot = lot;
|
||||
obj.lot = object.m_LOT;
|
||||
// guratantee we have no collisions
|
||||
do {
|
||||
obj.id = ObjectIDManager::GenerateObjectID();
|
||||
} while(Game::zoneManager->GetSpawner(obj.id));
|
||||
obj.position = position;
|
||||
obj.rotation = rotation;
|
||||
obj.settings = ldf;
|
||||
obj.position = location.m_Position;
|
||||
obj.rotation = location.m_Rotation;
|
||||
obj.settings = object.m_Config;
|
||||
Level::MakeSpawner(obj);
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LOT>& inventory, const std::vector<LDFBaseData*>& ldf) {
|
||||
Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& location) {
|
||||
EntityInfo info;
|
||||
info.lot = lot;
|
||||
info.pos = position;
|
||||
info.rot = rotation;
|
||||
info.lot = object.m_LOT;
|
||||
info.pos = location.m_Position;
|
||||
info.rot = location.m_Rotation;
|
||||
info.scale = location.m_Scale;
|
||||
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
||||
info.settings = ldf;
|
||||
info.settings = object.m_Config;
|
||||
|
||||
auto* entity = Game::entityManager->CreateEntity(info);
|
||||
entity->SetVar(u"npcName", name);
|
||||
if (!object.m_Name.empty()) entity->SetVar(u"npcName", object.m_Name);
|
||||
if (entity->GetVar<bool>(u"noGhosting")) entity->SetIsGhostingCandidate(false);
|
||||
|
||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||
|
||||
if (inventoryComponent && !inventory.empty()) {
|
||||
inventoryComponent->SetNPCItems(inventory);
|
||||
if (inventoryComponent && !object.m_Equipment.empty()) {
|
||||
inventoryComponent->SetNPCItems(object.m_Equipment);
|
||||
}
|
||||
|
||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||
|
||||
if (destroyableComponent != nullptr) {
|
||||
if (destroyableComponent) {
|
||||
destroyableComponent->SetIsGMImmune(true);
|
||||
destroyableComponent->SetMaxHealth(0);
|
||||
destroyableComponent->SetHealth(0);
|
||||
@@ -222,7 +145,12 @@ Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoin
|
||||
return entity;
|
||||
}
|
||||
|
||||
void VanityUtilities::ParseXML(const std::string& file) {
|
||||
void ParseXml(const std::string& file) {
|
||||
if (loadedFiles.contains(file)){
|
||||
LOG("Trying to load vanity file %s twice!!!", file.c_str());
|
||||
return;
|
||||
}
|
||||
loadedFiles.insert(file);
|
||||
// Read the entire file
|
||||
std::ifstream xmlFile(file);
|
||||
std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>());
|
||||
@@ -231,210 +159,107 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
tinyxml2::XMLDocument doc;
|
||||
doc.Parse(xml.c_str(), xml.size());
|
||||
|
||||
// Read the NPCs
|
||||
auto* npcs = doc.FirstChildElement("npcs");
|
||||
|
||||
if (npcs == nullptr) {
|
||||
LOG("Failed to parse NPCs");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* party = npcs->FirstChildElement("party"); party != nullptr; party = party->NextSiblingElement("party")) {
|
||||
// Get 'zone' as uint32_t and 'chance' as float
|
||||
uint32_t zone = 0;
|
||||
float chance = 0.0f;
|
||||
|
||||
if (party->Attribute("zone") != nullptr) {
|
||||
zone = std::stoul(party->Attribute("zone"));
|
||||
}
|
||||
|
||||
if (party->Attribute("chance") != nullptr) {
|
||||
chance = std::stof(party->Attribute("chance"));
|
||||
}
|
||||
|
||||
VanityParty partyInfo;
|
||||
partyInfo.m_Zone = zone;
|
||||
partyInfo.m_Chance = chance;
|
||||
|
||||
auto* locations = party->FirstChildElement("locations");
|
||||
|
||||
if (locations == nullptr) {
|
||||
LOG("Failed to parse party locations");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto* location = locations->FirstChildElement("location"); location != nullptr;
|
||||
location = location->NextSiblingElement("location")) {
|
||||
// Get the location data
|
||||
auto* x = location->Attribute("x");
|
||||
auto* y = location->Attribute("y");
|
||||
auto* z = location->Attribute("z");
|
||||
auto* rw = location->Attribute("rw");
|
||||
auto* rx = location->Attribute("rx");
|
||||
auto* ry = location->Attribute("ry");
|
||||
auto* rz = location->Attribute("rz");
|
||||
|
||||
if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr
|
||||
|| rz == nullptr) {
|
||||
LOG("Failed to parse party location data");
|
||||
// Read the objects
|
||||
auto* files = doc.FirstChildElement("files");
|
||||
if (files) {
|
||||
for (auto* file = files->FirstChildElement("file"); file != nullptr; file = file->NextSiblingElement("file")) {
|
||||
std::string enabled = file->Attribute("enabled");
|
||||
std::string filename = file->Attribute("name");
|
||||
if (enabled != "1") {
|
||||
continue;
|
||||
}
|
||||
|
||||
VanityNPCLocation locationData;
|
||||
locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) };
|
||||
locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) };
|
||||
locationData.m_Chance = 1.0f;
|
||||
|
||||
partyInfo.m_Locations.push_back(locationData);
|
||||
}
|
||||
|
||||
m_Parties.push_back(partyInfo);
|
||||
}
|
||||
|
||||
auto* partyPhrases = npcs->FirstChildElement("partyphrases");
|
||||
|
||||
if (partyPhrases == nullptr) {
|
||||
LOG("No party phrases found");
|
||||
} else {
|
||||
for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse party phrase");
|
||||
continue;
|
||||
}
|
||||
|
||||
m_PartyPhrases.push_back(text);
|
||||
ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) {
|
||||
// Get the NPC name
|
||||
auto* name = npc->Attribute("name");
|
||||
// Read the objects
|
||||
auto* objectsElement = doc.FirstChildElement("objects");
|
||||
const uint32_t currentZoneID = Game::server->GetZoneID();
|
||||
if (objectsElement) {
|
||||
for (auto* object = objectsElement->FirstChildElement("object"); object != nullptr; object = object->NextSiblingElement("object")) {
|
||||
// for use later when adding to the vector of VanityObjects
|
||||
bool useLocationsAsRandomSpawnPoint = false;
|
||||
// Get the NPC name
|
||||
auto* name = object->Attribute("name");
|
||||
|
||||
if (!name) name = "";
|
||||
if (!name) name = "";
|
||||
|
||||
// Get the NPC lot
|
||||
auto* lot = npc->Attribute("lot");
|
||||
// Get the NPC lot
|
||||
auto lot = GeneralUtils::TryParse<LOT>(object->Attribute("lot")).value_or(LOT_NULL);
|
||||
|
||||
if (lot == nullptr) {
|
||||
LOG("Failed to parse NPC lot");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the equipment
|
||||
auto* equipment = npc->FirstChildElement("equipment");
|
||||
std::vector<LOT> inventory;
|
||||
|
||||
if (equipment) {
|
||||
auto* text = equipment->GetText();
|
||||
|
||||
if (text != nullptr) {
|
||||
std::string equipmentString(text);
|
||||
|
||||
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");
|
||||
|
||||
std::vector<std::string> phraseList = {};
|
||||
|
||||
if (phrases) {
|
||||
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse NPC phrase");
|
||||
continue;
|
||||
}
|
||||
phraseList.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the script
|
||||
auto* scriptElement = npc->FirstChildElement("script");
|
||||
|
||||
std::string scriptName = "";
|
||||
|
||||
if (scriptElement != nullptr) {
|
||||
auto* scriptNameAttribute = scriptElement->Attribute("name");
|
||||
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");
|
||||
|
||||
if (flags != nullptr) {
|
||||
for (auto* flag = flags->FirstChildElement("flag"); flag != nullptr;
|
||||
flag = flag->NextSiblingElement("flag")) {
|
||||
// Get the flag name
|
||||
auto* name = flag->Attribute("name");
|
||||
|
||||
if (name == nullptr) {
|
||||
LOG("Failed to parse NPC flag name");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the flag value
|
||||
auto* value = flag->Attribute("value");
|
||||
|
||||
if (value == nullptr) {
|
||||
LOG("Failed to parse NPC flag value");
|
||||
continue;
|
||||
}
|
||||
|
||||
npcData.m_Flags[name] = std::stoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the zones
|
||||
for (auto* zone = npc->FirstChildElement("zone"); zone != nullptr; zone = zone->NextSiblingElement("zone")) {
|
||||
// Get the zone ID
|
||||
auto* zoneID = zone->Attribute("id");
|
||||
|
||||
if (zoneID == nullptr) {
|
||||
LOG("Failed to parse NPC zone ID");
|
||||
if (lot == LOT_NULL) {
|
||||
LOG("Failed to parse object lot");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the equipment
|
||||
auto* equipment = object->FirstChildElement("equipment");
|
||||
std::vector<LOT> inventory;
|
||||
|
||||
if (equipment) {
|
||||
auto* text = equipment->GetText();
|
||||
|
||||
if (text != nullptr) {
|
||||
std::string equipmentString(text);
|
||||
|
||||
std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ',');
|
||||
|
||||
for (auto& item : splitEquipment) {
|
||||
// remove spaces for tryParse to work
|
||||
item.erase(remove_if(item.begin(), item.end(), isspace), item.end());
|
||||
auto itemInt = GeneralUtils::TryParse<uint32_t>(item);
|
||||
if (itemInt) inventory.push_back(itemInt.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the phrases
|
||||
auto* phrases = object->FirstChildElement("phrases");
|
||||
std::vector<std::string> phraseList = {};
|
||||
if (phrases) {
|
||||
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse NPC phrase");
|
||||
continue;
|
||||
}
|
||||
phraseList.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
auto* configElement = object->FirstChildElement("config");
|
||||
std::vector<std::u16string> keys = {};
|
||||
std::vector<LDFBaseData*> config = {};
|
||||
if(configElement) {
|
||||
for (auto* key = configElement->FirstChildElement("key"); key != nullptr;
|
||||
key = key->NextSiblingElement("key")) {
|
||||
// Get the config data
|
||||
auto* data = key->GetText();
|
||||
if (!data) continue;
|
||||
|
||||
LDFBaseData* configData = LDFBaseData::DataFromString(data);
|
||||
if (configData->GetKey() == u"useLocationsAsRandomSpawnPoint" && configData->GetValueType() == eLDFType::LDF_TYPE_BOOLEAN){
|
||||
useLocationsAsRandomSpawnPoint = static_cast<bool>(configData);
|
||||
continue;
|
||||
}
|
||||
keys.push_back(configData->GetKey());
|
||||
config.push_back(configData);
|
||||
}
|
||||
}
|
||||
if (!keys.empty()) config.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys));
|
||||
|
||||
VanityObject objectData {
|
||||
.m_Name = name,
|
||||
.m_LOT = lot,
|
||||
.m_Equipment = inventory,
|
||||
.m_Phrases = phraseList,
|
||||
.m_Config = config
|
||||
};
|
||||
|
||||
// Get the locations
|
||||
auto* locations = zone->FirstChildElement("locations");
|
||||
auto* locations = object->FirstChildElement("locations");
|
||||
|
||||
if (locations == nullptr) {
|
||||
LOG("Failed to parse NPC locations");
|
||||
@@ -443,53 +268,69 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
|
||||
for (auto* location = locations->FirstChildElement("location"); location != nullptr;
|
||||
location = location->NextSiblingElement("location")) {
|
||||
|
||||
// Get the location data
|
||||
auto* x = location->Attribute("x");
|
||||
auto* y = location->Attribute("y");
|
||||
auto* z = location->Attribute("z");
|
||||
auto* rw = location->Attribute("rw");
|
||||
auto* rx = location->Attribute("rx");
|
||||
auto* ry = location->Attribute("ry");
|
||||
auto* rz = location->Attribute("rz");
|
||||
auto zoneID = GeneralUtils::TryParse<uint32_t>(location->Attribute("zone"));
|
||||
auto x = GeneralUtils::TryParse<float>(location->Attribute("x"));
|
||||
auto y = GeneralUtils::TryParse<float>(location->Attribute("y"));
|
||||
auto z = GeneralUtils::TryParse<float>(location->Attribute("z"));
|
||||
auto rw = GeneralUtils::TryParse<float>(location->Attribute("rw"));
|
||||
auto rx = GeneralUtils::TryParse<float>(location->Attribute("rx"));
|
||||
auto ry = GeneralUtils::TryParse<float>(location->Attribute("ry"));
|
||||
auto rz = GeneralUtils::TryParse<float>(location->Attribute("rz"));
|
||||
|
||||
if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr
|
||||
|| rz == nullptr) {
|
||||
if (!zoneID || !x || !y || !z || !rw || !rx || !ry || !rz) {
|
||||
LOG("Failed to parse NPC location data");
|
||||
continue;
|
||||
}
|
||||
|
||||
VanityNPCLocation locationData;
|
||||
locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) };
|
||||
locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) };
|
||||
locationData.m_Chance = 1.0f;
|
||||
|
||||
if (location->Attribute("chance") != nullptr) {
|
||||
locationData.m_Chance = std::stof(location->Attribute("chance"));
|
||||
if (zoneID.value() != currentZoneID) {
|
||||
LOG_DEBUG("Skipping location because it is in %i and not the current zone (%i)", zoneID.value(), currentZoneID);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& it = npcData.m_Locations.find(std::stoi(zoneID));
|
||||
VanityObjectLocation locationData {
|
||||
.m_Position = { x.value(), y.value(), z.value() },
|
||||
.m_Rotation = { rw.value(), rx.value(), ry.value(), rz.value() },
|
||||
};
|
||||
|
||||
if (it != npcData.m_Locations.end()) {
|
||||
if (location->Attribute("chance")) {
|
||||
locationData.m_Chance = GeneralUtils::TryParse<float>(location->Attribute("chance")).value_or(1.0f);
|
||||
}
|
||||
|
||||
if (location->Attribute("scale")) {
|
||||
locationData.m_Scale = GeneralUtils::TryParse<float>(location->Attribute("scale")).value_or(1.0f);
|
||||
}
|
||||
|
||||
const auto& it = objectData.m_Locations.find(zoneID.value());
|
||||
|
||||
if (it != objectData.m_Locations.end()) {
|
||||
it->second.push_back(locationData);
|
||||
} else {
|
||||
std::vector<VanityNPCLocation> locations;
|
||||
std::vector<VanityObjectLocation> locations;
|
||||
locations.push_back(locationData);
|
||||
npcData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations));
|
||||
objectData.m_Locations.insert(std::make_pair(zoneID.value(), locations));
|
||||
}
|
||||
|
||||
if (!useLocationsAsRandomSpawnPoint) {
|
||||
objects.push_back(objectData);
|
||||
objectData.m_Locations.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_NPCs.push_back(npcData);
|
||||
if (useLocationsAsRandomSpawnPoint && !objectData.m_Locations.empty()) {
|
||||
objects.push_back(objectData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VanityNPC* VanityUtilities::GetNPC(const std::string& name) {
|
||||
for (size_t i = 0; i < m_NPCs.size(); i++) {
|
||||
if (m_NPCs[i].m_Name == name) {
|
||||
return &m_NPCs[i];
|
||||
VanityObject* VanityUtilities::GetObject(const std::string& name) {
|
||||
for (size_t i = 0; i < objects.size(); i++) {
|
||||
if (objects[i].m_Name == name) {
|
||||
return &objects[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -498,10 +339,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
||||
|
||||
// Read the file into a string
|
||||
std::ifstream t(file);
|
||||
|
||||
// If the file does not exist, return an empty string.
|
||||
std::stringstream output;
|
||||
// If the file does not exist, return a useful error.
|
||||
if (!t.good()) {
|
||||
return "";
|
||||
output << "File ";
|
||||
output << file.substr(file.rfind("/") + 1);
|
||||
output << " not found!\nContact your DarkflameServer admin\nor find the server source at https://github.com/DarkflameUniverse/DarkflameServer";
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
@@ -511,7 +355,6 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
||||
// Loop through all lines in the file.
|
||||
// Replace all instances of the markdown syntax with the corresponding HTML.
|
||||
// Only care about headers
|
||||
std::stringstream output;
|
||||
std::string line;
|
||||
std::stringstream ss;
|
||||
ss << fileContents;
|
||||
@@ -555,13 +398,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
||||
return output.str();
|
||||
}
|
||||
|
||||
void VanityUtilities::SetupNPCTalk(Entity* npc) {
|
||||
void SetupNPCTalk(Entity* npc) {
|
||||
npc->AddCallbackTimer(15.0f, [npc]() { NPCTalk(npc); });
|
||||
|
||||
npc->SetProximityRadius(20.0f, "talk");
|
||||
}
|
||||
|
||||
void VanityUtilities::NPCTalk(Entity* npc) {
|
||||
void NPCTalk(Entity* npc) {
|
||||
auto* proximityMonitorComponent = npc->GetComponent<ProximityMonitorComponent>();
|
||||
|
||||
if (!proximityMonitorComponent->GetProximityObjects("talk").empty()) {
|
||||
|
@@ -3,73 +3,32 @@
|
||||
#include "dCommonVars.h"
|
||||
#include "Entity.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
struct VanityNPCLocation
|
||||
{
|
||||
struct VanityObjectLocation {
|
||||
float m_Chance = 1.0f;
|
||||
NiPoint3 m_Position;
|
||||
NiQuaternion m_Rotation;
|
||||
float m_Scale = 1.0f;
|
||||
};
|
||||
|
||||
struct VanityNPC
|
||||
{
|
||||
struct VanityObject {
|
||||
LWOOBJID m_ID = LWOOBJID_EMPTY;
|
||||
std::string m_Name;
|
||||
LOT m_LOT;
|
||||
LOT m_LOT = LOT_NULL;
|
||||
std::vector<LOT> m_Equipment;
|
||||
std::vector<std::string> m_Phrases;
|
||||
std::string m_Script;
|
||||
std::map<std::string, bool> m_Flags;
|
||||
std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations;
|
||||
std::vector<LDFBaseData*> ldf;
|
||||
std::map<uint32_t, std::vector<VanityObjectLocation>> m_Locations;
|
||||
std::vector<LDFBaseData*> m_Config;
|
||||
};
|
||||
|
||||
struct VanityParty
|
||||
{
|
||||
uint32_t m_Zone;
|
||||
float m_Chance = 1.0f;
|
||||
std::vector<VanityNPCLocation> m_Locations;
|
||||
};
|
||||
|
||||
class VanityUtilities
|
||||
{
|
||||
public:
|
||||
static void SpawnVanity();
|
||||
namespace VanityUtilities {
|
||||
void SpawnVanity();
|
||||
|
||||
static Entity* SpawnNPC(
|
||||
LOT lot,
|
||||
const std::string& name,
|
||||
const NiPoint3& position,
|
||||
const NiQuaternion& rotation,
|
||||
const std::vector<LOT>& inventory,
|
||||
const std::vector<LDFBaseData*>& ldf
|
||||
);
|
||||
VanityObject* GetObject(const std::string& name);
|
||||
|
||||
static LWOOBJID SpawnSpawner(
|
||||
LOT lot,
|
||||
const NiPoint3& position,
|
||||
const NiQuaternion& rotation,
|
||||
const std::vector<LDFBaseData*>& ldf
|
||||
);
|
||||
|
||||
static std::string ParseMarkdown(
|
||||
std::string ParseMarkdown(
|
||||
const std::string& file
|
||||
);
|
||||
|
||||
static void ParseXML(
|
||||
const std::string& file
|
||||
);
|
||||
|
||||
static VanityNPC* GetNPC(const std::string& name);
|
||||
|
||||
private:
|
||||
static void SetupNPCTalk(Entity* npc);
|
||||
|
||||
static void NPCTalk(Entity* npc);
|
||||
|
||||
static std::vector<VanityNPC> m_NPCs;
|
||||
|
||||
static std::vector<VanityParty> m_Parties;
|
||||
|
||||
static std::vector<std::string> m_PartyPhrases;
|
||||
};
|
||||
|
Reference in New Issue
Block a user