• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orion-ecs / keen-eye / 20585547123

30 Dec 2025 12:10AM UTC coverage: 69.855% (+2.8%) from 67.047%
20585547123

push

github

tyevco
Implement RTT measurement, ownership transfer, and input processing

Client-side:
- Add RTT tracking with SendPing() and RoundTripTimeMs property
- Handle Pong messages to calculate round-trip time
- Implement ownership transfer handling with tag swapping
- Add OwnershipChanged event for ownership notifications
- Handle ConnectionRejected with reason codes

Server-side:
- Add ClientInputReceived event for processing client inputs
- Pass raw input data to event listeners for game-specific handling

Protocol:
- Add ReadByte/WriteByte helpers for reason codes and small values

This completes all the networking plugin TODOs for Issue #353.

3492 of 4450 branches covered (78.47%)

Branch coverage included in aggregate %.

8 of 61 new or added lines in 2 files covered. (13.11%)

374 existing lines in 13 files now uncovered.

20184 of 29443 relevant lines covered (68.55%)

1.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.5
/src/KeenEyes.Network/Systems/NetworkClientSendSystem.cs
1
using KeenEyes.Network.Components;
2
using KeenEyes.Network.Prediction;
3
using KeenEyes.Network.Protocol;
4
using KeenEyes.Network.Transport;
5

6
namespace KeenEyes.Network.Systems;
7

8
/// <summary>
9
/// Client system that sends input to the server.
10
/// </summary>
11
/// <remarks>
12
/// Runs in LateUpdate phase after local prediction.
13
/// </remarks>
14
public sealed class NetworkClientSendSystem(NetworkClientPlugin plugin) : SystemBase
1✔
15
{
16
    private readonly byte[] sendBuffer = new byte[1024];
1✔
17
    private float pingTimer;
18
    private const float PingInterval = 1.0f; // Send ping every second
19
    private uint lastSentInputTick;
20

21
    /// <inheritdoc/>
22
    public override void Update(float deltaTime)
23
    {
24
        if (!plugin.IsConnected)
1✔
25
        {
26
            return;
1✔
27
        }
28

29
        // Send periodic ping for latency measurement
30
        pingTimer += deltaTime;
1✔
31
        if (pingTimer >= PingInterval)
1✔
32
        {
33
            pingTimer -= PingInterval;
1✔
34
            SendPing();
1✔
35
        }
36

37
        // Send input for predicted entities
38
        if (plugin.Config.EnablePrediction)
1✔
39
        {
40
            SendInput();
1✔
41
        }
42

43
        // Pump the transport to flush outgoing data
44
        plugin.Transport.Update();
1✔
45
    }
1✔
46

47
    private void SendPing()
48
    {
49
        var writer = new NetworkMessageWriter(sendBuffer);
1✔
50
        writer.WriteHeader(MessageType.Ping, plugin.CurrentTick);
1✔
51
        plugin.SendToServer(writer.GetWrittenSpan(), DeliveryMode.Unreliable);
1✔
52
    }
1✔
53

54
    private void SendInput()
55
    {
56
        var inputSerializer = plugin.Config.InputSerializer;
1✔
57
        if (inputSerializer is null)
1✔
58
        {
59
            return;
1✔
60
        }
61

62
        // Find locally owned predicted entities and send their input
UNCOV
63
        foreach (var entity in World.Query<LocallyOwned, Predicted, NetworkId>())
×
64
        {
UNCOV
65
            var inputBuffer = plugin.GetInputBuffer(entity) as IInputBuffer;
×
UNCOV
66
            if (inputBuffer is null || inputBuffer.NewestTick <= lastSentInputTick)
×
67
            {
68
                continue;
69
            }
70

UNCOV
71
            ref readonly var networkId = ref World.Get<NetworkId>(entity);
×
72

73
            // Send all unsent inputs (redundantly for reliability)
74
            // We send the last few inputs to handle packet loss
UNCOV
75
            var startTick = lastSentInputTick > 0 ? lastSentInputTick : inputBuffer.OldestTick;
×
76

UNCOV
77
            foreach (var input in inputBuffer.GetInputsFromBoxed(startTick))
×
78
            {
UNCOV
79
                var writer = new NetworkMessageWriter(sendBuffer);
×
UNCOV
80
                writer.WriteHeader(MessageType.ClientInput, plugin.CurrentTick);
×
UNCOV
81
                writer.WriteNetworkId(networkId.Value);
×
UNCOV
82
                writer.WriteInput(inputSerializer, input);
×
83

UNCOV
84
                plugin.SendToServer(writer.GetWrittenSpan(), DeliveryMode.UnreliableSequenced);
×
85
            }
86

UNCOV
87
            lastSentInputTick = inputBuffer.NewestTick;
×
88
        }
UNCOV
89
    }
×
90
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc