Skip to content

Commit 90ab0cf

Browse files
committed
Added lag compensation
1 parent 8484ed7 commit 90ab0cf

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

MLAPI/Data/NetworkingConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class NetworkingConfiguration
2323
public bool ConnectionApproval = false;
2424
public Action<byte[], int, Action<int, bool>> ConnectionApprovalCallback = null;
2525
public byte[] ConnectionData = new byte[0];
26+
public float SecondsHistory = 5;
2627
public bool HandleObjectSpawning = true;
2728
//TODO
2829
public bool CompressMessages = false;

MLAPI/Data/TrackedPointData.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using UnityEngine;
2+
3+
namespace MLAPI.Data
4+
{
5+
internal struct TrackedPointData
6+
{
7+
internal Vector3 position;
8+
internal Quaternion rotation;
9+
}
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine.Networking;
4+
5+
namespace MLAPI.MonoBehaviours.Core
6+
{
7+
public static class LagCompensationManager
8+
{
9+
public static List<TrackedObject> SimulationObjects = new List<TrackedObject>();
10+
11+
public static void Simulate(float secondsAgo, Action action)
12+
{
13+
for (int i = 0; i < SimulationObjects.Count; i++)
14+
{
15+
SimulationObjects[i].ReverseTransform(secondsAgo);
16+
}
17+
18+
action.Invoke();
19+
20+
for (int i = 0; i < SimulationObjects.Count; i++)
21+
{
22+
SimulationObjects[i].ResetStateTransform();
23+
}
24+
}
25+
26+
private static byte error = 0;
27+
public static void Simulate(int clientId, Action action)
28+
{
29+
float milisecondsDelay = NetworkTransport.GetCurrentRTT(NetworkingManager.singleton.hostId, clientId, out error) / 2f;
30+
Simulate(milisecondsDelay * 1000f, action);
31+
}
32+
33+
internal static void AddFrames()
34+
{
35+
for (int i = 0; i < SimulationObjects.Count; i++)
36+
{
37+
SimulationObjects[i].AddFrame();
38+
}
39+
}
40+
}
41+
}

MLAPI/MonoBehaviours/Core/NetworkingManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using MLAPI.NetworkingManagerComponents;
1+
using MLAPI.MonoBehaviours.Core;
2+
using MLAPI.NetworkingManagerComponents;
23
using System;
34
using System.Collections;
45
using System.Collections.Generic;
@@ -255,7 +256,7 @@ private void Shutdown()
255256
}
256257

257258
//Receive stuff
258-
int hostId;
259+
internal int hostId;
259260
int clientId;
260261
int channelId;
261262
int receivedSize;
@@ -328,6 +329,7 @@ private void Update()
328329
(messagesProcessed < NetworkConfig.MaxMessagesPerFrame || NetworkConfig.MaxMessagesPerFrame < 0));
329330

330331
}
332+
LagCompensationManager.AddFrames();
331333
}
332334

333335
private IEnumerator ApprovalTimeout(int clientId)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using MLAPI.Data;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace MLAPI.MonoBehaviours.Core
6+
{
7+
//Based on: https://twotenpvp.github.io/lag-compensation-in-unity.html
8+
//Modified to be used with latency rather than fixed frames and subframes. Thus it will be less accrurate but more modular.
9+
public class TrackedObject : MonoBehaviour
10+
{
11+
internal Dictionary<float, TrackedPointData> FrameData = new Dictionary<float, TrackedPointData>();
12+
internal List<float> Framekeys = new List<float>() { 0 };
13+
private Vector3 savedPosition;
14+
private Quaternion savedRotation;
15+
16+
internal void ReverseTransform(float secondsAgo)
17+
{
18+
savedPosition = transform.position;
19+
savedRotation = transform.rotation;
20+
float currentTime = Time.time;
21+
float targetTime = Time.time - secondsAgo;
22+
float previousTime = 0;
23+
float nextTime = 0;
24+
for (int i = 1; i < Framekeys.Count - 1; i++)
25+
{
26+
if(Framekeys[i - 1] > targetTime && Framekeys[i] <= targetTime)
27+
{
28+
previousTime = Framekeys[i];
29+
nextTime = Framekeys[i + 1];
30+
break;
31+
}
32+
}
33+
34+
float timeBetweenFrames = nextTime - previousTime;
35+
float timeAwayFromPrevious = currentTime - previousTime;
36+
float lerpProgress = timeAwayFromPrevious / timeBetweenFrames;
37+
transform.position = Vector3.Lerp(FrameData[previousTime].position, FrameData[nextTime].position, lerpProgress);
38+
transform.rotation = Quaternion.Slerp(FrameData[previousTime].rotation, FrameData[nextTime].rotation, lerpProgress);
39+
}
40+
41+
internal void ResetStateTransform()
42+
{
43+
transform.position = savedPosition;
44+
transform.rotation = savedRotation;
45+
}
46+
47+
void Start()
48+
{
49+
LagCompensationManager.SimulationObjects.Add(this);
50+
}
51+
52+
void OnDestroy()
53+
{
54+
LagCompensationManager.SimulationObjects.Remove(this);
55+
}
56+
57+
internal void AddFrame()
58+
{
59+
float currentTime = Time.time;
60+
for (int i = 0; i < Framekeys.Count; i++)
61+
{
62+
if (currentTime - Framekeys[i] <= NetworkingManager.singleton.NetworkConfig.SecondsHistory)
63+
{
64+
for (int j = 0; j < i; j++)
65+
{
66+
FrameData.Remove(Framekeys[0]);
67+
//This is not good for performance. Other datatypes should be concidered.
68+
Framekeys.RemoveAt(0);
69+
}
70+
}
71+
}
72+
FrameData.Add(Time.time, new TrackedPointData()
73+
{
74+
position = transform.position,
75+
rotation = transform.rotation
76+
});
77+
Framekeys.Add(Time.frameCount);
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)