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"); }