/
Writing a Metadata Replicator module
Writing a Metadata Replicator module
Atoms Behaviour Module
// ===========================================================================
// Copyright (c) 2015 Toolchefs Ltd. All rights reserved.
//
// Use of this software is subject to the terms of the Toolchefs license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
// ===========================================================================
#pragma once
#include <Atoms/BehaviourModule.h>
class UWorld;
class AActor;
class UAgentCollisionComponent;
class CustomMetadataReplicatorModule : public Atoms::BehaviourModule
{
public:
CustomMetadataReplicatorModule ();
virtual ~CustomMetadataReplicatorModule ();
void initSimulation(Atoms::AgentGroup* agentGroup) override;
void agentsCreated(const std::vector<Atoms::Agent *>& agents, Atoms::AgentGroup* agentGroup = nullptr) override;
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) override;
static Atoms::BehaviourModule* creator(const std::string& parameter);
void setWorld(UWorld* world) { m_world = world; }
void setMetadataReplicatorComponent(class UCustomMetadataReplicatorComponent* component) { m_replicatorComponent = component; }
UCustomMetadataReplicatorComponent* GetReplicatorComponent();
void AdvanceCounter(size_t TypeId, size_t& dataCounter) const;
size_t GetDataOffset(size_t TypeId) const;
private:
UWorld* m_world;
class UCustomMetadataReplicatorComponent* m_replicatorComponent;
double elapsedTime;
bool serverStarted;
};
#include "CustomMetadataReplicatorModule.h"
#include "AtomsConversions.h"
#include "Actors/AtomsAgentGroup.h"
#include "CustomMetadataReplicatorComponent.h"
#include "Components/AgentCollisionComponent.h"
#include "GameFramework/GameStateBase.h"
#include <AtomsCore/Metadata/Vector2Metadata.h>
#include <AtomsCore/Metadata/Vector2fMetadata.h>
#include <AtomsCore/Metadata/Vector3Metadata.h>
#include <AtomsCore/Metadata/Vector3fMetadata.h>
#include <AtomsCore/Metadata/Vector4Metadata.h>
#include <AtomsCore/Metadata/Vector4fMetadata.h>
#include <AtomsCore/Metadata/Vector3ArrayMetadata.h>
#include <AtomsCore/Metadata/Vector2fArrayMetadata.h>
#include <AtomsCore/Metadata/Vector3fArrayMetadata.h>
#include <AtomsCore/Metadata/Vector4fArrayMetadata.h>
#include <AtomsCore/Metadata/Vector4ArrayMetadata.h>
#include <AtomsCore/Metadata/MatrixMetadata.h>
#include <AtomsCore/Metadata/MatrixfMetadata.h>
#include <AtomsCore/Metadata/MatrixArrayMetadata.h>
#include <AtomsCore/Metadata/MatrixfArrayMetadata.h>
#include <AtomsCore/Metadata/QuaternionMetadata.h>
#include <AtomsCore/Metadata/QuaternionfMetadata.h>
#include <AtomsCore/Metadata/QuaternionArrayMetadata.h>
#include <AtomsCore/Metadata/QuaternionfArrayMetadata.h>
#include <AtomsCore/Metadata/EulerMetadata.h>
#include <AtomsCore/Metadata/EulerfMetadata.h>
#include <AtomsCore/Metadata/EulerArrayMetadata.h>
#include <AtomsCore/Metadata/EulerfArrayMetadata.h>
#include <AtomsCore/Metadata/IntMetadata.h>
#include <AtomsCore/Metadata/IntArrayMetadata.h>
#include <AtomsCore/Metadata/DoubleMetadata.h>
#include <AtomsCore/Metadata/DoubleArrayMetadata.h>
#include <AtomsCore/Metadata/FloatMetadata.h>
#include <AtomsCore/Metadata/FloatArrayMetadata.h>
#include <AtomsCore/Metadata/MapMetadata.h>
#include <AtomsCore/Metadata/BoolMetadata.h>
#include <AtomsCore/Metadata/BoolArrayMetadata.h>
#include <AtomsCore/Metadata/StringMetadata.h>
#include <AtomsCore/Metadata/StringArrayMetadata.h>
#include <AtomsCore/Metadata/Box3Metadata.h>
#include <AtomsCore/Metadata/ArrayMetadata.h>
#include <AtomsUtils/TaskScheduler.h>
#include <Atoms/Agent.h>
#include <Atoms/AgentGroup.h>
#include <Atoms/GlobalNames.h>
#include <AtomsUtils/Memory.h>
CustomMetadataReplicatorModule::CustomMetadataReplicatorModule() : Atoms::BehaviourModule(),
m_world(nullptr),
m_replicatorComponent(nullptr),
serverStarted(false)
{
AtomsCore::StringMetadata metadataNames;
addAttribute("MetadataName", &metadataNames);
AtomsCore::BoolMetadata enable(false);
addAttribute("EnableReplication", &enable, true);
}
CustomMetadataReplicatorModule::~CustomMetadataReplicatorModule()
{
}
void CustomMetadataReplicatorModule::initSimulation(Atoms::AgentGroup* agentGroup)
{
elapsedTime = 0.0;
}
void CustomMetadataReplicatorModule::agentsCreated(const std::vector<Atoms::Agent *>& agents, Atoms::AgentGroup* agentGroup)
{
if (!m_replicatorComponent)
return;
for (auto* agent : agents)
{
AtomsCore::BoolMetadata hasAutority(m_replicatorComponent->GetOwnerRole() == ROLE_Authority);
agent->metadata().addEntry("hasAutority", &hasAutority);
}
}
size_t CustomMetadataReplicatorModule::GetDataOffset(size_t TypeId) const
{
switch (TypeId)
{
case kMetadataBoolTypeId:
case kMetadataStringTypeId:
case kMetadataIntTypeId:
case kMetadataDoubleTypeId:
case kMetadataFloatTypeId:
{
return 1;
break;
}
case kMetadataVector3fTypeId:
case kMetadataVector3TypeId:
case kMetadataEulerfTypeId:
case kMetadataEulerTypeId:
{
return 3;
break;
}
case kMetadataVector4fTypeId:
case kMetadataVector4TypeId:
case kMetadataQuaternionfTypeId:
case kMetadataQuaternionTypeId:
{
return 4;
break;
}
case kMetadataMatrixfTypeId:
{
return 16;
break;
}
default:
break;
}
return 0;
}
void CustomMetadataReplicatorModule::AdvanceCounter(size_t TypeId, size_t& dataCounter) const
{
dataCounter += GetDataOffset(TypeId);
}
void CustomMetadataReplicatorModule::initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
if (!m_replicatorComponent)
return;
auto metadataName = attributes().getTypedEntry<AtomsCore::StringMetadata>("MetadataName");
if (!metadataName)
return;
auto metadataInterpolation = attributes().getTypedEntry<AtomsCore::BoolMetadata>("MetadataInterpolation");
if (!metadataInterpolation)
return;
auto enable = attributes().getTypedEntry<AtomsCore::BoolMetadata>("EnableReplication")->value();
auto enableOverride = attributes().getTypedEntry<AtomsCore::MapMetadata>("EnableReplication_override");
const std::string enableMetaName = name() + "@EnableReplication";
bool interpolation = metadataInterpolation->value();
double currentSeconds = agentGroup->simulationTime().seconds();
if (m_replicatorComponent->GetOwnerRole() == ROLE_Authority)
{
if (!m_replicatorComponent->EnableReplication)
return;
if (m_replicatorComponent->UseRpc)
{
if (currentSeconds - elapsedTime < m_replicatorComponent->UpdateTime)
{
return;
}
}
elapsedTime = agentGroup->simulationTime().seconds();
FMetadataReplicatorState State;
State.SimulationTime = agentGroup->simulationTime().time();
bool typeIdFound = false;
for (size_t i = 0; i < agents.size(); ++i)
{
auto* agent = agents[i];
if (!agent)
continue;
auto CurrentData = agent->metadata().getEntry(metadataName->get());
if (!CurrentData)
continue;
if (!getAttributePerAgent(enable, enableOverride.get(), agent->groupIdStr()->value(), agent->metadata(), enableMetaName))
continue;
if (!typeIdFound)
State.TypeId = CurrentData->typeId();
if (State.TypeId != CurrentData->typeId())
continue;
if (!agent->groupId())
continue;
State.Ids.Add(agent->groupId()->value());
switch (CurrentData->typeId())
{
case kMetadataBoolTypeId:
{
State.ValueMetadata.Add(std::static_pointer_cast<AtomsCore::BoolMetadata>(CurrentData)->get() ? 1.0 : 0.0);
break;
}
case kMetadataIntTypeId:
{
State.ValueMetadata.Add(std::static_pointer_cast<AtomsCore::IntMetadata>(CurrentData)->get());
break;
}
case kMetadataFloatTypeId:
{
State.ValueMetadata.Add(std::static_pointer_cast<AtomsCore::FloatMetadata>(CurrentData)->get());
break;
}
case kMetadataDoubleTypeId:
{
State.ValueMetadata.Add(std::static_pointer_cast<AtomsCore::DoubleMetadata>(CurrentData)->get());
break;
}
case kMetadataStringTypeId:
{
State.StringMetadata.Add(std::static_pointer_cast<AtomsCore::StringMetadata>(CurrentData)->get().c_str());
break;
}
case kMetadataVector2fTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector2fMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
break;
}
case kMetadataVector2TypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector2Metadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
break;
}
case kMetadataVector3fTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector3fMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
break;
}
case kMetadataVector3TypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector3Metadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
break;
}
case kMetadataVector4fTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector4fMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
State.ValueMetadata.Add(value.w);
break;
}
case kMetadataVector4TypeId:
{
auto value = std::static_pointer_cast<AtomsCore::Vector4Metadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
State.ValueMetadata.Add(value.w);
break;
}
case kMetadataMatrixfTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::MatrixfMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value[0][0]);
State.ValueMetadata.Add(value[0][1]);
State.ValueMetadata.Add(value[0][2]);
State.ValueMetadata.Add(value[0][3]);
State.ValueMetadata.Add(value[1][0]);
State.ValueMetadata.Add(value[1][1]);
State.ValueMetadata.Add(value[1][2]);
State.ValueMetadata.Add(value[1][3]);
State.ValueMetadata.Add(value[2][0]);
State.ValueMetadata.Add(value[2][1]);
State.ValueMetadata.Add(value[2][2]);
State.ValueMetadata.Add(value[2][3]);
State.ValueMetadata.Add(value[3][0]);
State.ValueMetadata.Add(value[3][1]);
State.ValueMetadata.Add(value[3][2]);
State.ValueMetadata.Add(value[3][3]);
break;
}
case kMetadataMatrixTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::MatrixMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value[0][0]);
State.ValueMetadata.Add(value[0][1]);
State.ValueMetadata.Add(value[0][2]);
State.ValueMetadata.Add(value[0][3]);
State.ValueMetadata.Add(value[1][0]);
State.ValueMetadata.Add(value[1][1]);
State.ValueMetadata.Add(value[1][2]);
State.ValueMetadata.Add(value[1][3]);
State.ValueMetadata.Add(value[2][0]);
State.ValueMetadata.Add(value[2][1]);
State.ValueMetadata.Add(value[2][2]);
State.ValueMetadata.Add(value[2][3]);
State.ValueMetadata.Add(value[3][0]);
State.ValueMetadata.Add(value[3][1]);
State.ValueMetadata.Add(value[3][2]);
State.ValueMetadata.Add(value[3][3]);
break;
}
case kMetadataEulerfTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::EulerfMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
break;
}
case kMetadataEulerTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::EulerMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.x);
State.ValueMetadata.Add(value.y);
State.ValueMetadata.Add(value.z);
break;
}
case kMetadataQuaternionfTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::QuaternionfMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.v.x);
State.ValueMetadata.Add(value.v.y);
State.ValueMetadata.Add(value.v.z);
State.ValueMetadata.Add(value.r);
break;
}
case kMetadataQuaternionTypeId:
{
auto value = std::static_pointer_cast<AtomsCore::QuaternionMetadata>(CurrentData)->get();
State.ValueMetadata.Add(value.v.x);
State.ValueMetadata.Add(value.v.y);
State.ValueMetadata.Add(value.v.z);
State.ValueMetadata.Add(value.r);
break;
}
default:
break;
}
}
if (m_replicatorComponent->EnableReplication && m_replicatorComponent->UseRpc)
{
if (m_replicatorComponent->UseReliableRpc)
m_replicatorComponent->UpdatedMetadata(State);
else
m_replicatorComponent->UnreliableUpdatedMetadata(State);
}
else
{
m_replicatorComponent->ReplicatedMetadata = State;
}
}
else if (m_replicatorComponent->ClientReplicatedData.Num() > 1)
{
auto Actor = m_replicatorComponent->GetOwner();
if (!Actor)
return;
UAgentCollisionComponent* CollisionComponent = nullptr;
#if ENGINE_MINOR_VERSION < 24
auto ExistingRagdollComponents = Actor->GetComponentsByClass(UAgentCollisionComponent::StaticClass());
#else
TArray<UActorComponent*> ExistingRagdollComponents;
Actor->GetComponents(UAgentCollisionComponent::StaticClass(), ExistingRagdollComponents);
#endif
for (auto It : ExistingRagdollComponents)
{
auto RagdollComp = Cast<UAgentCollisionComponent>(It);
if (RagdollComp)
{
CollisionComponent = RagdollComp;
break;
}
}
// if there is no data just exit
if (m_replicatorComponent->ClientReplicatedData.Num() == 0)
return;
float CurrentSimTime = agentGroup->simulationTime().time();
auto* Tail = m_replicatorComponent->ClientReplicatedData.GetTail();
auto& LastData = Tail->GetValue();
while (Tail->GetPrevNode())
{
auto* NextNode = Tail->GetPrevNode();
if (!NextNode)
break;
auto CurrTime = Tail->GetValue().SimulationTime;
auto NextTime = NextNode->GetValue().SimulationTime;
if (CurrentSimTime > NextTime)
{
m_replicatorComponent->ClientReplicatedData.RemoveNode(Tail);
}
Tail = NextNode;
}
Tail = m_replicatorComponent->ClientReplicatedData.GetTail();
auto* Head = Tail->GetPrevNode();
if (!Tail)
return;
float TimeTail = Tail->GetValue().SimulationTime;
float TimeHead = Head ? Head->GetValue().SimulationTime : CurrentSimTime;
float Alpha = (TimeHead > TimeTail) ? (CurrentSimTime - TimeTail) / (TimeHead - TimeTail) : 0.0;
auto& TailState = Tail->GetValue();
auto& ids = TailState.Ids;
if (ids.Num() == 0)
return;
size_t DataStride = GetDataOffset(TailState.TypeId);
size_t dataCounter = 0;
for (size_t i = 0; i < ids.Num(); ++i)
{
auto agentId = ids[i];
auto* agent = agentGroup->agent(agentId);
if (!agent)
{
dataCounter += DataStride;
continue;
}
auto CurrentData = agent->metadata().getEntry(metadataName->get());
if (!CurrentData)
{
dataCounter += DataStride;
continue;
}
// the metadata type id doesn't metch so continue;
if (CurrentData->typeId() != TailState.TypeId)
{
dataCounter += DataStride;
continue;
}
int32 HeadOffset = INDEX_NONE;
FMetadataReplicatorState* HeadState = nullptr;
if (interpolation && Head)
{
HeadState = &Head->GetValue();
HeadOffset = HeadState->Ids.Find(agentId);
if (HeadOffset == INDEX_NONE)
{
continue;
}
HeadOffset *= DataStride;
}
if (TailState.ValueMetadata.Num() < (dataCounter + DataStride))
{
break;
}
switch (TailState.TypeId)
{
case kMetadataBoolTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::BoolMetadata>(CurrentData);
agentData->set(TailState.ValueMetadata[dataCounter++] > 0.1);
break;
}
case kMetadataStringTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::StringMetadata>(CurrentData);
agentData->get() = TCHAR_TO_UTF8(*TailState.StringMetadata[dataCounter++]);
break;
}
case kMetadataIntTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::IntMetadata>(CurrentData);
if (!HeadState)
{
agentData->get() = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get() = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
dataCounter += 1;
}
break;
}
case kMetadataDoubleTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::DoubleMetadata>(CurrentData);
if (!HeadState)
{
agentData->get() = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get() = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
dataCounter += 1;
}
break;
}
case kMetadataFloatTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::FloatMetadata>(CurrentData);
if (!HeadState)
{
agentData->get() = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get() = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
dataCounter += 1;
}
break;
}
case kMetadataVector3fTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::Vector3fMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
dataCounter += 3;
}
if (CollisionComponent && metadataName->get() == Atoms::GlobalNameKeys::ATOMS_AGENT_POSITION_KEY)
{
auto InstanceBody = CollisionComponent->InstanceBodies.Find(agentId);
if (InstanceBody && *InstanceBody)
{
auto CurrentTransform = (*InstanceBody)->GetUnrealWorldTransform();
CurrentTransform.SetLocation(AtomsConverter::FromVector3(agentData->get()));
(*InstanceBody)->SetBodyTransform(CurrentTransform, ETeleportType::TeleportPhysics, false);
}
}
break;
}
case kMetadataVector3TypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::Vector3Metadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
dataCounter += 3;
}
if (CollisionComponent && metadataName->get() == Atoms::GlobalNameKeys::ATOMS_AGENT_POSITION_KEY)
{
auto InstanceBody = CollisionComponent->InstanceBodies.Find(agentId);
if (InstanceBody && *InstanceBody)
{
auto CurrentTransform = (*InstanceBody)->GetUnrealWorldTransform();
CurrentTransform.SetLocation(AtomsConverter::FromVector3(agentData->get()));
(*InstanceBody)->SetBodyTransform(CurrentTransform, ETeleportType::TeleportPhysics, false);
}
}
break;
}
case kMetadataEulerfTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::EulerfMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
dataCounter += 3;
}
break;
}
case kMetadataEulerTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::EulerMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
dataCounter += 3;
}
break;
}
case kMetadataVector4fTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::Vector4fMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
agentData->get().w = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
agentData->get().w = TailState.ValueMetadata[dataCounter + 3] + Alpha * (HeadState->ValueMetadata[HeadOffset + 3] - TailState.ValueMetadata[dataCounter + 3]);
dataCounter += 4;
}
break;
}
case kMetadataVector4TypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::Vector4Metadata>(CurrentData);
if (!HeadState)
{
agentData->get().x = TailState.ValueMetadata[dataCounter++];
agentData->get().y = TailState.ValueMetadata[dataCounter++];
agentData->get().z = TailState.ValueMetadata[dataCounter++];
agentData->get().w = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
agentData->get().w = TailState.ValueMetadata[dataCounter + 3] + Alpha * (HeadState->ValueMetadata[HeadOffset + 3] - TailState.ValueMetadata[dataCounter + 3]);
dataCounter += 4;
}
break;
}
case kMetadataQuaternionfTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::QuaternionfMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().v.x = TailState.ValueMetadata[dataCounter++];
agentData->get().v.y = TailState.ValueMetadata[dataCounter++];
agentData->get().v.z = TailState.ValueMetadata[dataCounter++];
agentData->get().r = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().v.x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().v.y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().v.z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
agentData->get().r = TailState.ValueMetadata[dataCounter + 3] + Alpha * (HeadState->ValueMetadata[HeadOffset + 3] - TailState.ValueMetadata[dataCounter + 3]);
dataCounter += 4;
}
break;
}
case kMetadataQuaternionTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::QuaternionMetadata>(CurrentData);
if (!HeadState)
{
agentData->get().v.x = TailState.ValueMetadata[dataCounter++];
agentData->get().v.y = TailState.ValueMetadata[dataCounter++];
agentData->get().v.z = TailState.ValueMetadata[dataCounter++];
agentData->get().r = TailState.ValueMetadata[dataCounter++];
}
else
{
agentData->get().v.x = TailState.ValueMetadata[dataCounter] + Alpha * (HeadState->ValueMetadata[HeadOffset] - TailState.ValueMetadata[dataCounter]);
agentData->get().v.y = TailState.ValueMetadata[dataCounter + 1] + Alpha * (HeadState->ValueMetadata[HeadOffset + 1] - TailState.ValueMetadata[dataCounter + 1]);
agentData->get().v.z = TailState.ValueMetadata[dataCounter + 2] + Alpha * (HeadState->ValueMetadata[HeadOffset + 2] - TailState.ValueMetadata[dataCounter + 2]);
agentData->get().r = TailState.ValueMetadata[dataCounter + 3] + Alpha * (HeadState->ValueMetadata[HeadOffset + 3] - TailState.ValueMetadata[dataCounter + 3]);
dataCounter += 4;
}
break;
}
case kMetadataMatrixfTypeId:
{
auto agentData = std::static_pointer_cast<AtomsCore::MatrixfMetadata>(CurrentData);
if (!HeadState)
{
for (int32 xi = 0; xi < 4; ++xi)
for (int32 yi = 0; yi < 4; ++yi)
agentData->get()[xi][yi] = TailState.ValueMetadata[dataCounter++];
}
else
{
for (int32 xi = 0; xi < 4; ++xi)
for (int32 yi = 0; yi < 4; ++yi)
agentData->get()[xi][yi] = TailState.ValueMetadata[dataCounter + xi * 4 + yi] + Alpha * (HeadState->ValueMetadata[HeadOffset + xi * 4 + yi] - TailState.ValueMetadata[dataCounter + xi * 4 + yi]);
dataCounter += 15;
}
break;
}
default:
break;
}
}
if (!serverStarted)
{
auto* UniqueHead = m_replicatorComponent->ClientReplicatedData.GetHead();
if (UniqueHead)
{
float ServerTime = UniqueHead->GetValue().SimulationTime;
auto AgentGroupActor = Cast<AAtomsAgentGroup>(Actor);
if (AgentGroupActor)
AgentGroupActor->CurrentFrame = ServerTime;
}
serverStarted = true;
}
}
}
Atoms::BehaviourModule* CustomMetadataReplicatorModule::creator(const std::string& parameter)
{
return new MetadataReplicatorModule();
}
UCustomMetadataReplicatorComponent* CustomMetadataReplicatorModule::GetReplicatorComponent()
{
return m_replicatorComponent;
}
Unreal Component
#pragma once
#include "CoreMinimal.h"
#include "Components/AtomsBehaviourComponent.h"
#include <Atoms/AgentGroup.h>
#include "CustomMetadataReplicatorComponent.generated.h"
USTRUCT()
struct FMetadataReplicatorState
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 TypeId;
UPROPERTY()
float SimulationTime;
UPROPERTY()
TArray<int32> Ids;
UPROPERTY()
TArray<float> ValueMetadata;
UPROPERTY()
TArray<FString> StringMetadata;
};
UCLASS(ClassGroup = (AtomsBehaviours), meta = (DisplayName = "Metadata Replicator", BlueprintSpawnableComponent))
class ATOMSUNREAL_API UCustomMetadataReplicatorComponent : public UAtomsBehaviourComponent
{
GENERATED_BODY()
public:
UCustomMetadataReplicatorComponent();
~UCustomMetadataReplicatorComponent();
virtual void OnBehaviourModuleCreated(AtomsPtr<Atoms::BehaviourModule>& module) override;
virtual void OnRegister() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
virtual void GetAtomsAttributes(AtomsPtr<AtomsCore::MapMetadata>& attributes) override;
public:
/* Enable the replication of the metadata, This can be override per agent using the enableReplicationOverride property or setting on the agent a bool metadata using as name thiscomponentname + "@enableReplication" */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
bool EnableReplication;
/* Enable the tick of the tree */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, bool> EnableReplicationOverride;
/* Metadata name to replicate */
UPROPERTY(replicated, EditAnywhere, Category = "Behaviour")
FString MetadataName;
/* Use interpolation. The component on the client store a list of value sent by the server at different simulation time.
Interpolate the value between different times.*/
UPROPERTY(replicated, EditAnywhere, Category = "Behaviour")
bool Interpolate;
/* Enable Rpc call to UpdatedMetadata instead use the ReplicatedMetadata property replication.
Please use this only if you need really fast updates and if you have enough bandwidth.*/
UPROPERTY(EditAnywhere, Category = "Behaviour")
bool UseRpc;
/* Use reliable rpc call */
UPROPERTY(EditAnywhere, Category = "Behaviour", meta = (EditCondition = UseRpc))
bool UseReliableRpc;
/* Send the rpc call every UpdateTime in seconds */
UPROPERTY(EditAnywhere, Category = "Behaviour", meta=(EditCondition = UseRpc))
float UpdateTime;
UPROPERTY(ReplicatedUsing = OnRep_ReplicatedMetadata)
FMetadataReplicatorState ReplicatedMetadata;
TDoubleLinkedList<FMetadataReplicatorState> ClientReplicatedData;
UFUNCTION()
void OnRep_ReplicatedMetadata();
UFUNCTION(NetMulticast, Reliable)
void UpdatedMetadata(const FMetadataReplicatorState& Data);
UFUNCTION(NetMulticast, Unreliable)
void UnreliableUpdatedMetadata(const FMetadataReplicatorState& Data);
UFUNCTION(BlueprintCallable, Category = "MetadatareplicatorBehaviourComponent", meta = (CallInEditor = "true"))
void SetEnableReplication(const bool Value, const int32 AgentId = -1);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "MetadatareplicatorBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveEnableReplicationOverride(const int32 AgentId);
/** Set the metadata name to replicate */
UFUNCTION(BlueprintCallable, Category = "MetadatareplicatorBehaviourComponent", meta = (CallInEditor = "true"))
void SetMetadataName(const FString& Value, const int32 AgentId = -1);
};
#include "CustomMetadataReplicatorComponent.h"
#include "Net/UnrealNetwork.h"
#include "Actors/AtomsAgentGroup.h"
#include "Behaviours/MetadataReplicatorModule.h"
#include <AtomsUtils/Memory.h>
#include <AtomsCore/Metadata/Vector3fArrayMetadata.h>
#include <AtomsCore/Metadata/StringArrayMetadata.h>
#include <AtomsCore/Metadata/BoolArrayMetadata.h>
#include "AtomsModuleGeneratorUtils.h"
#include "AtomsAttributeUtils.h"
#include "GameFramework/GameStateBase.h"
#include "Engine/Player.h"
UCustomMetadataReplicatorComponent::UCustomMetadataReplicatorComponent()
{
AtomsBehaviourModule = "custommetadatareplicator";
#if ENGINE_MINOR_VERSION < 25
bReplicates = true;
#endif
UpdateTime = 0.1;
UseReliableRpc = true;
EnableReplication = true;
}
UCustomMetadataReplicatorComponent::~UCustomMetadataReplicatorComponent()
{
}
void UCustomMetadataReplicatorComponent::OnRegister()
{
Super::OnRegister();
#if ENGINE_MINOR_VERSION > 24
SetIsReplicated(true);
#endif
}
void UCustomMetadataReplicatorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
}
void UCustomMetadataReplicatorComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UCustomMetadataReplicatorComponent, ReplicatedMetadata);
DOREPLIFETIME(UCustomMetadataReplicatorComponent, MetadataName);
DOREPLIFETIME(UCustomMetadataReplicatorComponent, Interpolate);
}
void UCustomMetadataReplicatorComponent::OnBehaviourModuleCreated(AtomsPtr<Atoms::BehaviourModule>& module)
{
Super::OnBehaviourModuleCreated(module);
if (module->typeName() != "custommetadatareplicator")
return;
auto replicator = std::static_pointer_cast<MetadataReplicatorModule>(module);
if (!replicator)
return;
replicator->setMetadataReplicatorComponent(this);
if (GetOwner())
replicator->setWorld(GetOwner()->GetWorld());
AtomsCore::StringMetadata metaNames(TCHAR_TO_UTF8(*MetadataName));
AtomsCore::BoolMetadata metadataInterpolation(Interpolate);
replicator->attributes().addEntry("MetadataName", &metaNames);
replicator->attributes().addEntry("MetadataInterpolation", &metadataInterpolation);
}
void UCustomMetadataReplicatorComponent::OnRep_ReplicatedMetadata()
{
ClientReplicatedData.AddHead(ReplicatedMetadata);
}
void UCustomMetadataReplicatorComponent::UpdatedMetadata_Implementation(const FMetadataReplicatorState& Data)
{
if (GetOwnerRole() == ROLE_Authority)
return;
ClientReplicatedData.AddHead(Data);
}
void UCustomMetadataReplicatorComponent::UnreliableUpdatedMetadata_Implementation(const FMetadataReplicatorState& Data)
{
if (GetOwnerRole() == ROLE_Authority)
return;
ClientReplicatedData.AddHead(Data);
}
void UCustomMetadataReplicatorComponent::SetEnableReplication(const bool Value, const int32 AgentId)
{
if (AgentId < 0)
{
EnableReplication = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(EnableReplication, AtomsCore::BoolMetadata, );
}
else
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(EnableReplication_override, EnableReplicationOverride, AtomsCore::BoolMetadata, , AgentId);
}
}
void UCustomMetadataReplicatorComponent::RemoveEnableReplicationOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(EnableReplication_override, EnableReplicationOverride, AgentId);
}
void UCustomMetadataReplicatorComponent::SetMetadataName(const FString& Value, const int32 AgentId)
{
if (AgentId < 0)
{
MetadataName = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(MetadataName, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString);
}
}
void UCustomMetadataReplicatorComponent::GetAtomsAttributes(AtomsPtr<AtomsCore::MapMetadata>& attributes)
{
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(EnableReplication, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(EnableReplication_override, EnableReplicationOverride, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(MetadataName, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString);
}
Atoms module registration
#include "CustomMetadataReplicatorModule.h"
#include <Atoms/BehaviourModules.h>
void FAtomsTestModule::StartupModule()
{
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.registerBehaviourModule("custommetadatareplicator", &CustomMetadataReplicatorModule::creator, Atoms::BehaviourModules::kNative, true, "Unreal");
}
void FAtomsTestModule::StartupModule()
{
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.deregisterBehaviourModule("custommetadatareplicator");
}
, multiple selections available,
Related content
Working with metadatas with Python
Working with metadatas with Python
More like this
Driving module attributes with metadatas
Driving module attributes with metadatas
More like this
Writing a layout module
Writing a layout module
More like this
Creating agent groups
Creating agent groups
More like this
Agent group (AtomsMaya/AtomsHoudini)
Agent group (AtomsMaya/AtomsHoudini)
More like this
Creating a new Behaviour Tree decorator
Creating a new Behaviour Tree decorator
More like this
Copyright © 2017, Toolchefs LTD.