mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-11-25 02:38:27 +00:00
Merge branch 'DarkflameUniverse:main' into PetFixes
This commit is contained in:
@@ -8,58 +8,27 @@ set(DGAME_SOURCES "Character.cpp"
|
||||
"User.cpp"
|
||||
"UserManager.cpp")
|
||||
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/dScripts
|
||||
${PROJECT_SOURCE_DIR}/dGame
|
||||
)
|
||||
|
||||
add_library(dGameBase ${DGAME_SOURCES})
|
||||
target_precompile_headers(dGameBase PRIVATE ${HEADERS_DGAME})
|
||||
target_link_libraries(dGameBase
|
||||
PUBLIC dDatabase dPhysics
|
||||
INTERFACE dComponents dEntity)
|
||||
|
||||
add_subdirectory(dBehaviors)
|
||||
|
||||
foreach(file ${DGAME_DBEHAVIORS_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dBehaviors/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dComponents)
|
||||
|
||||
foreach(file ${DGAME_DCOMPONENTS_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dComponents/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dEntity)
|
||||
|
||||
foreach(file ${DGAME_DENTITY_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dEntity/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dGameMessages)
|
||||
|
||||
foreach(file ${DGAME_DGAMEMESSAGES_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dGameMessages/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dInventory)
|
||||
|
||||
foreach(file ${DGAME_DINVENTORY_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dInventory/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dMission)
|
||||
|
||||
foreach(file ${DGAME_DMISSION_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dMission/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dPropertyBehaviors)
|
||||
|
||||
foreach(file ${DGAME_DPROPERTYBEHAVIORS_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dPropertyBehaviors/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(dUtilities)
|
||||
|
||||
foreach(file ${DGAME_DUTILITIES_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "dUtilities/${file}")
|
||||
endforeach()
|
||||
|
||||
foreach(file ${DSCRIPTS_SOURCES})
|
||||
set(DGAME_SOURCES ${DGAME_SOURCES} "${PROJECT_SOURCE_DIR}/dScripts/${file}")
|
||||
endforeach()
|
||||
|
||||
add_library(dGame STATIC ${DGAME_SOURCES})
|
||||
|
||||
target_link_libraries(dGame dDatabase Recast Detour)
|
||||
add_library(dGame INTERFACE)
|
||||
target_link_libraries(dGame INTERFACE
|
||||
dGameBase dBehaviors dComponents dEntity dGameMessages dInventory dMission dPropertyBehaviors dUtilities dScripts
|
||||
)
|
||||
|
||||
@@ -263,7 +263,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
}
|
||||
|
||||
//Now that the name is ok, we can get an objectID from Master:
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) {
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=, this](uint32_t objectID) {
|
||||
if (Database::Get()->GetCharacterInfo(objectID)) {
|
||||
LOG("Character object id unavailable, check object_id_tracker!");
|
||||
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
|
||||
|
||||
@@ -54,4 +54,9 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
|
||||
"TargetCasterBehavior.cpp"
|
||||
"TauntBehavior.cpp"
|
||||
"VentureVisionBehavior.cpp"
|
||||
"VerifyBehavior.cpp" PARENT_SCOPE)
|
||||
"VerifyBehavior.cpp")
|
||||
|
||||
add_library(dBehaviors STATIC ${DGAME_DBEHAVIORS_SOURCES})
|
||||
target_link_libraries(dBehaviors PUBLIC dPhysics)
|
||||
target_include_directories(dBehaviors PUBLIC ".")
|
||||
target_precompile_headers(dBehaviors REUSE_FROM dGameBase)
|
||||
|
||||
@@ -33,7 +33,7 @@ ActivityComponent::ActivityComponent(Entity* parent, int32_t activityID) : Compo
|
||||
if (activityID > 0) m_ActivityID = activityID;
|
||||
else m_ActivityID = parent->GetVar<int32_t>(u"activityID");
|
||||
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([this](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
|
||||
for (CDActivities activity : activities) {
|
||||
m_ActivityInfo = activity;
|
||||
@@ -93,7 +93,7 @@ void ActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIniti
|
||||
|
||||
void ActivityComponent::ReloadConfig() {
|
||||
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([this](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
for (auto activity : activities) {
|
||||
auto mapID = m_ActivityInfo.instanceMapID;
|
||||
if (static_cast<Leaderboard::Type>(activity.leaderboardType) == Leaderboard::Type::Racing && Game::config->GetValue("solo_racing") == "1") {
|
||||
@@ -532,7 +532,7 @@ void ActivityInstance::RewardParticipant(Entity* participant) {
|
||||
|
||||
// First, get the activity data
|
||||
auto* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([this](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
|
||||
|
||||
if (!activityRewards.empty()) {
|
||||
uint32_t minCoins = 0;
|
||||
|
||||
@@ -95,10 +95,16 @@ void BuffComponent::Update(float deltaTime) {
|
||||
|
||||
if (buff.second.time <= 0.0f) {
|
||||
RemoveBuff(buff.first);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_BuffsToRemove.empty()) return;
|
||||
|
||||
for (const auto& buff : m_BuffsToRemove) {
|
||||
m_Buffs.erase(buff);
|
||||
}
|
||||
|
||||
m_BuffsToRemove.clear();
|
||||
}
|
||||
|
||||
const std::string& GetFxName(const std::string& buffname) {
|
||||
@@ -216,7 +222,7 @@ void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity
|
||||
|
||||
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
|
||||
|
||||
m_Buffs.erase(iter);
|
||||
m_BuffsToRemove.push_back(id);
|
||||
|
||||
RemoveBuffEffect(id);
|
||||
}
|
||||
|
||||
@@ -140,6 +140,9 @@ private:
|
||||
*/
|
||||
std::map<int32_t, Buff> m_Buffs;
|
||||
|
||||
// Buffs to remove at the end of the update frame.
|
||||
std::vector<int32_t> m_BuffsToRemove;
|
||||
|
||||
/**
|
||||
* Parameters (=effects) for each buff
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
set(DGAME_DCOMPONENTS_SOURCES "ActivityComponent.cpp"
|
||||
set(DGAME_DCOMPONENTS_SOURCES
|
||||
"ActivityComponent.cpp"
|
||||
"BaseCombatAIComponent.cpp"
|
||||
"BouncerComponent.cpp"
|
||||
"BuffComponent.cpp"
|
||||
@@ -46,5 +47,11 @@ set(DGAME_DCOMPONENTS_SOURCES "ActivityComponent.cpp"
|
||||
"HavokVehiclePhysicsComponent.cpp"
|
||||
"VendorComponent.cpp"
|
||||
"MiniGameControlComponent.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
add_library(dComponents STATIC ${DGAME_DCOMPONENTS_SOURCES})
|
||||
target_include_directories(dComponents PRIVATE ${PROJECT_SOURCE_DIR}/dScripts/02_server/Map/General) # PetDigServer.h
|
||||
target_precompile_headers(dComponents REUSE_FROM dGameBase)
|
||||
target_link_libraries(dComponents
|
||||
PUBLIC dPhysics dDatabase
|
||||
INTERFACE dUtilities dCommon dBehaviors dChatFilter dMission dInventory)
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#include "ModelComponent.h"
|
||||
#include "Entity.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include "BehaviorStates.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
|
||||
ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
|
||||
m_OriginalPosition = m_Parent->GetDefaultPosition();
|
||||
m_OriginalRotation = m_Parent->GetDefaultRotation();
|
||||
@@ -29,3 +35,40 @@ void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialU
|
||||
outBitStream->Write1(); // Is this model paused
|
||||
if (bIsInitialUpdate) outBitStream->Write0(); // We are not writing model editing info
|
||||
}
|
||||
|
||||
void ModelComponent::UpdatePendingBehaviorId(const int32_t newId) {
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == -1) behavior.SetBehaviorId(newId);
|
||||
}
|
||||
|
||||
void ModelComponent::SendBehaviorListToClient(AMFArrayValue& args) const {
|
||||
args.Insert("objectID", std::to_string(m_Parent->GetObjectID()));
|
||||
|
||||
auto* behaviorArray = args.InsertArray("behaviors");
|
||||
for (auto& behavior : m_Behaviors) {
|
||||
auto* behaviorArgs = behaviorArray->PushArray();
|
||||
behavior.SendBehaviorListToClient(*behaviorArgs);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelComponent::VerifyBehaviors() {
|
||||
for (auto& behavior : m_Behaviors) behavior.VerifyLastEditedState();
|
||||
}
|
||||
|
||||
void ModelComponent::SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const {
|
||||
args.Insert("BehaviorID", std::to_string(behaviorToSend));
|
||||
args.Insert("objectID", std::to_string(m_Parent->GetObjectID()));
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == behaviorToSend) behavior.SendBehaviorBlocksToClient(args);
|
||||
}
|
||||
|
||||
void ModelComponent::AddBehavior(AddMessage& msg) {
|
||||
// Can only have 1 of the loot behaviors
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == msg.GetBehaviorId()) return;
|
||||
m_Behaviors.insert(m_Behaviors.begin() + msg.GetBehaviorIndex(), PropertyBehavior());
|
||||
m_Behaviors.at(msg.GetBehaviorIndex()).HandleMsg(msg);
|
||||
}
|
||||
|
||||
void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) {
|
||||
if (msg.GetBehaviorIndex() >= m_Behaviors.size() || m_Behaviors.at(msg.GetBehaviorIndex()).GetBehaviorId() != msg.GetBehaviorId()) return;
|
||||
m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex());
|
||||
// TODO move to the inventory
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include "RakNetTypes.h"
|
||||
#include "NiPoint3.h"
|
||||
@@ -6,7 +9,15 @@
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "PropertyBehavior.h"
|
||||
#include "StripUiPosition.h"
|
||||
|
||||
class AddMessage;
|
||||
class AMFArrayValue;
|
||||
class BehaviorMessageBase;
|
||||
class Entity;
|
||||
class MoveToInventoryMessage;
|
||||
|
||||
/**
|
||||
* Component that represents entities that are a model, e.g. collectible models and BBB models.
|
||||
@@ -43,7 +54,68 @@ public:
|
||||
*/
|
||||
void SetRotation(const NiQuaternion& rot) { m_OriginalRotation = rot; }
|
||||
|
||||
/**
|
||||
* Main gateway for all behavior messages to be passed to their respective behaviors.
|
||||
*
|
||||
* @tparam Msg The message type to pass
|
||||
* @param args the arguments of the message to be deserialized
|
||||
*/
|
||||
template<typename Msg>
|
||||
void HandleControlBehaviorsMsg(AMFArrayValue* args) {
|
||||
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "Msg must be a BehaviorMessageBase");
|
||||
Msg msg(args);
|
||||
for (auto& behavior : m_Behaviors) {
|
||||
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
|
||||
behavior.HandleMsg(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we somehow added more than 5 behaviors, resize to 5.
|
||||
if (m_Behaviors.size() > 5) m_Behaviors.resize(5);
|
||||
|
||||
// Do not allow more than 5 to be added. The client UI will break if you do!
|
||||
if (m_Behaviors.size() == 5) return;
|
||||
|
||||
auto newBehavior = m_Behaviors.insert(m_Behaviors.begin(), PropertyBehavior());
|
||||
// Generally if we are inserting a new behavior, it is because the client is creating a new behavior.
|
||||
// However if we are testing behaviors the behavior will not exist on the initial pass, so we set the ID here to that of the msg.
|
||||
// This will either set the ID to -1 (no change in the current default) or set the ID to the ID of the behavior we are testing.
|
||||
newBehavior->SetBehaviorId(msg.GetBehaviorId());
|
||||
newBehavior->HandleMsg(msg);
|
||||
};
|
||||
|
||||
void AddBehavior(AddMessage& msg);
|
||||
|
||||
void MoveToInventory(MoveToInventoryMessage& msg);
|
||||
|
||||
// Updates the pending behavior ID to the new ID.
|
||||
void UpdatePendingBehaviorId(const int32_t newId);
|
||||
|
||||
// Sends the behavior list to the client.
|
||||
|
||||
/**
|
||||
* The behaviors AMFArray will have up to 5 elements in the dense portion.
|
||||
* Each element in the dense portion will be made up of another AMFArray
|
||||
* with the following information mapped in the associative portion
|
||||
* "id": Behavior ID cast to an AMFString
|
||||
* "isLocked": AMFTrue or AMFFalse of whether or not the behavior is locked
|
||||
* "isLoot": AMFTrue or AMFFalse of whether or not the behavior is a custom behavior (true if custom)
|
||||
* "name": The name of the behavior formatted as an AMFString
|
||||
*/
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
|
||||
void SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const;
|
||||
|
||||
void VerifyBehaviors();
|
||||
|
||||
private:
|
||||
/**
|
||||
* The behaviors of the model
|
||||
* Note: This is a vector because the order of the behaviors matters when serializing to the client.
|
||||
* Note: No two PropertyBehaviors should have the same behavior ID.
|
||||
*/
|
||||
std::vector<PropertyBehavior> m_Behaviors;
|
||||
|
||||
/**
|
||||
* The original position of the model
|
||||
|
||||
@@ -312,7 +312,7 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
|
||||
}
|
||||
|
||||
// Respawn the player in 2 seconds, as was done in live. Not sure if this value is in a setting somewhere else...
|
||||
vehicle->AddCallbackTimer(2.0f, [=]() {
|
||||
vehicle->AddCallbackTimer(2.0f, [=, this]() {
|
||||
if (!vehicle || !this->m_Parent) return;
|
||||
GameMessages::SendRacingResetPlayerToLastReset(
|
||||
m_Parent->GetObjectID(), racingPlayer.playerID,
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
set(DGAME_DENTITY_SOURCES "EntityCallbackTimer.cpp"
|
||||
"EntityTimer.cpp" PARENT_SCOPE)
|
||||
set(DGAME_DENTITY_SOURCES
|
||||
"EntityCallbackTimer.cpp"
|
||||
"EntityTimer.cpp")
|
||||
|
||||
add_library(dEntity STATIC ${DGAME_DENTITY_SOURCES})
|
||||
target_include_directories(dEntity PUBLIC ".")
|
||||
target_precompile_headers(dEntity REUSE_FROM dGameBase)
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp"
|
||||
set(DGAME_DGAMEMESSAGES_SOURCES
|
||||
"GameMessageHandler.cpp"
|
||||
"GameMessages.cpp"
|
||||
"PropertyDataMessage.cpp"
|
||||
"PropertySelectQueryProperty.cpp" PARENT_SCOPE)
|
||||
"PropertySelectQueryProperty.cpp")
|
||||
|
||||
add_library(dGameMessages STATIC ${DGAME_DGAMEMESSAGES_SOURCES})
|
||||
target_link_libraries(dGameMessages PUBLIC dDatabase)
|
||||
target_precompile_headers(dGameMessages REUSE_FROM dGameBase)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
set(DGAME_DINVENTORY_SOURCES "EquippedItem.cpp"
|
||||
set(DGAME_DINVENTORY_SOURCES
|
||||
"EquippedItem.cpp"
|
||||
"Inventory.cpp"
|
||||
"Item.cpp"
|
||||
"ItemSet.cpp"
|
||||
"ItemSetPassiveAbility.cpp" PARENT_SCOPE)
|
||||
"ItemSetPassiveAbility.cpp")
|
||||
|
||||
add_library(dInventory STATIC ${DGAME_DINVENTORY_SOURCES})
|
||||
target_precompile_headers(dInventory REUSE_FROM dGameBase)
|
||||
|
||||
@@ -249,7 +249,7 @@ bool Item::IsEquipped() const {
|
||||
bool Item::Consume() {
|
||||
auto* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>();
|
||||
|
||||
auto skills = skillsTable->Query([=](const CDObjectSkills entry) {
|
||||
auto skills = skillsTable->Query([this](const CDObjectSkills entry) {
|
||||
return entry.objectTemplate == static_cast<uint32_t>(lot);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
set(DGAME_DMISSION_SOURCES "Mission.cpp"
|
||||
set(DGAME_DMISSION_SOURCES
|
||||
"Mission.cpp"
|
||||
"MissionPrerequisites.cpp"
|
||||
"MissionTask.cpp" PARENT_SCOPE)
|
||||
"MissionTask.cpp")
|
||||
|
||||
add_library(dMission STATIC ${DGAME_DMISSION_SOURCES})
|
||||
target_link_libraries(dMission PUBLIC dDatabase)
|
||||
target_precompile_headers(dMission REUSE_FROM dGameBase)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
set(DGAME_DPROPERTYBEHAVIORS_SOURCES
|
||||
"PropertyBehavior.cpp"
|
||||
"State.cpp"
|
||||
"Strip.cpp"
|
||||
"BlockDefinition.cpp"
|
||||
"ControlBehaviors.cpp"
|
||||
)
|
||||
@@ -9,4 +12,5 @@ foreach(file ${DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES})
|
||||
set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} "ControlBehaviorMessages/${file}")
|
||||
endforeach()
|
||||
|
||||
set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} PARENT_SCOPE)
|
||||
add_library(dPropertyBehaviors STATIC ${DGAME_DPROPERTYBEHAVIORS_SOURCES})
|
||||
target_precompile_headers(dPropertyBehaviors REUSE_FROM dGameBase)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Action.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
Action::Action() {
|
||||
type = "";
|
||||
@@ -12,20 +13,34 @@ Action::Action(AMFArrayValue* arguments) {
|
||||
valueParameterName = "";
|
||||
valueParameterString = "";
|
||||
valueParameterDouble = 0.0;
|
||||
for (auto& typeValueMap : arguments->GetAssociative()) {
|
||||
if (typeValueMap.first == "Type") {
|
||||
if (typeValueMap.second->GetValueType() != eAmf::String) continue;
|
||||
type = static_cast<AMFStringValue*>(typeValueMap.second)->GetValue();
|
||||
for (auto& [paramName, paramValue] : arguments->GetAssociative()) {
|
||||
if (paramName == "Type") {
|
||||
if (paramValue->GetValueType() != eAmf::String) continue;
|
||||
type = static_cast<AMFStringValue*>(paramValue)->GetValue();
|
||||
} else {
|
||||
valueParameterName = typeValueMap.first;
|
||||
valueParameterName = paramName;
|
||||
// Message is the only known string parameter
|
||||
if (valueParameterName == "Message") {
|
||||
if (typeValueMap.second->GetValueType() != eAmf::String) continue;
|
||||
valueParameterString = static_cast<AMFStringValue*>(typeValueMap.second)->GetValue();
|
||||
if (paramValue->GetValueType() != eAmf::String) continue;
|
||||
valueParameterString = static_cast<AMFStringValue*>(paramValue)->GetValue();
|
||||
} else {
|
||||
if (typeValueMap.second->GetValueType() != eAmf::Double) continue;
|
||||
valueParameterDouble = static_cast<AMFDoubleValue*>(typeValueMap.second)->GetValue();
|
||||
if (paramValue->GetValueType() != eAmf::Double) continue;
|
||||
valueParameterDouble = static_cast<AMFDoubleValue*>(paramValue)->GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Action::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
|
||||
auto* actionArgs = args.PushArray();
|
||||
actionArgs->Insert("Type", type);
|
||||
|
||||
auto valueParameterName = GetValueParameterName();
|
||||
if (valueParameterName.empty()) return;
|
||||
|
||||
if (valueParameterName == "Message") {
|
||||
actionArgs->Insert(valueParameterName, valueParameterString);
|
||||
} else {
|
||||
actionArgs->Insert(valueParameterName, valueParameterDouble);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef __ACTION__H__
|
||||
#define __ACTION__H__
|
||||
|
||||
#include "BehaviorMessageBase.h"
|
||||
#include <string>
|
||||
|
||||
class AMFArrayValue;
|
||||
|
||||
/**
|
||||
* @brief Sent if a ControlBehavior message has an Action associated with it
|
||||
@@ -11,10 +13,12 @@ class Action {
|
||||
public:
|
||||
Action();
|
||||
Action(AMFArrayValue* arguments);
|
||||
const std::string& GetType() { return type; };
|
||||
const std::string& GetValueParameterName() { return valueParameterName; };
|
||||
const std::string& GetValueParameterString() { return valueParameterString; };
|
||||
const double GetValueParameterDouble() { return valueParameterDouble; };
|
||||
const std::string& GetType() const { return type; };
|
||||
const std::string& GetValueParameterName() const { return valueParameterName; };
|
||||
const std::string& GetValueParameterString() const { return valueParameterString; };
|
||||
const double GetValueParameterDouble() const { return valueParameterDouble; };
|
||||
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
private:
|
||||
std::string type;
|
||||
std::string valueParameterName;
|
||||
|
||||
@@ -14,8 +14,8 @@ class ActionContext {
|
||||
public:
|
||||
ActionContext();
|
||||
ActionContext(AMFArrayValue* arguments, std::string customStateKey = "stateID", std::string customStripKey = "stripID");
|
||||
const StripId GetStripId() { return stripId; };
|
||||
const BehaviorState GetStateId() { return stateId; };
|
||||
const StripId GetStripId() const { return stripId; };
|
||||
const BehaviorState GetStateId() const { return stateId; };
|
||||
private:
|
||||
BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key);
|
||||
StripId GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key);
|
||||
|
||||
@@ -14,11 +14,11 @@ class AMFArrayValue;
|
||||
class AddActionMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
AddActionMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetActionIndex() { return actionIndex; };
|
||||
Action GetAction() { return action; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
int32_t GetActionIndex() const { return actionIndex; };
|
||||
Action GetAction() const { return action; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
private:
|
||||
uint32_t actionIndex;
|
||||
int32_t actionIndex = -1;
|
||||
ActionContext actionContext;
|
||||
Action action;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
class AddMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
AddMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetBehaviorIndex() { return behaviorIndex; };
|
||||
const uint32_t GetBehaviorIndex() const { return behaviorIndex; };
|
||||
private:
|
||||
uint32_t behaviorIndex;
|
||||
};
|
||||
|
||||
@@ -19,9 +19,9 @@ class AMFArrayValue;
|
||||
class AddStripMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
AddStripMessage(AMFArrayValue* arguments);
|
||||
StripUiPosition GetPosition() { return position; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
std::vector<Action> GetActionsToAdd() { return actionsToAdd; };
|
||||
StripUiPosition GetPosition() const { return position; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
std::vector<Action> GetActionsToAdd() const { return actionsToAdd; };
|
||||
private:
|
||||
StripUiPosition position;
|
||||
ActionContext actionContext;
|
||||
|
||||
@@ -5,29 +5,27 @@
|
||||
#include "dCommonVars.h"
|
||||
|
||||
BehaviorMessageBase::BehaviorMessageBase(AMFArrayValue* arguments) {
|
||||
behaviorId = 0;
|
||||
behaviorId = GetBehaviorIdFromArgument(arguments);
|
||||
}
|
||||
|
||||
int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(AMFArrayValue* arguments) {
|
||||
const auto* key = "BehaviorID";
|
||||
auto* behaviorIDValue = arguments->Get<std::string>(key);
|
||||
int32_t behaviorID = -1;
|
||||
|
||||
if (behaviorIDValue && behaviorIDValue->GetValueType() == eAmf::String) {
|
||||
behaviorID = std::stoul(behaviorIDValue->GetValue());
|
||||
} else if (arguments->Get(key)->GetValueType() != eAmf::Undefined) {
|
||||
GeneralUtils::TryParse(behaviorIDValue->GetValue(), behaviorId);
|
||||
} else if (arguments->Get(key) && arguments->Get(key)->GetValueType() != eAmf::Undefined) {
|
||||
throw std::invalid_argument("Unable to find behavior ID");
|
||||
}
|
||||
|
||||
return behaviorID;
|
||||
return behaviorId;
|
||||
}
|
||||
|
||||
uint32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName) {
|
||||
int32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName) {
|
||||
auto* actionIndexAmf = arguments->Get<double>(keyName);
|
||||
if (!actionIndexAmf) {
|
||||
throw std::invalid_argument("Unable to find actionIndex");
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(actionIndexAmf->GetValue());
|
||||
return static_cast<int32_t>(actionIndexAmf->GetValue());
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
#include "Amf3.h"
|
||||
#include "dCommonVars.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
|
||||
enum class BehaviorState : uint32_t;
|
||||
|
||||
/**
|
||||
@@ -18,12 +15,14 @@ enum class BehaviorState : uint32_t;
|
||||
*/
|
||||
class BehaviorMessageBase {
|
||||
public:
|
||||
const uint32_t GetBehaviorId() { return behaviorId; };
|
||||
protected:
|
||||
static inline int32_t DefaultBehaviorId = -1;
|
||||
const int32_t GetBehaviorId() const { return behaviorId; };
|
||||
bool IsDefaultBehaviorId() { return behaviorId == DefaultBehaviorId; };
|
||||
BehaviorMessageBase(AMFArrayValue* arguments);
|
||||
protected:
|
||||
int32_t GetBehaviorIdFromArgument(AMFArrayValue* arguments);
|
||||
uint32_t GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName = "actionIndex");
|
||||
int32_t behaviorId = -1;
|
||||
int32_t GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName = "actionIndex");
|
||||
int32_t behaviorId = DefaultBehaviorId;
|
||||
};
|
||||
|
||||
#endif //!__BEHAVIORMESSAGEBASE__H__
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef __CONTROLBEHAVIORMSGS__H__
|
||||
#define __CONTROLBEHAVIORMSGS__H__
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionContext.h"
|
||||
#include "AddActionMessage.h"
|
||||
#include "AddMessage.h"
|
||||
#include "AddStripMessage.h"
|
||||
#include "BehaviorMessageBase.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
#include "MergeStripsMessage.h"
|
||||
#include "MigrateActionsMessage.h"
|
||||
#include "MoveToInventoryMessage.h"
|
||||
#include "RearrangeStripMessage.h"
|
||||
#include "RemoveActionsMessage.h"
|
||||
#include "RemoveStripMessage.h"
|
||||
#include "RenameMessage.h"
|
||||
#include "SplitStripMessage.h"
|
||||
#include "StripUiPosition.h"
|
||||
#include "UpdateActionMessage.h"
|
||||
#include "UpdateStripUiMessage.h"
|
||||
|
||||
#endif //!__CONTROLBEHAVIORMSGS__H__
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __MERGESTRIPSMESSAGE__H__
|
||||
#define __MERGESTRIPSMESSAGE__H__
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionContext.h"
|
||||
#include "BehaviorMessageBase.h"
|
||||
|
||||
@@ -13,13 +14,16 @@ class AMFArrayValue;
|
||||
class MergeStripsMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
MergeStripsMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetDstActionIndex() { return dstActionIndex; };
|
||||
ActionContext GetSourceActionContext() { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() { return destinationActionContext; };
|
||||
int32_t GetDstActionIndex() const { return dstActionIndex; };
|
||||
ActionContext GetSourceActionContext() const { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
|
||||
const std::vector<Action>& GetMigratedActions() const { return migratedActions; };
|
||||
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { migratedActions.assign(start, end); };
|
||||
private:
|
||||
std::vector<Action> migratedActions;
|
||||
ActionContext sourceActionContext;
|
||||
ActionContext destinationActionContext;
|
||||
uint32_t dstActionIndex;
|
||||
int32_t dstActionIndex;
|
||||
};
|
||||
|
||||
#endif //!__MERGESTRIPSMESSAGE__H__
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __MIGRATEACTIONSMESSAGE__H__
|
||||
#define __MIGRATEACTIONSMESSAGE__H__
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionContext.h"
|
||||
#include "BehaviorMessageBase.h"
|
||||
|
||||
@@ -13,15 +14,18 @@ class AMFArrayValue;
|
||||
class MigrateActionsMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
MigrateActionsMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetSrcActionIndex() { return srcActionIndex; };
|
||||
const uint32_t GetDstActionIndex() { return dstActionIndex; };
|
||||
ActionContext GetSourceActionContext() { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() { return destinationActionContext; };
|
||||
int32_t GetSrcActionIndex() const { return srcActionIndex; };
|
||||
int32_t GetDstActionIndex() const { return dstActionIndex; };
|
||||
ActionContext GetSourceActionContext() const { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
|
||||
const std::vector<Action>& GetMigratedActions() const { return migratedActions; };
|
||||
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { migratedActions.assign(start, end); };
|
||||
private:
|
||||
std::vector<Action> migratedActions;
|
||||
ActionContext sourceActionContext;
|
||||
ActionContext destinationActionContext;
|
||||
uint32_t srcActionIndex;
|
||||
uint32_t dstActionIndex;
|
||||
int32_t srcActionIndex;
|
||||
int32_t dstActionIndex;
|
||||
};
|
||||
|
||||
#endif //!__MIGRATEACTIONSMESSAGE__H__
|
||||
|
||||
@@ -13,7 +13,7 @@ class AMFArrayValue;
|
||||
class MoveToInventoryMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
MoveToInventoryMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetBehaviorIndex() { return behaviorIndex; };
|
||||
const uint32_t GetBehaviorIndex() const { return behaviorIndex; };
|
||||
private:
|
||||
uint32_t behaviorIndex;
|
||||
};
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
class RearrangeStripMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
RearrangeStripMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetSrcActionIndex() { return srcActionIndex; };
|
||||
const uint32_t GetDstActionIndex() { return dstActionIndex; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
int32_t GetSrcActionIndex() const { return srcActionIndex; };
|
||||
int32_t GetDstActionIndex() const { return dstActionIndex; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
private:
|
||||
ActionContext actionContext;
|
||||
uint32_t srcActionIndex;
|
||||
uint32_t dstActionIndex;
|
||||
int32_t srcActionIndex;
|
||||
int32_t dstActionIndex;
|
||||
};
|
||||
|
||||
#endif //!__REARRANGESTRIPMESSAGE__H__
|
||||
|
||||
@@ -13,11 +13,11 @@ class AMFArrayValue;
|
||||
class RemoveActionsMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
RemoveActionsMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetActionIndex() { return actionIndex; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
int32_t GetActionIndex() const { return actionIndex; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
private:
|
||||
ActionContext actionContext;
|
||||
uint32_t actionIndex;
|
||||
int32_t actionIndex;
|
||||
};
|
||||
|
||||
#endif //!__REMOVEACTIONSMESSAGE__H__
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
class RemoveStripMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
RemoveStripMessage(AMFArrayValue* arguments);
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
private:
|
||||
ActionContext actionContext;
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ class AMFArrayValue;
|
||||
class RenameMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
RenameMessage(AMFArrayValue* arguments);
|
||||
const std::string& GetName() { return name; };
|
||||
const std::string& GetName() const { return name; };
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __SPLITSTRIPMESSAGE__H__
|
||||
#define __SPLITSTRIPMESSAGE__H__
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionContext.h"
|
||||
#include "BehaviorMessageBase.h"
|
||||
#include "StripUiPosition.h"
|
||||
@@ -14,15 +15,19 @@ class AMFArrayValue;
|
||||
class SplitStripMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
SplitStripMessage(AMFArrayValue* arguments);
|
||||
ActionContext GetSourceActionContext() { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() { return destinationActionContext; };
|
||||
const uint32_t GetSrcActionIndex() { return srcActionIndex; };
|
||||
StripUiPosition GetPosition() { return destinationPosition; };
|
||||
ActionContext GetSourceActionContext() const { return sourceActionContext; };
|
||||
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
|
||||
int32_t GetSrcActionIndex() const { return srcActionIndex; };
|
||||
StripUiPosition GetPosition() const { return destinationPosition; };
|
||||
const std::vector<Action>& GetTransferredActions() const { return transferredActions; };
|
||||
void SetTransferredActions(std::vector<Action>::const_iterator begin, std::vector<Action>::const_iterator end) { transferredActions.assign(begin, end); };
|
||||
private:
|
||||
ActionContext sourceActionContext;
|
||||
ActionContext destinationActionContext;
|
||||
uint32_t srcActionIndex;
|
||||
int32_t srcActionIndex;
|
||||
StripUiPosition destinationPosition;
|
||||
|
||||
std::vector<Action> transferredActions;
|
||||
};
|
||||
|
||||
#endif //!__SPLITSTRIPMESSAGE__H__
|
||||
|
||||
@@ -20,3 +20,9 @@ StripUiPosition::StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName
|
||||
yPosition = yPositionValue->GetValue();
|
||||
xPosition = xPositionValue->GetValue();
|
||||
}
|
||||
|
||||
void StripUiPosition::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
|
||||
auto* uiArgs = args.InsertArray("ui");
|
||||
uiArgs->Insert("x", xPosition);
|
||||
uiArgs->Insert("y", yPosition);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ class StripUiPosition {
|
||||
public:
|
||||
StripUiPosition();
|
||||
StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName = "ui");
|
||||
double GetX() { return xPosition; };
|
||||
double GetY() { return yPosition; };
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
double GetX() const { return xPosition; };
|
||||
double GetY() const { return yPosition; };
|
||||
private:
|
||||
double xPosition;
|
||||
double yPosition;
|
||||
|
||||
@@ -14,11 +14,11 @@ class AMFArrayValue;
|
||||
class UpdateActionMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
UpdateActionMessage(AMFArrayValue* arguments);
|
||||
const uint32_t GetActionIndex() { return actionIndex; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
Action GetAction() { return action; };
|
||||
int32_t GetActionIndex() const { return actionIndex; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
Action GetAction() const { return action; };
|
||||
private:
|
||||
uint32_t actionIndex;
|
||||
int32_t actionIndex;
|
||||
ActionContext actionContext;
|
||||
Action action;
|
||||
};
|
||||
|
||||
@@ -14,8 +14,8 @@ class AMFArrayValue;
|
||||
class UpdateStripUiMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
UpdateStripUiMessage(AMFArrayValue* arguments);
|
||||
StripUiPosition GetPosition() { return position; };
|
||||
ActionContext GetActionContext() { return actionContext; };
|
||||
StripUiPosition GetPosition() const { return position; };
|
||||
ActionContext GetActionContext() const { return actionContext; };
|
||||
private:
|
||||
StripUiPosition position;
|
||||
ActionContext actionContext;
|
||||
|
||||
@@ -30,221 +30,49 @@
|
||||
#include "UpdateActionMessage.h"
|
||||
#include "UpdateStripUiMessage.h"
|
||||
|
||||
void ControlBehaviors::RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr) {
|
||||
// auto behavior = modelComponent->FindBehavior(behaviorID);
|
||||
// if (behavior->GetBehaviorID() == -1 || behavior->GetShouldSetNewID()) {
|
||||
// ObjectIDManager::Instance()->RequestPersistentID(
|
||||
// [behaviorID, behavior, modelComponent, modelOwner, sysAddr](uint32_t persistentId) {
|
||||
// behavior->SetShouldGetNewID(false);
|
||||
// behavior->SetIsTemplated(false);
|
||||
// behavior->SetBehaviorID(persistentId);
|
||||
void ControlBehaviors::RequestUpdatedID(ControlBehaviorContext& context) {
|
||||
ObjectIDManager::Instance()->RequestPersistentID(
|
||||
[context](uint32_t persistentId) {
|
||||
if (!context) {
|
||||
LOG("Model to update behavior ID for is null. Cannot update ID.");
|
||||
return;
|
||||
}
|
||||
// This updates the behavior ID of the behavior should this be a new behavior
|
||||
AMFArrayValue args;
|
||||
|
||||
// // This updates the behavior ID of the behavior should this be a new behavior
|
||||
// AMFArrayValue args;
|
||||
args.Insert("behaviorID", std::to_string(persistentId));
|
||||
args.Insert("objectID", std::to_string(context.modelComponent->GetParent()->GetObjectID()));
|
||||
|
||||
// AMFStringValue* behaviorIDString = new AMFStringValue();
|
||||
// behaviorIDString->SetValue(std::to_string(persistentId));
|
||||
// args.InsertValue("behaviorID", behaviorIDString);
|
||||
GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorID", args);
|
||||
context.modelComponent->UpdatePendingBehaviorId(persistentId);
|
||||
|
||||
// AMFStringValue* objectIDAsString = new AMFStringValue();
|
||||
// objectIDAsString->SetValue(std::to_string(modelComponent->GetParent()->GetObjectID()));
|
||||
// args.InsertValue("objectID", objectIDAsString);
|
||||
|
||||
// GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorID", &args);
|
||||
// ControlBehaviors::SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner);
|
||||
// });
|
||||
// }
|
||||
ControlBehaviors::Instance().SendBehaviorListToClient(context);
|
||||
});
|
||||
}
|
||||
|
||||
void ControlBehaviors::SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner) {
|
||||
auto* modelComponent = modelEntity->GetComponent<ModelComponent>();
|
||||
|
||||
if (!modelComponent) return;
|
||||
void ControlBehaviors::SendBehaviorListToClient(const ControlBehaviorContext& context) {
|
||||
if (!context) return;
|
||||
|
||||
AMFArrayValue behaviorsToSerialize;
|
||||
context.modelComponent->SendBehaviorListToClient(behaviorsToSerialize);
|
||||
|
||||
/**
|
||||
* The behaviors AMFArray will have up to 5 elements in the dense portion.
|
||||
* Each element in the dense portion will be made up of another AMFArray
|
||||
* with the following information mapped in the associative portion
|
||||
* "id": Behavior ID cast to an AMFString
|
||||
* "isLocked": AMFTrue or AMFFalse of whether or not the behavior is locked
|
||||
* "isLoot": AMFTrue or AMFFalse of whether or not the behavior is a custom behavior (true if custom)
|
||||
* "name": The name of the behavior formatted as an AMFString
|
||||
*/
|
||||
|
||||
behaviorsToSerialize.Insert("behaviors");
|
||||
behaviorsToSerialize.Insert("objectID", std::to_string(modelComponent->GetParent()->GetObjectID()));
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorList", behaviorsToSerialize);
|
||||
}
|
||||
|
||||
void ControlBehaviors::ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) {
|
||||
auto* modelTypeAmf = arguments->Get<double>("ModelType");
|
||||
if (!modelTypeAmf) return;
|
||||
|
||||
uint32_t modelType = static_cast<uint32_t>(modelTypeAmf->GetValue());
|
||||
|
||||
//TODO Update the model type here
|
||||
}
|
||||
|
||||
void ControlBehaviors::ToggleExecutionUpdates() {
|
||||
//TODO do something with this info
|
||||
}
|
||||
|
||||
void ControlBehaviors::AddStrip(AMFArrayValue* arguments) {
|
||||
AddStripMessage addStripMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::RemoveStrip(AMFArrayValue* arguments) {
|
||||
RemoveStripMessage removeStrip(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::MergeStrips(AMFArrayValue* arguments) {
|
||||
MergeStripsMessage mergeStripsMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::SplitStrip(AMFArrayValue* arguments) {
|
||||
SplitStripMessage splitStripMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::UpdateStripUI(AMFArrayValue* arguments) {
|
||||
UpdateStripUiMessage updateStripUiMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::AddAction(AMFArrayValue* arguments) {
|
||||
AddActionMessage addActionMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::MigrateActions(AMFArrayValue* arguments) {
|
||||
MigrateActionsMessage migrateActionsMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::RearrangeStrip(AMFArrayValue* arguments) {
|
||||
RearrangeStripMessage rearrangeStripMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::Add(AMFArrayValue* arguments) {
|
||||
AddMessage addMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::RemoveActions(AMFArrayValue* arguments) {
|
||||
RemoveActionsMessage removeActionsMessage(arguments);
|
||||
}
|
||||
|
||||
void ControlBehaviors::Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) {
|
||||
RenameMessage renameMessage(arguments);
|
||||
GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorList", behaviorsToSerialize);
|
||||
}
|
||||
|
||||
// TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet
|
||||
void ControlBehaviors::SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) {
|
||||
// uint32_t behaviorID = ControlBehaviors::GetBehaviorIDFromArgument(arguments);
|
||||
void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& context) {
|
||||
if (!context) return;
|
||||
BehaviorMessageBase behaviorMsg(context.arguments);
|
||||
|
||||
// auto modelBehavior = modelComponent->FindBehavior(behaviorID);
|
||||
|
||||
// if (!modelBehavior) return;
|
||||
|
||||
// modelBehavior->VerifyStates();
|
||||
|
||||
// auto states = modelBehavior->GetBehaviorStates();
|
||||
|
||||
// // Begin serialization.
|
||||
|
||||
// /**
|
||||
// * for each state
|
||||
// * strip id
|
||||
// * ui info
|
||||
// * x
|
||||
// * y
|
||||
// * actions
|
||||
// * action1
|
||||
// * action2
|
||||
// * ...
|
||||
// * behaviorID of strip
|
||||
// * objectID of strip
|
||||
// */
|
||||
// LWOOBJID targetObjectID = LWOOBJID_EMPTY;
|
||||
// behaviorID = 0;
|
||||
// AMFArrayValue behaviorInfo;
|
||||
|
||||
// AMFArrayValue* stateSerialize = new AMFArrayValue();
|
||||
|
||||
// for (auto it = states.begin(); it != states.end(); it++) {
|
||||
// LOG("Begin serialization of state %i!\n", it->first);
|
||||
// AMFArrayValue* state = new AMFArrayValue();
|
||||
|
||||
// AMFDoubleValue* stateAsDouble = new AMFDoubleValue();
|
||||
// stateAsDouble->SetValue(it->first);
|
||||
// state->InsertValue("id", stateAsDouble);
|
||||
|
||||
// AMFArrayValue* strips = new AMFArrayValue();
|
||||
// auto stripsInState = it->second->GetStrips();
|
||||
// for (auto strip = stripsInState.begin(); strip != stripsInState.end(); strip++) {
|
||||
// LOG("Begin serialization of strip %i!\n", strip->first);
|
||||
// AMFArrayValue* thisStrip = new AMFArrayValue();
|
||||
|
||||
// AMFDoubleValue* stripID = new AMFDoubleValue();
|
||||
// stripID->SetValue(strip->first);
|
||||
// thisStrip->InsertValue("id", stripID);
|
||||
|
||||
// AMFArrayValue* uiArray = new AMFArrayValue();
|
||||
// AMFDoubleValue* yPosition = new AMFDoubleValue();
|
||||
// yPosition->SetValue(strip->second->GetYPosition());
|
||||
// uiArray->InsertValue("y", yPosition);
|
||||
|
||||
// AMFDoubleValue* xPosition = new AMFDoubleValue();
|
||||
// xPosition->SetValue(strip->second->GetXPosition());
|
||||
// uiArray->InsertValue("x", xPosition);
|
||||
|
||||
// thisStrip->InsertValue("ui", uiArray);
|
||||
// targetObjectID = modelComponent->GetParent()->GetObjectID();
|
||||
// behaviorID = modelBehavior->GetBehaviorID();
|
||||
|
||||
// AMFArrayValue* stripSerialize = new AMFArrayValue();
|
||||
// for (auto behaviorAction : strip->second->GetActions()) {
|
||||
// LOG("Begin serialization of action %s!\n", behaviorAction->actionName.c_str());
|
||||
// AMFArrayValue* thisAction = new AMFArrayValue();
|
||||
|
||||
// AMFStringValue* actionName = new AMFStringValue();
|
||||
// actionName->SetValue(behaviorAction->actionName);
|
||||
// thisAction->InsertValue("Type", actionName);
|
||||
|
||||
// if (behaviorAction->parameterValueString != "")
|
||||
// {
|
||||
// AMFStringValue* valueAsString = new AMFStringValue();
|
||||
// valueAsString->SetValue(behaviorAction->parameterValueString);
|
||||
// thisAction->InsertValue(behaviorAction->parameterName, valueAsString);
|
||||
// }
|
||||
// else if (behaviorAction->parameterValueDouble != 0.0)
|
||||
// {
|
||||
// AMFDoubleValue* valueAsDouble = new AMFDoubleValue();
|
||||
// valueAsDouble->SetValue(behaviorAction->parameterValueDouble);
|
||||
// thisAction->InsertValue(behaviorAction->parameterName, valueAsDouble);
|
||||
// }
|
||||
// stripSerialize->PushBackValue(thisAction);
|
||||
// }
|
||||
// thisStrip->InsertValue("actions", stripSerialize);
|
||||
// strips->PushBackValue(thisStrip);
|
||||
// }
|
||||
// state->InsertValue("strips", strips);
|
||||
// stateSerialize->PushBackValue(state);
|
||||
// }
|
||||
// behaviorInfo.InsertValue("states", stateSerialize);
|
||||
|
||||
// AMFStringValue* objectidAsString = new AMFStringValue();
|
||||
// objectidAsString->SetValue(std::to_string(targetObjectID));
|
||||
// behaviorInfo.InsertValue("objectID", objectidAsString);
|
||||
|
||||
// AMFStringValue* behaviorIDAsString = new AMFStringValue();
|
||||
// behaviorIDAsString->SetValue(std::to_string(behaviorID));
|
||||
// behaviorInfo.InsertValue("BehaviorID", behaviorIDAsString);
|
||||
|
||||
// GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorBlocks", &behaviorInfo);
|
||||
context.modelComponent->VerifyBehaviors();
|
||||
AMFArrayValue behavior;
|
||||
context.modelComponent->SendBehaviorBlocksToClient(behaviorMsg.GetBehaviorId(), behavior);
|
||||
GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorBlocks", behavior);
|
||||
}
|
||||
|
||||
void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) {
|
||||
UpdateActionMessage updateActionMessage(arguments);
|
||||
auto* blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType());
|
||||
auto blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType());
|
||||
|
||||
if (!blockDefinition) {
|
||||
LOG("Received undefined block type %s. Ignoring.", updateActionMessage.GetAction().GetType().c_str());
|
||||
@@ -266,75 +94,83 @@ void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) {
|
||||
}
|
||||
}
|
||||
|
||||
void ControlBehaviors::MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) {
|
||||
// This closes the UI menu should it be open while the player is removing behaviors
|
||||
AMFArrayValue args;
|
||||
|
||||
args.Insert("visible", false);
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, modelOwner->GetParentUser()->GetSystemAddress(), "ToggleBehaviorEditor", args);
|
||||
|
||||
MoveToInventoryMessage moveToInventoryMessage(arguments);
|
||||
|
||||
SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner);
|
||||
}
|
||||
|
||||
void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) {
|
||||
if (!isInitialized || !modelEntity || !modelOwner || !arguments) return;
|
||||
auto* modelComponent = modelEntity->GetComponent<ModelComponent>();
|
||||
|
||||
if (!modelComponent) return;
|
||||
|
||||
if (command == "sendBehaviorListToClient")
|
||||
SendBehaviorListToClient(modelEntity, sysAddr, modelOwner);
|
||||
else if (command == "modelTypeChanged")
|
||||
ModelTypeChanged(arguments, modelComponent);
|
||||
else if (command == "toggleExecutionUpdates")
|
||||
ToggleExecutionUpdates();
|
||||
else if (command == "addStrip")
|
||||
AddStrip(arguments);
|
||||
else if (command == "removeStrip")
|
||||
RemoveStrip(arguments);
|
||||
else if (command == "mergeStrips")
|
||||
MergeStrips(arguments);
|
||||
else if (command == "splitStrip")
|
||||
SplitStrip(arguments);
|
||||
else if (command == "updateStripUI")
|
||||
UpdateStripUI(arguments);
|
||||
else if (command == "addAction")
|
||||
AddAction(arguments);
|
||||
else if (command == "migrateActions")
|
||||
MigrateActions(arguments);
|
||||
else if (command == "rearrangeStrip")
|
||||
RearrangeStrip(arguments);
|
||||
else if (command == "add")
|
||||
Add(arguments);
|
||||
else if (command == "removeActions")
|
||||
RemoveActions(arguments);
|
||||
else if (command == "rename")
|
||||
Rename(modelEntity, sysAddr, modelOwner, arguments);
|
||||
else if (command == "sendBehaviorBlocksToClient")
|
||||
SendBehaviorBlocksToClient(modelComponent, sysAddr, modelOwner, arguments);
|
||||
else if (command == "moveToInventory")
|
||||
MoveToInventory(modelComponent, sysAddr, modelOwner, arguments);
|
||||
else if (command == "updateAction")
|
||||
UpdateAction(arguments);
|
||||
else
|
||||
LOG("Unknown behavior command (%s)\n", command.c_str());
|
||||
ControlBehaviorContext context(arguments, modelComponent, modelOwner);
|
||||
|
||||
if (command == "sendBehaviorListToClient") {
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "modelTypeChanged") {
|
||||
auto* modelType = arguments->Get<double>("ModelType");
|
||||
if (!modelType) return;
|
||||
|
||||
modelEntity->SetVar<int>(u"modelType", modelType->GetValue());
|
||||
} else if (command == "toggleExecutionUpdates") {
|
||||
// TODO
|
||||
} else if (command == "addStrip") {
|
||||
if (BehaviorMessageBase(context.arguments).IsDefaultBehaviorId()) RequestUpdatedID(context);
|
||||
|
||||
context.modelComponent->HandleControlBehaviorsMsg<AddStripMessage>(context.arguments);
|
||||
} else if (command == "removeStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RemoveStripMessage>(arguments);
|
||||
} else if (command == "mergeStrips") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<MergeStripsMessage>(arguments);
|
||||
} else if (command == "splitStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<SplitStripMessage>(arguments);
|
||||
} else if (command == "updateStripUI") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateStripUiMessage>(arguments);
|
||||
} else if (command == "addAction") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<AddActionMessage>(arguments);
|
||||
} else if (command == "migrateActions") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<MigrateActionsMessage>(arguments);
|
||||
} else if (command == "rearrangeStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
|
||||
} else if (command == "add") {
|
||||
AddMessage msg(context.arguments);
|
||||
context.modelComponent->AddBehavior(msg);
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "removeActions") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RemoveActionsMessage>(arguments);
|
||||
} else if (command == "rename") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RenameMessage>(arguments);
|
||||
|
||||
// Send the list back to the client so the name is updated.
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "sendBehaviorBlocksToClient") {
|
||||
SendBehaviorBlocksToClient(context);
|
||||
} else if (command == "moveToInventory") {
|
||||
MoveToInventoryMessage msg(arguments);
|
||||
context.modelComponent->MoveToInventory(msg);
|
||||
|
||||
AMFArrayValue args;
|
||||
args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId()));
|
||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, modelOwner->GetParentUser()->GetSystemAddress(), "BehaviorRemoved", args);
|
||||
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "updateAction") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateActionMessage>(arguments);
|
||||
} else {
|
||||
LOG("Unknown behavior command (%s)", command.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ControlBehaviors::ControlBehaviors() {
|
||||
auto blocksBuffer = Game::assetManager->GetFile("ui\\ingame\\blocksdef.xml");
|
||||
if (!blocksBuffer) {
|
||||
LOG("Failed to open blocksdef.xml");
|
||||
LOG("Failed to open blocksdef.xml, property behaviors will be disabled for this zone! "
|
||||
"(This is a necessary file for cheat detection and ensuring we do not send unexpected values to the client)");
|
||||
return;
|
||||
}
|
||||
|
||||
tinyxml2::XMLDocument m_Doc;
|
||||
|
||||
std::string read{};
|
||||
std::string read;
|
||||
|
||||
std::string buffer{};
|
||||
std::string buffer;
|
||||
bool commentBlockStart = false;
|
||||
while (std::getline(blocksBuffer, read)) {
|
||||
// tinyxml2 should handle comment blocks but the client has one that fails the processing.
|
||||
@@ -371,14 +207,14 @@ ControlBehaviors::ControlBehaviors() {
|
||||
while (block) {
|
||||
blockName = block->Name();
|
||||
|
||||
BlockDefinition* blockDefinition = new BlockDefinition();
|
||||
auto& blockDefinition = blockTypes[blockName];
|
||||
std::string name{};
|
||||
std::string typeName{};
|
||||
|
||||
auto* argument = block->FirstChildElement("Argument");
|
||||
if (argument) {
|
||||
auto* defaultDefinition = argument->FirstChildElement("DefaultValue");
|
||||
if (defaultDefinition) blockDefinition->SetDefaultValue(defaultDefinition->GetText());
|
||||
if (defaultDefinition) blockDefinition.SetDefaultValue(defaultDefinition->GetText());
|
||||
|
||||
auto* typeDefinition = argument->FirstChildElement("Type");
|
||||
if (typeDefinition) typeName = typeDefinition->GetText();
|
||||
@@ -388,23 +224,23 @@ ControlBehaviors::ControlBehaviors() {
|
||||
|
||||
// Now we parse the blocksdef file for the relevant information
|
||||
if (typeName == "String") {
|
||||
blockDefinition->SetMaximumValue(50); // The client has a hardcoded limit of 50 characters in a string field
|
||||
blockDefinition.SetMaximumValue(50); // The client has a hardcoded limit of 50 characters in a string field
|
||||
} else if (typeName == "Float" || typeName == "Integer") {
|
||||
auto* maximumDefinition = argument->FirstChildElement("Maximum");
|
||||
if (maximumDefinition) blockDefinition->SetMaximumValue(std::stof(maximumDefinition->GetText()));
|
||||
if (maximumDefinition) blockDefinition.SetMaximumValue(std::stof(maximumDefinition->GetText()));
|
||||
|
||||
auto* minimumDefinition = argument->FirstChildElement("Minimum");
|
||||
if (minimumDefinition) blockDefinition->SetMinimumValue(std::stof(minimumDefinition->GetText()));
|
||||
if (minimumDefinition) blockDefinition.SetMinimumValue(std::stof(minimumDefinition->GetText()));
|
||||
} else if (typeName == "Enumeration") {
|
||||
auto* values = argument->FirstChildElement("Values");
|
||||
if (values) {
|
||||
auto* value = values->FirstChildElement("Value");
|
||||
while (value) {
|
||||
if (value->GetText() == blockDefinition->GetDefaultValue()) blockDefinition->GetDefaultValue() = std::to_string(blockDefinition->GetMaximumValue());
|
||||
blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() + 1);
|
||||
if (value->GetText() == blockDefinition.GetDefaultValue()) blockDefinition.GetDefaultValue() = std::to_string(blockDefinition.GetMaximumValue());
|
||||
blockDefinition.SetMaximumValue(blockDefinition.GetMaximumValue() + 1);
|
||||
value = value->NextSiblingElement("Value");
|
||||
}
|
||||
blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() - 1); // Maximum value is 0 indexed
|
||||
blockDefinition.SetMaximumValue(blockDefinition.GetMaximumValue() - 1); // Maximum value is 0 indexed
|
||||
} else {
|
||||
values = argument->FirstChildElement("EnumerationSource");
|
||||
if (!values) {
|
||||
@@ -421,8 +257,8 @@ ControlBehaviors::ControlBehaviors() {
|
||||
std::string serviceName = serviceNameNode->GetText();
|
||||
if (serviceName == "GetBehaviorSoundList") {
|
||||
auto res = CDClientDatabase::ExecuteQuery("SELECT MAX(id) as countSounds FROM UGBehaviorSounds;");
|
||||
blockDefinition->SetMaximumValue(res.getIntField("countSounds"));
|
||||
blockDefinition->SetDefaultValue("0");
|
||||
blockDefinition.SetMaximumValue(res.getIntField("countSounds"));
|
||||
blockDefinition.SetDefaultValue("0");
|
||||
} else {
|
||||
LOG("Unsupported Enumeration ServiceType (%s)", serviceName.c_str());
|
||||
continue;
|
||||
@@ -433,19 +269,18 @@ ControlBehaviors::ControlBehaviors() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
blockTypes.insert(std::make_pair(blockName, blockDefinition));
|
||||
block = block->NextSiblingElement();
|
||||
}
|
||||
blockSections = blockSections->NextSiblingElement();
|
||||
}
|
||||
isInitialized = true;
|
||||
LOG_DEBUG("Created all base block classes");
|
||||
for (auto b : blockTypes) {
|
||||
LOG_DEBUG("block name is %s default %s min %f max %f", b.first.c_str(), b.second->GetDefaultValue().c_str(), b.second->GetMinimumValue(), b.second->GetMaximumValue());
|
||||
for (auto& [name, block] : blockTypes) {
|
||||
LOG_DEBUG("block name is %s default %s min %f max %f", name.c_str(), block.GetDefaultValue().c_str(), block.GetMinimumValue(), block.GetMaximumValue());
|
||||
}
|
||||
}
|
||||
|
||||
BlockDefinition* ControlBehaviors::GetBlockInfo(const BlockName& blockName) {
|
||||
std::optional<BlockDefinition> ControlBehaviors::GetBlockInfo(const BlockName& blockName) {
|
||||
auto blockDefinition = blockTypes.find(blockName);
|
||||
return blockDefinition != blockTypes.end() ? blockDefinition->second : nullptr;
|
||||
return blockDefinition != blockTypes.end() ? std::optional(blockDefinition->second) : std::nullopt;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
#define __CONTROLBEHAVIORS__H__
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "BlockDefinition.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
class AMFArrayValue;
|
||||
class BlockDefinition;
|
||||
class Entity;
|
||||
class ModelComponent;
|
||||
class SystemAddress;
|
||||
@@ -17,6 +18,18 @@ class SystemAddress;
|
||||
// Type definition to clarify what is used where
|
||||
typedef std::string BlockName; //! A block name
|
||||
|
||||
struct ControlBehaviorContext {
|
||||
ControlBehaviorContext(AMFArrayValue* args, ModelComponent* modelComponent, Entity* modelOwner) : arguments(args), modelComponent(modelComponent), modelOwner(modelOwner) {};
|
||||
|
||||
operator bool() const {
|
||||
return arguments != nullptr && modelComponent != nullptr && modelOwner != nullptr;
|
||||
}
|
||||
|
||||
AMFArrayValue* arguments;
|
||||
Entity* modelOwner;
|
||||
ModelComponent* modelComponent;
|
||||
};
|
||||
|
||||
class ControlBehaviors: public Singleton<ControlBehaviors> {
|
||||
public:
|
||||
ControlBehaviors();
|
||||
@@ -39,27 +52,13 @@ public:
|
||||
*
|
||||
* @return A pair of the block parameter name to its typing
|
||||
*/
|
||||
BlockDefinition* GetBlockInfo(const BlockName& blockName);
|
||||
std::optional<BlockDefinition> GetBlockInfo(const BlockName& blockName);
|
||||
private:
|
||||
void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr);
|
||||
void SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner);
|
||||
void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent);
|
||||
void ToggleExecutionUpdates();
|
||||
void AddStrip(AMFArrayValue* arguments);
|
||||
void RemoveStrip(AMFArrayValue* arguments);
|
||||
void MergeStrips(AMFArrayValue* arguments);
|
||||
void SplitStrip(AMFArrayValue* arguments);
|
||||
void UpdateStripUI(AMFArrayValue* arguments);
|
||||
void AddAction(AMFArrayValue* arguments);
|
||||
void MigrateActions(AMFArrayValue* arguments);
|
||||
void RearrangeStrip(AMFArrayValue* arguments);
|
||||
void Add(AMFArrayValue* arguments);
|
||||
void RemoveActions(AMFArrayValue* arguments);
|
||||
void Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments);
|
||||
void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments);
|
||||
void RequestUpdatedID(ControlBehaviorContext& context);
|
||||
void SendBehaviorListToClient(const ControlBehaviorContext& context);
|
||||
void SendBehaviorBlocksToClient(ControlBehaviorContext& context);
|
||||
void UpdateAction(AMFArrayValue* arguments);
|
||||
void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments);
|
||||
std::map<BlockName, BlockDefinition*> blockTypes{};
|
||||
std::map<BlockName, BlockDefinition> blockTypes{};
|
||||
|
||||
// If false, property behaviors will not be able to be edited.
|
||||
bool isInitialized = false;
|
||||
|
||||
131
dGame/dPropertyBehaviors/PropertyBehavior.cpp
Normal file
131
dGame/dPropertyBehaviors/PropertyBehavior.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "PropertyBehavior.h"
|
||||
|
||||
#include "Amf3.h"
|
||||
#include "BehaviorStates.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
|
||||
PropertyBehavior::PropertyBehavior() {
|
||||
m_LastEditedState = BehaviorState::HOME_STATE;
|
||||
}
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(AddStripMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(AddActionMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(RearrangeStripMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(UpdateActionMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(UpdateStripUiMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(RemoveStripMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(RemoveActionsMessage& msg) {
|
||||
m_States[msg.GetActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(SplitStripMessage& msg) {
|
||||
m_States[msg.GetSourceActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_States[msg.GetDestinationActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetDestinationActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(MigrateActionsMessage& msg) {
|
||||
m_States[msg.GetSourceActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_States[msg.GetDestinationActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetDestinationActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(MergeStripsMessage& msg) {
|
||||
m_States[msg.GetSourceActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_States[msg.GetDestinationActionContext().GetStateId()].HandleMsg(msg);
|
||||
m_LastEditedState = msg.GetDestinationActionContext().GetStateId();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(RenameMessage& msg) {
|
||||
m_Name = msg.GetName();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(AddMessage& msg) {
|
||||
// TODO Parse the corresponding behavior xml file.
|
||||
m_BehaviorId = msg.GetBehaviorId();
|
||||
isLoot = m_BehaviorId != 7965;
|
||||
};
|
||||
|
||||
void PropertyBehavior::SetBehaviorId(int32_t behaviorId) {
|
||||
m_BehaviorId = behaviorId;
|
||||
}
|
||||
|
||||
void PropertyBehavior::SendBehaviorListToClient(AMFArrayValue& args) const {
|
||||
args.Insert("id", std::to_string(m_BehaviorId));
|
||||
args.Insert("name", m_Name);
|
||||
args.Insert("isLocked", isLocked);
|
||||
args.Insert("isLoot", isLoot);
|
||||
}
|
||||
|
||||
void PropertyBehavior::VerifyLastEditedState() {
|
||||
if (!m_States[m_LastEditedState].IsEmpty()) return;
|
||||
|
||||
for (const auto& [stateId, state] : m_States) {
|
||||
if (state.IsEmpty()) continue;
|
||||
|
||||
LOG_DEBUG("Updating last edited state to %i because %i is empty.", stateId, m_LastEditedState);
|
||||
m_LastEditedState = stateId;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("No states found, sending default state");
|
||||
|
||||
m_LastEditedState = BehaviorState::HOME_STATE;
|
||||
}
|
||||
|
||||
void PropertyBehavior::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
|
||||
auto* stateArray = args.InsertArray("states");
|
||||
|
||||
auto lastState = BehaviorState::HOME_STATE;
|
||||
for (auto& [stateId, state] : m_States) {
|
||||
if (state.IsEmpty()) continue;
|
||||
|
||||
LOG_DEBUG("Serializing state %i", stateId);
|
||||
auto* stateArgs = stateArray->PushArray();
|
||||
stateArgs->Insert("id", static_cast<double>(stateId));
|
||||
state.SendBehaviorBlocksToClient(*stateArgs);
|
||||
}
|
||||
|
||||
auto* executionState = args.InsertArray("executionState");
|
||||
executionState->Insert("stateID", static_cast<double>(m_LastEditedState));
|
||||
executionState->InsertArray("strips");
|
||||
|
||||
// TODO Serialize the execution state of the behavior
|
||||
}
|
||||
49
dGame/dPropertyBehaviors/PropertyBehavior.h
Normal file
49
dGame/dPropertyBehaviors/PropertyBehavior.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef __PROPERTYBEHAVIOR__H__
|
||||
#define __PROPERTYBEHAVIOR__H__
|
||||
|
||||
#include "State.h"
|
||||
|
||||
enum class BehaviorState : uint32_t;
|
||||
|
||||
class AMFArrayValue;
|
||||
|
||||
/**
|
||||
* Represents the Entity of a Property Behavior and holds data associated with the behavior
|
||||
*/
|
||||
class PropertyBehavior {
|
||||
public:
|
||||
PropertyBehavior();
|
||||
template<typename Msg>
|
||||
void HandleMsg(Msg& msg);
|
||||
|
||||
// If the last edited state has no strips, this method will set the last edited state to the first state that has strips.
|
||||
void VerifyLastEditedState();
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
|
||||
int32_t GetBehaviorId() const { return m_BehaviorId; }
|
||||
void SetBehaviorId(int32_t id);
|
||||
private:
|
||||
|
||||
// The states this behavior has.
|
||||
std::map<BehaviorState, State> m_States;
|
||||
|
||||
// The name of this behavior.
|
||||
std::string m_Name = "New Behavior";
|
||||
|
||||
// Whether this behavior is locked and cannot be edited.
|
||||
bool isLocked = false;
|
||||
|
||||
// Whether this behavior is custom or pre-fab.
|
||||
bool isLoot = false;
|
||||
|
||||
// The last state that was edited. This is used so when the client re-opens the behavior editor, it will open to the last edited state.
|
||||
// If the last edited state has no strips, it will open to the first state that has strips.
|
||||
BehaviorState m_LastEditedState;
|
||||
|
||||
// The behavior id for this behavior. This is expected to be fully unique, however an id of -1 means this behavior was just created
|
||||
// and needs to be assigned an id.
|
||||
int32_t m_BehaviorId = -1;
|
||||
};
|
||||
|
||||
#endif //!__PROPERTYBEHAVIOR__H__
|
||||
137
dGame/dPropertyBehaviors/State.cpp
Normal file
137
dGame/dPropertyBehaviors/State.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "State.h"
|
||||
|
||||
#include "Amf3.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(AddStripMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
m_Strips.resize(msg.GetActionContext().GetStripId() + 1);
|
||||
}
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(AddActionMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(UpdateStripUiMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(RemoveActionsMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(RearrangeStripMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(UpdateActionMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(RemoveStripMessage& msg) {
|
||||
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(SplitStripMessage& msg) {
|
||||
if (msg.GetTransferredActions().empty()) {
|
||||
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
|
||||
} else {
|
||||
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
|
||||
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(MergeStripsMessage& msg) {
|
||||
if (msg.GetMigratedActions().empty()) {
|
||||
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
|
||||
} else {
|
||||
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
|
||||
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void State::HandleMsg(MigrateActionsMessage& msg) {
|
||||
if (msg.GetMigratedActions().empty()) {
|
||||
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
|
||||
} else {
|
||||
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
|
||||
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
|
||||
}
|
||||
|
||||
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
|
||||
}
|
||||
};
|
||||
|
||||
bool State::IsEmpty() const {
|
||||
for (auto& strip : m_Strips) {
|
||||
if (!strip.IsEmpty()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void State::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
|
||||
auto* strips = args.InsertArray("strips");
|
||||
for (int32_t stripId = 0; stripId < m_Strips.size(); stripId++) {
|
||||
auto& strip = m_Strips.at(stripId);
|
||||
if (strip.IsEmpty()) continue;
|
||||
|
||||
auto* stripArgs = strips->PushArray();
|
||||
stripArgs->Insert("id", static_cast<double>(stripId));
|
||||
|
||||
strip.SendBehaviorBlocksToClient(*stripArgs);
|
||||
}
|
||||
};
|
||||
19
dGame/dPropertyBehaviors/State.h
Normal file
19
dGame/dPropertyBehaviors/State.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __STATE__H__
|
||||
#define __STATE__H__
|
||||
|
||||
#include "Strip.h"
|
||||
|
||||
class AMFArrayValue;
|
||||
|
||||
class State {
|
||||
public:
|
||||
template<typename Msg>
|
||||
void HandleMsg(Msg& msg);
|
||||
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
bool IsEmpty() const;
|
||||
private:
|
||||
std::vector<Strip> m_Strips;
|
||||
};
|
||||
|
||||
#endif //!__STATE__H__
|
||||
87
dGame/dPropertyBehaviors/Strip.cpp
Normal file
87
dGame/dPropertyBehaviors/Strip.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "Strip.h"
|
||||
|
||||
#include "Amf3.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(AddStripMessage& msg) {
|
||||
m_Actions = msg.GetActionsToAdd();
|
||||
m_Position = msg.GetPosition();
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(AddActionMessage& msg) {
|
||||
if (msg.GetActionIndex() == -1) return;
|
||||
|
||||
m_Actions.insert(m_Actions.begin() + msg.GetActionIndex(), msg.GetAction());
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(UpdateStripUiMessage& msg) {
|
||||
m_Position = msg.GetPosition();
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(RemoveStripMessage& msg) {
|
||||
m_Actions.clear();
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(RemoveActionsMessage& msg) {
|
||||
if (msg.GetActionIndex() >= m_Actions.size()) return;
|
||||
m_Actions.erase(m_Actions.begin() + msg.GetActionIndex(), m_Actions.end());
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(UpdateActionMessage& msg) {
|
||||
if (msg.GetActionIndex() >= m_Actions.size()) return;
|
||||
m_Actions.at(msg.GetActionIndex()) = msg.GetAction();
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(RearrangeStripMessage& msg) {
|
||||
if (msg.GetDstActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() <= msg.GetDstActionIndex()) return;
|
||||
std::rotate(m_Actions.begin() + msg.GetDstActionIndex(), m_Actions.begin() + msg.GetSrcActionIndex(), m_Actions.end());
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(SplitStripMessage& msg) {
|
||||
if (msg.GetTransferredActions().empty() && !m_Actions.empty()) {
|
||||
auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex();
|
||||
msg.SetTransferredActions(startToMove, m_Actions.end());
|
||||
m_Actions.erase(startToMove, m_Actions.end());
|
||||
} else {
|
||||
m_Actions = msg.GetTransferredActions();
|
||||
m_Position = msg.GetPosition();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(MergeStripsMessage& msg) {
|
||||
if (msg.GetMigratedActions().empty() && !m_Actions.empty()) {
|
||||
msg.SetMigratedActions(m_Actions.begin(), m_Actions.end());
|
||||
m_Actions.erase(m_Actions.begin(), m_Actions.end());
|
||||
} else {
|
||||
m_Actions.insert(m_Actions.begin() + msg.GetDstActionIndex(), msg.GetMigratedActions().begin(), msg.GetMigratedActions().end());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void Strip::HandleMsg(MigrateActionsMessage& msg) {
|
||||
if (msg.GetMigratedActions().empty() && !m_Actions.empty()) {
|
||||
auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex();
|
||||
msg.SetMigratedActions(startToMove, m_Actions.end());
|
||||
m_Actions.erase(startToMove, m_Actions.end());
|
||||
} else {
|
||||
m_Actions.insert(m_Actions.begin() + msg.GetDstActionIndex(), msg.GetMigratedActions().begin(), msg.GetMigratedActions().end());
|
||||
}
|
||||
};
|
||||
|
||||
void Strip::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
|
||||
m_Position.SendBehaviorBlocksToClient(args);
|
||||
|
||||
auto* actions = args.InsertArray("actions");
|
||||
for (auto& action : m_Actions) {
|
||||
action.SendBehaviorBlocksToClient(*actions);
|
||||
}
|
||||
};
|
||||
23
dGame/dPropertyBehaviors/Strip.h
Normal file
23
dGame/dPropertyBehaviors/Strip.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __STRIP__H__
|
||||
#define __STRIP__H__
|
||||
|
||||
#include "Action.h"
|
||||
#include "StripUiPosition.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class AMFArrayValue;
|
||||
|
||||
class Strip {
|
||||
public:
|
||||
template<typename Msg>
|
||||
void HandleMsg(Msg& msg);
|
||||
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
bool IsEmpty() const { return m_Actions.empty(); }
|
||||
private:
|
||||
std::vector<Action> m_Actions;
|
||||
StripUiPosition m_Position;
|
||||
};
|
||||
|
||||
#endif //!__STRIP__H__
|
||||
@@ -5,4 +5,10 @@ set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp"
|
||||
"Mail.cpp"
|
||||
"Preconditions.cpp"
|
||||
"SlashCommandHandler.cpp"
|
||||
"VanityUtilities.cpp" PARENT_SCOPE)
|
||||
"VanityUtilities.cpp")
|
||||
|
||||
add_library(dUtilities STATIC ${DGAME_DUTILITIES_SOURCES})
|
||||
target_precompile_headers(dUtilities REUSE_FROM dGameBase)
|
||||
target_link_libraries(dUtilities
|
||||
PUBLIC dDatabase dPhysics
|
||||
INTERFACE dZoneManager)
|
||||
|
||||
@@ -294,21 +294,20 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
auto* partyPhrases = npcs->FirstChildElement("partyphrases");
|
||||
|
||||
if (partyPhrases == nullptr) {
|
||||
LOG("Failed to parse party phrases");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
m_PartyPhrases.push_back(text);
|
||||
}
|
||||
|
||||
for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) {
|
||||
|
||||
Reference in New Issue
Block a user