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);
};
Â
Atoms module registration
Â
Copyright © 2017, Toolchefs LTD.