Skip to content
Snippets Groups Projects
Commit 1f0bc76b authored by David Gilbert's avatar David Gilbert :bug:
Browse files

Separated basic transform replication into own component.

parent 6a6aae42
No related branches found
No related tags found
1 merge request!31Initial Pawn Replication
No preview for this file type
// Fill out your copyright notice in the Description page of Project Settings.
#include "Pawn/ClientTransformReplication.h"
#include "Net/UnrealNetwork.h"
UClientTransformReplication::UClientTransformReplication()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = TG_PostUpdateWork;
PrimaryComponentTick.SetTickFunctionEnable(true);
SetIsReplicatedByDefault(true);
// Direct transform replication
ControllerNetUpdateRate = 100.0f; // 100 htz is default
ControllerNetUpdateCount = 0.0f;
}
// Naive direct transform replication (replace with input rep?)
void UClientTransformReplication::UpdateState(float DeltaTime)
{
const auto* Pawn = GetOwner();
if (Pawn && Pawn->HasLocalNetOwner())
{
if (GetIsReplicated())
{
const FVector Loc = Pawn->GetActorLocation();
const FRotator Rot = Pawn->GetActorRotation();
if (!Loc.Equals(ReplicatedTransform.Position) || !Rot.Equals(ReplicatedTransform.Rotation))
{
ControllerNetUpdateCount += DeltaTime;
if (ControllerNetUpdateCount >= (1.0f / ControllerNetUpdateRate)) // todo save inverse?
{
ControllerNetUpdateCount = 0.0f;
ReplicatedTransform.Position = Loc;
ReplicatedTransform.Rotation = Rot;
if (GetNetMode() == NM_Client) // why do we differentiate here between netmode and authority?
{
SendControllerTransform_ServerRpc(ReplicatedTransform);
}
}
}
}
}
}
void UClientTransformReplication::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
UpdateState(DeltaTime);
}
void UClientTransformReplication::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// Skipping the owner with this as the owner will use the controllers location directly
DOREPLIFETIME_CONDITION(UClientTransformReplication, ReplicatedTransform, COND_SkipOwner);
DOREPLIFETIME(UClientTransformReplication, ControllerNetUpdateRate);
}
void UClientTransformReplication::SendControllerTransform_ServerRpc_Implementation(FVRTransformRep NewTransform)
{
// Store new transform and trigger OnRep_Function
ReplicatedTransform = NewTransform;
if (!GetOwner()->HasLocalNetOwner())
OnRep_ReplicatedTransform();
}
bool UClientTransformReplication::SendControllerTransform_ServerRpc_Validate(FVRTransformRep NewTransform)
{
return true;
// Optionally check to make sure that player is inside of their bounds and deny it if they aren't?
}
\ No newline at end of file
......@@ -9,21 +9,6 @@
#include "Pawn/VRPawnInputConfig.h"
#include "Utility/VirtualRealityUtilities.h"
#include "MotionControllerComponent.h"
#include "Net/UnrealNetwork.h"
UContinuousMovementComponent::UContinuousMovementComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = TG_PostUpdateWork;
PrimaryComponentTick.SetTickFunctionEnable(false);
// Replication:
SetIsReplicatedByDefault(true);
// Direct transform replication
ControllerNetUpdateRate = 100.0f; // 100 htz is default
ControllerNetUpdateCount = 0.0f;
}
void UContinuousMovementComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent)
{
......@@ -93,9 +78,6 @@ void UContinuousMovementComponent::SetupPlayerInput(UInputComponent* PlayerInput
EI->BindAction(DesktopRotation, ETriggerEvent::Completed, this, &UContinuousMovementComponent::EndDesktopRotation);
EI->BindAction(MoveUp, ETriggerEvent::Triggered,this,&UContinuousMovementComponent::OnBeginUp);
}
// We're initialized
PrimaryComponentTick.SetTickFunctionEnable(true);
}
void UContinuousMovementComponent::StartDesktopRotation()
......@@ -112,7 +94,6 @@ void UContinuousMovementComponent::TickComponent(float DeltaTime, ELevelTick Tic
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
UpdateState(DeltaTime);
}
void UContinuousMovementComponent::OnBeginMove(const FInputActionValue& Value)
......@@ -208,59 +189,3 @@ void UContinuousMovementComponent::OnBeginUp(const FInputActionValue& Value)
//the right hand is rotated on desktop to follow the cursor so it's forward is also changing with cursor position
VRPawn->AddMovementInput(FVector::UpVector, MoveValue);
}
// Naive direct transform replication (replace with input rep?)
void UContinuousMovementComponent::UpdateState(float DeltaTime)
{
if (VRPawn && VRPawn->HasLocalNetOwner())
{
if (GetIsReplicated())
{
const FVector Loc = VRPawn->GetActorLocation();
const FRotator Rot = VRPawn->GetActorRotation();
if (!Loc.Equals(ReplicatedTransform.Position) || !Rot.Equals(ReplicatedTransform.Rotation))
{
ControllerNetUpdateCount += DeltaTime;
if (ControllerNetUpdateCount >= (1.0f / ControllerNetUpdateRate)) // todo save inverse?
{
ControllerNetUpdateCount = 0.0f;
ReplicatedTransform.Position = Loc;
ReplicatedTransform.Rotation = Rot;
if (GetNetMode() == NM_Client) // why do we differentiate here between netmode and authority?
{
SendControllerTransform_ServerRpc(ReplicatedTransform);
}
}
}
}
}
}
void UContinuousMovementComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// Skipping the owner with this as the owner will use the controllers location directly
DOREPLIFETIME_CONDITION(UContinuousMovementComponent, ReplicatedTransform, COND_SkipOwner);
DOREPLIFETIME(UContinuousMovementComponent, ControllerNetUpdateRate);
}
void UContinuousMovementComponent::SendControllerTransform_ServerRpc_Implementation(FVRTransformRep NewTransform)
{
// Store new transform and trigger OnRep_Function
ReplicatedTransform = NewTransform;
if (!GetOwner()->HasLocalNetOwner())
OnRep_ReplicatedTransform();
}
bool UContinuousMovementComponent::SendControllerTransform_ServerRpc_Validate(FVRTransformRep NewTransform)
{
return true;
// Optionally check to make sure that player is inside of their bounds and deny it if they aren't?
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Utility/VirtualRealityUtilities.h"
#include "ClientTransformReplication.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UClientTransformReplication : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UClientTransformReplication();
protected:
/*
* For now, replicate in a naive sending every x ms if the transform has changed.
* This is way overkill, as we should only be sending input. However, I am not yet fully sure how
* the Unreal Client-Authoritative thingy works and what part simulates e.g. gravity.
* As this modifies only the tracking origin, latency should not be that much of an issue, so theoretically
* Server-Authority should work here too, in which case we'd just send the x and y input.
* Try both ways.
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Full transform update replication
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Rate to update the position to the server, 100htz is default (same as replication rate, should also hit every tick).
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Networking", meta = (ClampMin = "0", UIMin = "0"))
float ControllerNetUpdateRate;
// Accumulates time until next send
float ControllerNetUpdateCount;
UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedTransform, Category = "Networking")
FVRTransformRep ReplicatedTransform;
void UpdateState(float DeltaTime);
UFUNCTION()
virtual void OnRep_ReplicatedTransform()
{
// Modify pawn position - how does this work in movement components?
// For now, directly apply the transforms:
auto* Pawn = GetOwner();
if (Pawn && Pawn->HasValidRootComponent())
Pawn->SetActorLocationAndRotation(ReplicatedTransform.Position, ReplicatedTransform.Rotation);
}
UFUNCTION(Unreliable, Server, WithValidation)
void SendControllerTransform_ServerRpc(FVRTransformRep NewTransform);
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;
};
......@@ -26,9 +26,6 @@ class RWTHVRTOOLKIT_API UContinuousMovementComponent : public UActorComponent, p
GENERATED_BODY()
public:
UContinuousMovementComponent();
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement")
......@@ -111,48 +108,4 @@ private:
*/
void SetCameraOffset() const;
void UpdateRightHandForDesktopInteraction() const;
//~ Begin Replication
protected:
/*
* For now, replicate in a naive sending every x ms if the transform has changed.
* This is way overkill, as we should only be sending input. However, I am not yet fully sure how
* the Unreal Client-Authoritative thingy works and what part simulates e.g. gravity.
* As this modifies only the tracking origin, latency should not be that much of an issue, so theoretically
* Server-Authority should work here too, in which case we'd just send the x and y input.
* Try both ways.
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Full transform update replication
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Rate to update the position to the server, 100htz is default (same as replication rate, should also hit every tick).
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Networking", meta = (ClampMin = "0", UIMin = "0"))
float ControllerNetUpdateRate;
// Accumulates time until next send
float ControllerNetUpdateCount;
UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedTransform, Category = "Networking")
FVRTransformRep ReplicatedTransform;
void UpdateState(float DeltaTime);
UFUNCTION()
virtual void OnRep_ReplicatedTransform()
{
// Modify pawn position - how does this work in movement components?
// For now, directly apply the transforms:
auto* Pawn = GetOwner();
if (Pawn && Pawn->HasValidRootComponent())
Pawn->SetActorLocationAndRotation(ReplicatedTransform.Position, ReplicatedTransform.Rotation);
}
UFUNCTION(Unreliable, Server, WithValidation)
void SendControllerTransform_ServerRpc(FVRTransformRep NewTransform);
//~ End Replication
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment