Add NetworkTransform component
This commit is contained in:
169
Source/Engine/Networking/Components/NetworkTransform.cpp
Normal file
169
Source/Engine/Networking/Components/NetworkTransform.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "NetworkTransform.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Networking/NetworkReplicator.h"
|
||||
#include "Engine/Networking/NetworkStream.h"
|
||||
|
||||
PACK_STRUCT(struct Data
|
||||
{
|
||||
uint8 LocalSpace : 1;
|
||||
NetworkTransform::SyncModes SyncMode : 9;
|
||||
});
|
||||
|
||||
static_assert((int32)NetworkTransform::SyncModes::All + 1 == 512, "Invalid SyncModes bit count for Data.");
|
||||
|
||||
NetworkTransform::NetworkTransform(const SpawnParams& params)
|
||||
: Script(params)
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkTransform::OnEnable()
|
||||
{
|
||||
// Register for replication
|
||||
NetworkReplicator::AddObject(this);
|
||||
}
|
||||
|
||||
void NetworkTransform::OnDisable()
|
||||
{
|
||||
// Unregister from replication
|
||||
NetworkReplicator::RemoveObject(this);
|
||||
}
|
||||
|
||||
void NetworkTransform::Serialize(NetworkStream* stream)
|
||||
{
|
||||
// Get transform
|
||||
Transform transform;
|
||||
if (const auto* parent = GetParent())
|
||||
transform = LocalSpace ? parent->GetLocalTransform() : parent->GetTransform();
|
||||
else
|
||||
transform = Transform::Identity;
|
||||
|
||||
// Encode data
|
||||
Data data;
|
||||
data.LocalSpace = LocalSpace;
|
||||
data.SyncMode = SyncMode;
|
||||
stream->Write(data);
|
||||
if ((data.SyncMode & SyncModes::All) == (int)SyncModes::All)
|
||||
{
|
||||
stream->Write(transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((data.SyncMode & SyncModes::Position) == (int)SyncModes::Position)
|
||||
{
|
||||
stream->Write(transform.Translation);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Position)
|
||||
{
|
||||
if (data.SyncMode & SyncModes::PositionX)
|
||||
stream->Write(transform.Translation.X);
|
||||
if (data.SyncMode & SyncModes::PositionY)
|
||||
stream->Write(transform.Translation.X);
|
||||
if (data.SyncMode & SyncModes::PositionZ)
|
||||
stream->Write(transform.Translation.X);
|
||||
}
|
||||
if ((data.SyncMode & SyncModes::Scale) == (int)SyncModes::Scale)
|
||||
{
|
||||
stream->Write(transform.Scale);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Scale)
|
||||
{
|
||||
if (data.SyncMode & SyncModes::ScaleX)
|
||||
stream->Write(transform.Scale.X);
|
||||
if (data.SyncMode & SyncModes::ScaleY)
|
||||
stream->Write(transform.Scale.X);
|
||||
if (data.SyncMode & SyncModes::ScaleZ)
|
||||
stream->Write(transform.Scale.X);
|
||||
}
|
||||
if ((data.SyncMode & SyncModes::Rotation) == (int)SyncModes::Rotation)
|
||||
{
|
||||
const Float3 rotation = transform.Orientation.GetEuler();
|
||||
stream->Write(rotation);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Rotation)
|
||||
{
|
||||
const Float3 rotation = transform.Orientation.GetEuler();
|
||||
if (data.SyncMode & SyncModes::RotationX)
|
||||
stream->Write(rotation.X);
|
||||
if (data.SyncMode & SyncModes::RotationY)
|
||||
stream->Write(rotation.Y);
|
||||
if (data.SyncMode & SyncModes::RotationZ)
|
||||
stream->Write(rotation.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTransform::Deserialize(NetworkStream* stream)
|
||||
{
|
||||
// Get transform
|
||||
Transform transform;
|
||||
if (const auto* parent = GetParent())
|
||||
transform = LocalSpace ? parent->GetLocalTransform() : parent->GetTransform();
|
||||
else
|
||||
transform = Transform::Identity;
|
||||
|
||||
// Decode data
|
||||
Data data;
|
||||
stream->Read(data);
|
||||
if ((data.SyncMode & SyncModes::All) == (int)SyncModes::All)
|
||||
{
|
||||
stream->Read(transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((data.SyncMode & SyncModes::Position) == (int)SyncModes::Position)
|
||||
{
|
||||
stream->Read(transform.Translation);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Position)
|
||||
{
|
||||
if (data.SyncMode & SyncModes::PositionX)
|
||||
stream->Read(transform.Translation.X);
|
||||
if (data.SyncMode & SyncModes::PositionY)
|
||||
stream->Read(transform.Translation.X);
|
||||
if (data.SyncMode & SyncModes::PositionZ)
|
||||
stream->Read(transform.Translation.X);
|
||||
}
|
||||
if ((data.SyncMode & SyncModes::Scale) == (int)SyncModes::Scale)
|
||||
{
|
||||
stream->Read(transform.Scale);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Scale)
|
||||
{
|
||||
if (data.SyncMode & SyncModes::ScaleX)
|
||||
stream->Read(transform.Scale.X);
|
||||
if (data.SyncMode & SyncModes::ScaleY)
|
||||
stream->Read(transform.Scale.X);
|
||||
if (data.SyncMode & SyncModes::ScaleZ)
|
||||
stream->Read(transform.Scale.X);
|
||||
}
|
||||
if ((data.SyncMode & SyncModes::Rotation) == (int)SyncModes::Rotation)
|
||||
{
|
||||
Float3 rotation;
|
||||
stream->Read(rotation);
|
||||
transform.Orientation = Quaternion::Euler(rotation);
|
||||
}
|
||||
else if (data.SyncMode & SyncModes::Rotation)
|
||||
{
|
||||
Float3 rotation = transform.Orientation.GetEuler();
|
||||
if (data.SyncMode & SyncModes::RotationX)
|
||||
stream->Read(rotation.X);
|
||||
if (data.SyncMode & SyncModes::RotationY)
|
||||
stream->Read(rotation.Y);
|
||||
if (data.SyncMode & SyncModes::RotationZ)
|
||||
stream->Read(rotation.Z);
|
||||
transform.Orientation = Quaternion::Euler(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// Set transform
|
||||
if (auto* parent = GetParent())
|
||||
{
|
||||
if (data.LocalSpace)
|
||||
parent->SetLocalTransform(transform);
|
||||
else
|
||||
parent->SetTransform(transform);
|
||||
}
|
||||
}
|
||||
78
Source/Engine/Networking/Components/NetworkTransform.h
Normal file
78
Source/Engine/Networking/Components/NetworkTransform.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Scripting/Script.h"
|
||||
#include "Engine/Networking/INetworkSerializable.h"
|
||||
|
||||
/// <summary>
|
||||
/// Actor script component that synchronizes the Transform over the network.
|
||||
/// </summary>
|
||||
API_CLASS(Namespace="FlaxEngine.Networking") class FLAXENGINE_API NetworkTransform : public Script, public INetworkSerializable
|
||||
{
|
||||
API_AUTO_SERIALIZATION();
|
||||
DECLARE_SCRIPTING_TYPE(NetworkTransform);
|
||||
|
||||
/// <summary>
|
||||
/// Actor transform synchronization modes (flags).
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="Flags") enum class SyncModes
|
||||
{
|
||||
// No sync.
|
||||
None = 0,
|
||||
|
||||
// Position X component.
|
||||
PositionX = 1 << 0,
|
||||
// Position Y component.
|
||||
PositionY = 1 << 1,
|
||||
// Position Z component.
|
||||
PositionZ = 1 << 2,
|
||||
// Position XYZ components (full).
|
||||
Position = PositionX | PositionY | PositionZ,
|
||||
|
||||
// Scale X component.
|
||||
ScaleX = 1 << 3,
|
||||
// Scale Y component.
|
||||
ScaleY = 1 << 4,
|
||||
// Scale Z component.
|
||||
ScaleZ = 1 << 5,
|
||||
// Scale XYZ components (full).
|
||||
Scale = ScaleX | ScaleY | ScaleZ,
|
||||
|
||||
// Position X component.
|
||||
RotationX = 1 << 6,
|
||||
// Position Y component.
|
||||
RotationY = 1 << 7,
|
||||
// Position Z component.
|
||||
RotationZ = 1 << 8,
|
||||
// Rotation XYZ components (full).
|
||||
Rotation = RotationX | RotationY | RotationZ,
|
||||
|
||||
// All components fully synchronized.
|
||||
All = Position | Scale | Rotation,
|
||||
};
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// If checked, actor transform will be synchronized in local space of the parent actor (otherwise in world space).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(10)")
|
||||
bool LocalSpace = false;
|
||||
|
||||
/// <summary>
|
||||
/// Actor transform synchronization mode (flags).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(20)")
|
||||
SyncModes SyncMode = SyncModes::All;
|
||||
|
||||
public:
|
||||
// [Script]
|
||||
void OnEnable() override;
|
||||
void OnDisable() override;
|
||||
|
||||
// [INetworkSerializable]
|
||||
void Serialize(NetworkStream* stream) override;
|
||||
void Deserialize(NetworkStream* stream) override;
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(NetworkTransform::SyncModes);
|
||||
@@ -367,6 +367,20 @@ void NetworkReplicator::AddObject(ScriptingObject* obj, ScriptingObject* parent)
|
||||
Objects.Add(MoveTemp(item));
|
||||
}
|
||||
|
||||
void NetworkReplicator::RemoveObject(ScriptingObject* obj)
|
||||
{
|
||||
if (!obj || NetworkManager::State == NetworkConnectionState::Offline)
|
||||
return;
|
||||
ScopeLock lock(ObjectsLock);
|
||||
const auto it = Objects.Find(obj->GetID());
|
||||
if (it != Objects.End())
|
||||
return;
|
||||
|
||||
// Remove object from the list
|
||||
NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Remove object {}, owned by {}", obj->GetID().ToString(), it->Item.ParentId.ToString());
|
||||
Objects.Remove(it);
|
||||
}
|
||||
|
||||
void NetworkReplicator::SpawnObject(ScriptingObject* obj)
|
||||
{
|
||||
if (!obj || NetworkManager::State == NetworkConnectionState::Offline)
|
||||
@@ -507,10 +521,9 @@ void NetworkInternal::NetworkReplicatorClear()
|
||||
{
|
||||
// Cleanup any spawned objects
|
||||
DeleteNetworkObject(obj);
|
||||
Objects.Remove(it);
|
||||
}
|
||||
}
|
||||
Objects.Clear();
|
||||
Objects.SetCapacity(0);
|
||||
SpawnQueue.Clear();
|
||||
DespawnQueue.Clear();
|
||||
IdsRemappingTable.Clear();
|
||||
|
||||
@@ -59,6 +59,13 @@ public:
|
||||
/// <param name="parent">The parent of the object (eg. player that spawned it).</param>
|
||||
API_FUNCTION() static void AddObject(ScriptingObject* obj, ScriptingObject* parent = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the object from the network replication system.
|
||||
/// </summary>
|
||||
/// <remarks>Does nothing if network is offline.</remarks>
|
||||
/// <param name="obj">The object to don't replicate.</param>
|
||||
API_FUNCTION() static void RemoveObject(ScriptingObject* obj);
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the object to the other clients. Can be spawned by the owner who locally created it (eg. from prefab).
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user