mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-09 20:24:16 +00:00
Add FlagComponent and msg handlers
This commit is contained in:
@@ -10,6 +10,7 @@ set(DGAME_DCOMPONENTS_SOURCES
|
||||
"ControllablePhysicsComponent.cpp"
|
||||
"DestroyableComponent.cpp"
|
||||
"DonationVendorComponent.cpp"
|
||||
"FlagComponent.cpp"
|
||||
"GhostComponent.cpp"
|
||||
"InventoryComponent.cpp"
|
||||
"ItemComponent.cpp"
|
||||
|
199
dGame/dComponents/FlagComponent.cpp
Normal file
199
dGame/dComponents/FlagComponent.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "FlagComponent.h"
|
||||
|
||||
#include "CDPlayerFlagsTable.h"
|
||||
|
||||
#include "eMissionTaskType.h"
|
||||
#include "ePlayerFlag.h"
|
||||
|
||||
#include "MissionComponent.h"
|
||||
|
||||
FlagComponent::FlagComponent(Entity* parent) : Component(parent) {
|
||||
RegisterMsg(MessageType::Game::SET_FLAG, this, &FlagComponent::OnSetFlag);
|
||||
RegisterMsg(MessageType::Game::GET_FLAG, this, &FlagComponent::OnGetFlag);
|
||||
RegisterMsg(MessageType::Game::CLEAR_SESSION_FLAGS, this, &FlagComponent::OnClearSessionFlags);
|
||||
RegisterMsg(MessageType::Game::SET_RETROACTIVE_FLAGS, this, &FlagComponent::OnSetRetroactiveFlags);
|
||||
}
|
||||
|
||||
bool FlagComponent::OnSetFlag(GameMessages::GameMsg& msg) {
|
||||
auto& setFlag = static_cast<GameMessages::SetFlag&>(msg);
|
||||
LOG("Set %i", setFlag.iFlagId);
|
||||
SetPlayerFlag(setFlag.iFlagId, setFlag.bFlag);
|
||||
|
||||
// This is always set the first time a player loads into a world from character select
|
||||
// and is used to know when to refresh the players inventory items so they show up.
|
||||
if (setFlag.iFlagId == ePlayerFlag::IS_NEWS_SCREEN_VISIBLE && setFlag.bFlag) {
|
||||
m_Parent->SetVar<bool>(u"dlu_first_time_load", true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlagComponent::OnGetFlag(GameMessages::GameMsg& msg) {
|
||||
auto& getFlag = static_cast<GameMessages::GetFlag&>(msg);
|
||||
LOG("Get %i", getFlag.iFlagId);
|
||||
|
||||
getFlag.bFlag = GetPlayerFlag(getFlag.iFlagId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlagComponent::UpdateXml(tinyxml2::XMLDocument& doc) {
|
||||
if (!doc.FirstChildElement("obj")) return;
|
||||
auto& obj = *doc.FirstChildElement("obj");
|
||||
|
||||
if (!obj.FirstChildElement("flag")) {
|
||||
obj.InsertNewChildElement("flag");
|
||||
}
|
||||
|
||||
auto& flags = *obj.FirstChildElement("flag");
|
||||
|
||||
flags.DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes
|
||||
|
||||
// Save our flags
|
||||
for (const auto& [index, flagBucket] : m_PlayerFlags) {
|
||||
auto& f = *flags.InsertNewChildElement("f");
|
||||
f.SetAttribute("id", index);
|
||||
f.SetAttribute("v", flagBucket);
|
||||
}
|
||||
|
||||
// Save our session flags
|
||||
for (const auto& sessionFlag : m_SessionFlags) {
|
||||
auto& s = *flags.InsertNewChildElement("s");
|
||||
LOG("Saving session flag %i", sessionFlag);
|
||||
s.SetAttribute("si", sessionFlag);
|
||||
}
|
||||
}
|
||||
|
||||
void FlagComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) {
|
||||
if (!doc.FirstChildElement("obj")) return;
|
||||
auto& obj = *doc.FirstChildElement("obj");
|
||||
|
||||
if (!obj.FirstChildElement("flag")) return;
|
||||
auto& flags = *obj.FirstChildElement("flag");
|
||||
|
||||
const auto* currentChild = flags.FirstChildElement("f");
|
||||
while (currentChild) {
|
||||
const auto* temp = currentChild->Attribute("v");
|
||||
const auto* id = currentChild->Attribute("id");
|
||||
if (temp && id) {
|
||||
uint32_t index = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
index = std::stoul(id);
|
||||
value = std::stoull(temp);
|
||||
|
||||
m_PlayerFlags.insert(std::make_pair(index, value));
|
||||
}
|
||||
currentChild = currentChild->NextSiblingElement("f");
|
||||
}
|
||||
|
||||
// Now load our session flags
|
||||
currentChild = flags.FirstChildElement("s");
|
||||
while (currentChild) {
|
||||
const auto* temp = currentChild->Attribute("si");
|
||||
if (temp) {
|
||||
uint32_t sessionIndex = 0;
|
||||
sessionIndex = std::stoul(temp);
|
||||
m_SessionFlags.insert(sessionIndex);
|
||||
}
|
||||
currentChild = currentChild->NextSiblingElement("s");
|
||||
}
|
||||
}
|
||||
|
||||
void FlagComponent::SetPlayerFlag(const uint32_t flagId, const bool value) {
|
||||
// If the flag is already set, we don't have to recalculate it
|
||||
if (GetPlayerFlag(flagId) == value) return;
|
||||
|
||||
if (value) {
|
||||
// Update the mission component:
|
||||
auto* missionComponent = m_Parent->GetComponent<MissionComponent>();
|
||||
|
||||
if (missionComponent != nullptr) {
|
||||
missionComponent->Progress(eMissionTaskType::PLAYER_FLAG, flagId);
|
||||
}
|
||||
}
|
||||
|
||||
const auto flagEntry = CDPlayerFlagsTable::GetEntry(flagId);
|
||||
|
||||
if (flagEntry && flagEntry->sessionOnly) {
|
||||
if (value) m_SessionFlags.insert(flagId);
|
||||
else m_SessionFlags.erase(flagId);
|
||||
} else {
|
||||
// Calculate the index first
|
||||
auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
|
||||
// Check if flag index exists
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Update the value
|
||||
if (value) {
|
||||
it->second |= shiftedValue;
|
||||
} else {
|
||||
it->second &= ~shiftedValue;
|
||||
}
|
||||
} else {
|
||||
if (value) {
|
||||
// Otherwise, insert the value
|
||||
uint64_t flagValue = 0;
|
||||
|
||||
flagValue |= shiftedValue;
|
||||
|
||||
m_PlayerFlags.insert(std::make_pair(flagIndex, flagValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify the client that a flag has changed server-side
|
||||
GameMessages::SendNotifyClientFlagChange(m_Parent->GetObjectID(), flagId, value, m_Parent->GetSystemAddress());
|
||||
}
|
||||
|
||||
bool FlagComponent::GetPlayerFlag(const uint32_t flagId) const {
|
||||
bool toReturn = false; //by def, return false.
|
||||
|
||||
const auto flagEntry = CDPlayerFlagsTable::GetEntry(flagId);
|
||||
if (flagEntry && flagEntry->sessionOnly) {
|
||||
toReturn = m_SessionFlags.contains(flagId);
|
||||
} else {
|
||||
// Calculate the index first
|
||||
const auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Don't set the data if we don't have to
|
||||
toReturn = (it->second & shiftedValue) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
bool FlagComponent::OnSetRetroactiveFlags(GameMessages::GameMsg& msg) {
|
||||
// Retroactive check for if player has joined a faction to set their 'joined a faction' flag to true.
|
||||
if (GetPlayerFlag(ePlayerFlag::VENTURE_FACTION) ||
|
||||
GetPlayerFlag(ePlayerFlag::ASSEMBLY_FACTION) ||
|
||||
GetPlayerFlag(ePlayerFlag::PARADOX_FACTION) ||
|
||||
GetPlayerFlag(ePlayerFlag::SENTINEL_FACTION)) {
|
||||
SetPlayerFlag(ePlayerFlag::JOINED_A_FACTION, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlagComponent::ClearSessionFlags(tinyxml2::XMLDocument& doc) {
|
||||
if (!doc.FirstChildElement("obj")) return;
|
||||
auto& obj = *doc.FirstChildElement("obj");
|
||||
|
||||
if (!obj.FirstChildElement("flag")) return;
|
||||
auto& flags = *obj.FirstChildElement("flag");
|
||||
|
||||
auto* currentChild = flags.FirstChildElement();
|
||||
while (currentChild) {
|
||||
auto* nextChild = currentChild->NextSiblingElement();
|
||||
if (currentChild->Attribute("si")) {
|
||||
flags.DeleteChild(currentChild);
|
||||
}
|
||||
currentChild = nextChild;
|
||||
}
|
||||
}
|
59
dGame/dComponents/FlagComponent.h
Normal file
59
dGame/dComponents/FlagComponent.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef FLAGCOMPONENT_H
|
||||
#define FLAGCOMPONENT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
class FlagComponent final : public Component {
|
||||
public:
|
||||
static const inline eReplicaComponentType ComponentType = eReplicaComponentType::FLAG;
|
||||
FlagComponent(Entity* parent);
|
||||
|
||||
void UpdateXml(tinyxml2::XMLDocument& doc) override;
|
||||
void LoadFromXml(const tinyxml2::XMLDocument& doc) override;
|
||||
|
||||
// Used to clear the save data from a static context where you only have a doc (switching characters)
|
||||
static void ClearSessionFlags(tinyxml2::XMLDocument& doc);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Sets a flag for the character, indicating certain parts of the game that have been interacted with. Not to be
|
||||
* confused with the permissions
|
||||
* @param flagId the ID of the flag to set
|
||||
* @param value the value to set for the flag
|
||||
*/
|
||||
bool OnSetFlag(GameMessages::GameMsg& msg);
|
||||
void SetPlayerFlag(const uint32_t flagId, const bool value);
|
||||
|
||||
/**
|
||||
* Gets the value for a certain character flag
|
||||
* @param flagId the ID of the flag to get a value for
|
||||
* @return the value of the flag given the ID (the default is false, obviously)
|
||||
*/
|
||||
bool OnGetFlag(GameMessages::GameMsg& msg);
|
||||
bool GetPlayerFlag(const uint32_t flagId) const;
|
||||
|
||||
bool OnClearSessionFlags(GameMessages::GameMsg& msg) { m_SessionFlags.clear(); return true; }
|
||||
|
||||
/**
|
||||
* Sets any flags that are meant to have been set that may not have been set due to them being
|
||||
* missing in a previous patch.
|
||||
*/
|
||||
bool OnSetRetroactiveFlags(GameMessages::GameMsg& msg);
|
||||
/**
|
||||
* Flags only set for the duration of a session
|
||||
*
|
||||
*/
|
||||
std::set<uint32_t> m_SessionFlags;
|
||||
|
||||
/**
|
||||
* The gameplay flags this character has (not just true values)
|
||||
*/
|
||||
std::unordered_map<uint32_t, uint64_t> m_PlayerFlags;
|
||||
};
|
||||
|
||||
#endif //!FLAGCOMPONENT_H
|
@@ -557,7 +557,11 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
|
||||
|
||||
// Triggers the catch a pet missions
|
||||
if (petFlags.find(m_Parent->GetLOT()) != petFlags.end()) {
|
||||
tamer->GetCharacter()->SetPlayerFlag(petFlags.at(m_Parent->GetLOT()), true);
|
||||
GameMessages::SetFlag setFlag{};
|
||||
setFlag.target = tamer->GetObjectID();
|
||||
setFlag.iFlagId = petFlags.at(m_Parent->GetLOT());
|
||||
setFlag.bFlag = true;
|
||||
SEND_ENTITY_MSG(setFlag);
|
||||
}
|
||||
|
||||
auto* missionComponent = tamer->GetComponent<MissionComponent>();
|
||||
@@ -847,7 +851,11 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
owner->GetCharacter()->SetPlayerFlag(ePlayerFlag::FIRST_MANUAL_PET_HIBERNATE, true);
|
||||
GameMessages::SetFlag setFlag{};
|
||||
setFlag.target = owner->GetObjectID();
|
||||
setFlag.iFlagId = ePlayerFlag::FIRST_MANUAL_PET_HIBERNATE;
|
||||
setFlag.bFlag = true;
|
||||
SEND_ENTITY_MSG(setFlag);
|
||||
|
||||
if (registerPet) {
|
||||
GameMessages::SendAddPetToPlayer(m_Owner, 0, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, m_Parent->GetLOT(), owner->GetSystemAddress());
|
||||
|
@@ -481,14 +481,12 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) {
|
||||
}
|
||||
|
||||
// Set flag
|
||||
auto* character = user->GetCharacter();
|
||||
|
||||
if (character != nullptr) {
|
||||
const auto flagNumber = m_Parent->GetVar<int32_t>(u"quickbuild_single_build_player_flag");
|
||||
|
||||
if (flagNumber != 0) {
|
||||
character->SetPlayerFlag(flagNumber, true);
|
||||
}
|
||||
if (m_Parent->HasVar(u"quickbuild_single_build_player_flag")) {
|
||||
GameMessages::SetFlag setFlag{};
|
||||
setFlag.target = user->GetObjectID();
|
||||
setFlag.iFlagId = m_Parent->GetVar<int32_t>(u"quickbuild_single_build_player_flag");
|
||||
setFlag.bFlag = true;
|
||||
SEND_ENTITY_MSG(setFlag);
|
||||
}
|
||||
RenderComponent::PlayAnimation(user, u"rebuild-celebrate", 1.09f);
|
||||
}
|
||||
|
Reference in New Issue
Block a user