mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-27 02:22:04 +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
	 David Markowitz
					David Markowitz