Skip to content

Instantly share code, notes, and snippets.

@DoubleDeez
Created June 16, 2020 20:50
Show Gist options
  • Save DoubleDeez/9e032411a5578264285f6c68905da8fa to your computer and use it in GitHub Desktop.
Save DoubleDeez/9e032411a5578264285f6c68905da8fa to your computer and use it in GitHub Desktop.
using Godot;
using System;
public class PositionReplicator : Node2D
{
[Export]
private float SendPeriod = 0.06f;
[Export]
private float ForceSyncTime = 2f;
private float TimeUntilSend = 0f;
private float LastSyncTime = 0f;
private Vector2 LastPosition = new Vector2();
private float LastRotation;
private Vector2 TargetPosition = new Vector2();
private float TargetRotation;
public Vector2 LinearVelocity = new Vector2();
public float AngularVelocity = 0f;
private float LastPacketTime = 0f;
private float LerpTime = 0f;
private bool IsEnabled = true;
private Node2D Target;
private bool IsMaster = false;
public delegate void MasterChangedEventHandler(bool IsMaster);
public event MasterChangedEventHandler OnMasterChangedEvent = delegate {};
public delegate void SyncPositionEventHandler(Vector2 OldPos, Vector2 NewPos);
public event SyncPositionEventHandler OnSyncPositionEvent = delegate {};
public delegate void SyncRotationEventHandler(float OldRot, float NewRot);
public event SyncRotationEventHandler OnSyncRotationEvent = delegate {};
public event Func<Vector2> GetLinearVelocity = null;
public event Func<float> GetAngularVelocity = null;
private const string LOG_CAT = "LogPositionReplicator";
public override void _Ready()
{
if (Target == null)
{
Target = this;
}
LastPacketTime = OS.GetTicksMsec();
IsMaster = this.IsMaster();
OnMasterChanged(IsMaster);
MDLog.AddLogCategoryProperties(LOG_CAT, new MDLogProperties(MDLogLevel.Info));
}
public void SetTarget(Node2D InTarget)
{
Target = InTarget;
TargetPosition = Target.Position;
TargetRotation = Target.Rotation;
}
public override void _Process(float Delta)
{
if (IsEnabled == false)
{
return;
}
bool CurIsMaster = this.IsMaster();
if (CurIsMaster != IsMaster)
{
IsMaster = CurIsMaster;
OnMasterChanged(IsMaster);
}
if (MDStatics.IsNetworkActive())
{
if (IsMaster)
{
TimeUntilSend -= Delta;
if (TimeUntilSend <= 0f)
{
if (GetLinearVelocity != null)
{
LinearVelocity = GetLinearVelocity();
}
else
{
LinearVelocity = (Target.Position - LastPosition) / Delta;
}
if (GetAngularVelocity != null)
{
AngularVelocity = GetAngularVelocity();
}
else
{
AngularVelocity = (Target.Rotation - LastRotation) / Delta;
}
TimeUntilSend = SendPeriod;
RpcUnreliable(nameof(SyncPosition), Target.Position, Target.Rotation, LinearVelocity, AngularVelocity);
}
LastPosition = Target.Position;
LastRotation = Target.Rotation;
}
}
}
public override void _PhysicsProcess(float Delta)
{
if (IsEnabled == false)
{
return;
}
if (MDStatics.IsNetworkActive() && IsMaster == false)
{
Vector2 OldPos = Target.Position;
float OldRot = Target.Rotation;
if (LerpTime > 0)
{
Target.Position += (TargetPosition - Target.Position) / LerpTime * Delta;
Target.Rotation += (TargetRotation - Target.Rotation) / LerpTime * Delta;
LerpTime -= Delta;
}
else
{
Target.Position = TargetPosition;
Target.Rotation = TargetRotation;
}
OnSyncPositionEvent(OldPos, Target.Position);
OnSyncRotationEvent(OldRot, Target.Rotation);
}
}
public void SetIsEnabled(bool InIsEnabled)
{
if (InIsEnabled != IsEnabled)
{
IsEnabled = InIsEnabled;
}
}
[Puppet]
void SyncPosition(Vector2 InPosition, float InRotation, Vector2 LinVelocity, float AngVelocity)
{
float CurrentTime = OS.GetTicksMsec() / 1000f;
float TimeDelta = CurrentTime - LastPacketTime;
float Jitter = TimeDelta - SendPeriod;
LerpTime = SendPeriod - Jitter;
LastPacketTime = CurrentTime;
TargetPosition = InPosition + (LinVelocity * TimeDelta);
TargetRotation = InRotation + (AngVelocity * TimeDelta);
LinearVelocity = LinVelocity;
AngVelocity = AngularVelocity;
if ((LastSyncTime + ForceSyncTime) < CurrentTime)
{
Vector2 OldPos = Target.Position;
float OldRot = Target.Rotation;
LastSyncTime = CurrentTime;
Target.Position = InPosition;
Target.Rotation = InRotation;
OnSyncPositionEvent(OldPos, Target.Position);
OnSyncRotationEvent(OldRot, Target.Rotation);
}
}
private void OnMasterChanged(bool IsMaster)
{
OnMasterChangedEvent(IsMaster);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment