Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

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