Skip to content
This repository was archived by the owner on Oct 22, 2023. It is now read-only.

Commit 9546246

Browse files
committed
First steps towards clientside prediction
1 parent 6262651 commit 9546246

31 files changed

+473
-412
lines changed

Engine/Client/CommandBuffer.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Lockstep.Core.Data;
4+
using Lockstep.Core.Interfaces;
5+
6+
namespace Lockstep.Client.Implementations
7+
{
8+
public class CommandBuffer : ICommandBuffer
9+
{
10+
private readonly Dictionary<ulong, List<ICommand>> _commands = new Dictionary<ulong, List<ICommand>>();
11+
12+
public ulong Count
13+
{
14+
get
15+
{
16+
lock (_commands)
17+
{
18+
return _commands.Keys.Max();
19+
}
20+
}
21+
}
22+
23+
public ulong ItemIndex { get; private set; }
24+
25+
public ulong Remaining => Count - ItemIndex;
26+
27+
public void Insert(ulong frameNumber, ICommand command)
28+
{
29+
lock (_commands)
30+
{
31+
if (!_commands.ContainsKey(frameNumber))
32+
{
33+
_commands.Add(frameNumber, new List<ICommand>(10));
34+
}
35+
36+
_commands[frameNumber].Add(command);
37+
}
38+
}
39+
40+
public ICommand[] GetNext()
41+
{
42+
lock (_commands)
43+
{
44+
//If no commands were inserted then return an empty list
45+
if (!_commands.ContainsKey(ItemIndex))
46+
{
47+
_commands[ItemIndex] = new List<ICommand>();
48+
}
49+
50+
return _commands[ItemIndex++].ToArray();
51+
52+
}
53+
}
54+
}
55+
}

Engine/Client/FrameBuffer.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

Engine/Client/Implementations/LocalDataReceiver.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

Engine/Client/Implementations/NetworkedDataReceiver.cs

Lines changed: 0 additions & 98 deletions
This file was deleted.

Engine/Client/Interfaces/IDataReceiver.cs

Lines changed: 0 additions & 14 deletions
This file was deleted.

Engine/Client/Simulation.cs

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,68 @@
11
using System;
2-
using Lockstep.Client.Interfaces;
3-
using Lockstep.Core.Data;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using Lockstep.Client.Implementations;
5+
using Lockstep.Client.Interfaces;
46
using Lockstep.Core.Interfaces;
7+
using Lockstep.Network;
58
using Lockstep.Network.Messages;
9+
using Lockstep.Network.Utils;
610

711
namespace Lockstep.Client
812
{
913
public class Simulation
1014
{
11-
public event Action<uint> Ticked;
15+
public event Action<ulong> Ticked;
1216

1317
public bool Running { get; set; }
18+
19+
private readonly ISystems _systems;
20+
private readonly INetwork _network;
1421

15-
public IFrameBuffer FrameBuffer { get; } = new FrameBuffer();
22+
public float _tickDt;
23+
public float _accumulatedTime;
1624

17-
private readonly ISystems _systems;
25+
public ulong CurrentTick { get; private set; }
1826

19-
private readonly IDataReceiver _dataReceiver;
27+
private readonly CommandBuffer _networkCommandBuffer;
28+
private readonly IDictionary<ushort, Func<ISerializableCommand>> _commandFactories = new Dictionary<ushort, Func<ISerializableCommand>>();
2029

21-
public float _tickDt;
22-
public float _accumulatedTime;
2330

24-
public Simulation(ISystems systems, IDataReceiver dataReceiver)
31+
public Simulation(ISystems systems, INetwork network)
2532
{
2633
_systems = systems;
27-
_systems.SetFrameBuffer(FrameBuffer);
34+
_systems.CommandBuffer = new CommandBuffer();
2835

29-
_dataReceiver = dataReceiver;
36+
_networkCommandBuffer = new CommandBuffer();
3037

31-
_dataReceiver.InitReceived += OnInitReceived;
32-
_dataReceiver.FrameReceived += OnFrameReceived;
38+
_network = network;
39+
_network.DataReceived += OnDataReceived;
3340
}
3441

35-
public void Execute(ICommand command)
42+
43+
public void RegisterCommand(Func<ISerializableCommand> commandFactory)
3644
{
37-
_dataReceiver.Receive(command);
45+
var tag = commandFactory.Invoke().Tag;
46+
if (_commandFactories.ContainsKey(tag))
47+
{
48+
throw new InvalidDataException("The command tag " + tag + " is already registered. Every command tag must be unique.");
49+
}
50+
_commandFactories.Add(tag, commandFactory);
51+
}
52+
53+
public void Execute(ISerializableCommand command)
54+
{
55+
//Execute the command locally in the next tick
56+
_systems.CommandBuffer.Insert(CurrentTick + 1, command);
57+
58+
//Tell the server
59+
var writer = new Serializer();
60+
writer.Put((byte)MessageTag.Input);
61+
writer.Put(CurrentTick + 1);
62+
writer.Put(command.Tag);
63+
command.Serialize(writer);
64+
65+
_network.Send(Compressor.Compress(writer));
3866
}
3967

4068
public void Update(float deltaTime)
@@ -45,36 +73,59 @@ public void Update(float deltaTime)
4573
}
4674

4775
_accumulatedTime += deltaTime;
48-
49-
//TODO: adjust _tickDt depending on buffersize
76+
5077
while (_accumulatedTime >= _tickDt)
5178
{
52-
//Tick();
79+
Tick();
5380

5481
_accumulatedTime -= _tickDt;
5582
}
5683
}
5784

58-
private void OnInitReceived(object sender, Init init)
85+
private void StartSimulation(int targetFps)
5986
{
60-
_tickDt = 1000f / init.TargetFPS;
87+
_tickDt = 1000f / targetFps;
6188

6289
_systems.Initialize();
6390

6491
Running = true;
92+
}
93+
94+
private void Tick()
95+
{
96+
_systems.Tick();
97+
Ticked?.Invoke(CurrentTick);
98+
99+
CurrentTick++;
65100
}
66101

67-
private void OnFrameReceived(object sender, Frame e)
102+
private void OnDataReceived(byte[] data)
68103
{
69-
FrameBuffer.Insert(e);
104+
data = Compressor.Decompress(data);
70105

71-
Tick();
106+
var reader = new Deserializer(data);
107+
var messageTag = (MessageTag)reader.GetByte();
108+
switch (messageTag)
109+
{
110+
case MessageTag.StartSimulation:
111+
var init = new Init();
112+
init.Deserialize(reader);
113+
StartSimulation(init.TargetFPS);
114+
break;
115+
case MessageTag.Input:
116+
var frameNumber = reader.GetULong();
117+
var tag = reader.GetUShort();
118+
119+
if (_commandFactories.ContainsKey(tag))
120+
{
121+
var newCommand = _commandFactories[tag].Invoke();
122+
newCommand.Deserialize(reader);
123+
124+
_networkCommandBuffer.Insert(frameNumber, newCommand);
125+
}
126+
127+
break;
128+
}
72129
}
73-
74-
private void Tick()
75-
{
76-
_systems.Tick();
77-
Ticked?.Invoke(FrameBuffer.ItemIndex);
78-
}
79130
}
80131
}

0 commit comments

Comments
 (0)