-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathServerPhaseSync.cs
More file actions
140 lines (115 loc) · 3.94 KB
/
ServerPhaseSync.cs
File metadata and controls
140 lines (115 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
namespace Kaminari
{
public class ServerPhaseSync<PQ> where PQ : IProtocolQueues
{
public ulong NextTick { get; private set; }
public ulong MeanTickTime { get; private set; }
public float Integrator { get; private set; }
public float AdjustedIntegrator => Integrator + protocol.ServerTimeDiff - MeanTickTime;
public Action OnEarlyTick;
public Action OnTick;
public Action OnLateTick;
private Protocol<PQ> protocol;
private ushort lastPacketID;
private ConcurrentQueue<Action> earlyOneShot;
private ConcurrentQueue<Action> oneShot;
private bool running;
private Thread thread;
public ushort TickId { get; private set; }
public ulong TickTime { get; private set; }
public ulong PhaserTickTime { get; private set; }
public ServerPhaseSync(Protocol<PQ> protocol)
{
// Base values
TickId = 0;
NextTick = DateTimeExtensions.now() + 50;
PhaserTickTime = DateTimeExtensions.now();
Integrator = 50;
this.protocol = protocol;
// No actions yet
earlyOneShot = new ConcurrentQueue<Action>();
oneShot = new ConcurrentQueue<Action>();
}
public void Start()
{
// Start
running = true;
thread = new Thread(update);
thread.Start();
}
public void Stop()
{
running = false;
thread.Join();
}
public void FixTickId(ushort id)
{
TickId = id;
lastPacketID = id;
}
public void EarlyOneShot(Action action)
{
earlyOneShot.Enqueue(action);
}
public void OneShot(Action action)
{
oneShot.Enqueue(action);
}
public void ServerPacket(ushort currentID, ushort maxID)
{
// Multipackets should not be counted towards PLL
if (currentID == maxID)
{
return;
}
// Get current tick time
ulong time = PhaserTickTime + (ulong)Integrator;
PhaserTickTime = DateTimeExtensions.now();
// More than one packet in between?
ushort packetDiff = Overflow.sub(maxID, lastPacketID);
lastPacketID = maxID;
if (packetDiff > 1)
{
NextTick += (ulong)(Integrator * (packetDiff - 1));
time += (ulong)(Integrator * (packetDiff - 1));
}
// Phase detector
float err = (float)((long)time - (long)NextTick);
// Loop filter
// Integrator = 0.999f * Integrator + err;
float Ki = 1e-3f;
Integrator = Ki * err + Integrator;
// NCO
NextTick = time + (ulong)Integrator;
}
private void update()
{
MeanTickTime = 0;
while (running)
{
++TickId;
TickTime = DateTimeExtensions.now();
while (earlyOneShot.TryDequeue(out var action))
{
action();
}
OnEarlyTick?.Invoke();
OnTick?.Invoke();
while (oneShot.TryDequeue(out var action))
{
action();
}
OnLateTick?.Invoke();
// Update tick time
MeanTickTime = DateTimeExtensions.now() - TickTime;
// MeanTickTime = (ulong)((float)MeanTickTime * 0.9f + (float)(DateTimeExtensions.now() - TickTime) * 0.1f);
// Wait until next tick, account sever/client diff
Thread.Sleep((int)Math.Max(1.01f, AdjustedIntegrator));
}
}
}
}