将 openspec skills 迁移到全局 + 定义后续 proto 类型
This commit is contained in:
@@ -26,14 +26,14 @@ public class MovementComponent : MonoBehaviour
|
||||
private Vector3 _currentPos;
|
||||
private float _lerpTime;
|
||||
[SerializeField] private float _lerpRate = 0.1f;
|
||||
private PlayerInput _cachedInput;
|
||||
private MoveInput _cachedInput;
|
||||
|
||||
public void Init(bool isControlled, Player master, int speed = 0, long serverTick = 0)
|
||||
{
|
||||
this._master = master;
|
||||
this._isControlled = isControlled;
|
||||
this._speed = speed;
|
||||
this._startTickOffset = serverTick;
|
||||
_master = master;
|
||||
_isControlled = isControlled;
|
||||
_speed = speed;
|
||||
_startTickOffset = serverTick;
|
||||
_rigid.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
_rigid.isKinematic = !isControlled;
|
||||
_rigid.velocity = Vector3.zero;
|
||||
@@ -50,7 +50,7 @@ public class MovementComponent : MonoBehaviour
|
||||
{
|
||||
if (_cachedInput != null)
|
||||
{
|
||||
NetworkManager.Instance.SendPlayerInput(_cachedInput);
|
||||
NetworkManager.Instance.SendMoveInput(_cachedInput);
|
||||
}
|
||||
|
||||
_lastSendTime = Time.time;
|
||||
@@ -98,21 +98,26 @@ public class MovementComponent : MonoBehaviour
|
||||
ReplayPendingInputs(replayInputs);
|
||||
}
|
||||
|
||||
private PlayerInput CaptureInput()
|
||||
private MoveInput CaptureInput()
|
||||
{
|
||||
Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
|
||||
if (input == Vector3.zero) return null;
|
||||
return new PlayerInput()
|
||||
var input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
|
||||
if (input == Vector3.zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MoveInput
|
||||
{
|
||||
PlayerId = _master.PlayerId,
|
||||
Input = ProtoExtensions.ToProtoVector3(input),
|
||||
Tick = Tick
|
||||
Tick = Tick,
|
||||
MoveX = input.x,
|
||||
MoveY = input.z
|
||||
};
|
||||
}
|
||||
|
||||
private void Simulate(PlayerInput input)
|
||||
private void Simulate(MoveInput input)
|
||||
{
|
||||
Vector3 dir = input == null ? Vector3.zero : input.Input.ToVector3();
|
||||
var dir = input == null ? Vector3.zero : new Vector3(input.MoveX, 0f, input.MoveY);
|
||||
_rigid.velocity = _speed * dir;
|
||||
if (_isControlled)
|
||||
{
|
||||
@@ -165,11 +170,11 @@ public class MovementComponent : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplayPendingInputs(IReadOnlyList<PlayerInput> replayInputs)
|
||||
private void ReplayPendingInputs(IReadOnlyList<MoveInput> replayInputs)
|
||||
{
|
||||
foreach (var replayInput in replayInputs)
|
||||
{
|
||||
_rigid.position += _speed * replayInput.Input.ToVector3() * _sendInterval;
|
||||
_rigid.position += _speed * new Vector3(replayInput.MoveX, 0f, replayInput.MoveY) * _sendInterval;
|
||||
}
|
||||
|
||||
if (_isControlled)
|
||||
@@ -177,4 +182,4 @@ public class MovementComponent : MonoBehaviour
|
||||
MainUI.Instance.OnClientPosChanged(_rigid.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,35 +4,34 @@ namespace Network.Defines
|
||||
{
|
||||
Unknow = 0,
|
||||
|
||||
// 游戏相关
|
||||
PlayerInput = 1,
|
||||
// Gameplay
|
||||
MoveInput = 1,
|
||||
PlayerState = 2,
|
||||
PlayerAction = 3,
|
||||
GameState = 4,
|
||||
ShootInput = 3,
|
||||
CombatEvent = 4,
|
||||
PlayerJoin = 5,
|
||||
PlayerLeave = 6,
|
||||
PlayerAction = 7,
|
||||
GameState = 8,
|
||||
|
||||
// 聊天相关
|
||||
// Chat
|
||||
ChatMessage = 10,
|
||||
PrivateMessage = 11,
|
||||
SystemMessage = 12,
|
||||
|
||||
// 系统相关
|
||||
// Session
|
||||
HeartBeat = 20,
|
||||
|
||||
LoginRequest = 21,
|
||||
LoginResponse = 22,
|
||||
|
||||
LogoutRequest = 23,
|
||||
|
||||
// 房间管理
|
||||
// Room management
|
||||
CreateRoom = 30,
|
||||
JoinRoom = 31,
|
||||
LeaveRoom = 32,
|
||||
RoomList = 33,
|
||||
|
||||
|
||||
Heartbeat = 40,
|
||||
HeartbeatResponse = 41,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package Network.Defines;
|
||||
option csharp_namespace = "Network.Defines";
|
||||
|
||||
message Envelope {
|
||||
int32 type = 1;
|
||||
bytes payload = 2;
|
||||
}
|
||||
|
||||
message Vector3 {
|
||||
float x = 1;
|
||||
float y = 2;
|
||||
float z = 3;
|
||||
}
|
||||
|
||||
message LoginRequest {
|
||||
string player_id = 1;
|
||||
int32 speed = 2;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
repeated string player_id = 1;
|
||||
repeated Vector3 positions = 2;
|
||||
int32 speed = 3;
|
||||
int64 server_tick = 4;
|
||||
bool result = 5;
|
||||
}
|
||||
|
||||
message PlayerJoin {
|
||||
string player_id = 1;
|
||||
Vector3 position = 2;
|
||||
}
|
||||
|
||||
message LogoutRequest {
|
||||
string player_id = 1;
|
||||
}
|
||||
|
||||
message MoveInput {
|
||||
string player_id = 1;
|
||||
int64 tick = 2;
|
||||
float move_x = 3;
|
||||
float move_y = 4;
|
||||
}
|
||||
|
||||
message ShootInput {
|
||||
string player_id = 1;
|
||||
int64 tick = 2;
|
||||
float dir_x = 3;
|
||||
float dir_y = 4;
|
||||
string target_id = 5;
|
||||
}
|
||||
|
||||
enum CombatEventType {
|
||||
COMBAT_EVENT_TYPE_UNSPECIFIED = 0;
|
||||
COMBAT_EVENT_TYPE_HIT = 1;
|
||||
COMBAT_EVENT_TYPE_DAMAGE_APPLIED = 2;
|
||||
COMBAT_EVENT_TYPE_DEATH = 3;
|
||||
COMBAT_EVENT_TYPE_SHOOT_REJECTED = 4;
|
||||
}
|
||||
|
||||
message CombatEvent {
|
||||
int64 tick = 1;
|
||||
CombatEventType event_type = 2;
|
||||
string attacker_id = 3;
|
||||
string target_id = 4;
|
||||
int32 damage = 5;
|
||||
Vector3 hit_position = 6;
|
||||
}
|
||||
|
||||
message PlayerState {
|
||||
string player_id = 1;
|
||||
Vector3 position = 2;
|
||||
Vector3 velocity = 3;
|
||||
float rotation = 4;
|
||||
int64 tick = 5;
|
||||
int32 hp = 6;
|
||||
}
|
||||
|
||||
message Heartbeat {
|
||||
}
|
||||
|
||||
message HeartbeatResponse {
|
||||
int64 server_tick = 1;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 188a244376e8ae247b1c065b510a70d0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -7,13 +7,13 @@ namespace Network.NetworkApplication
|
||||
{
|
||||
public sealed class ClientPredictionBuffer
|
||||
{
|
||||
private readonly List<PlayerInput> pendingInputs = new();
|
||||
private readonly List<MoveInput> pendingInputs = new();
|
||||
|
||||
public long? LastAuthoritativeTick { get; private set; }
|
||||
|
||||
public IReadOnlyList<PlayerInput> PendingInputs => pendingInputs;
|
||||
public IReadOnlyList<MoveInput> PendingInputs => pendingInputs;
|
||||
|
||||
public void Record(PlayerInput input)
|
||||
public void Record(MoveInput input)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Network.NetworkApplication
|
||||
pendingInputs.Add(input);
|
||||
}
|
||||
|
||||
public bool TryApplyAuthoritativeState(PlayerState state, out IReadOnlyList<PlayerInput> replayInputs)
|
||||
public bool TryApplyAuthoritativeState(PlayerState state, out IReadOnlyList<MoveInput> replayInputs)
|
||||
{
|
||||
if (state == null)
|
||||
{
|
||||
@@ -37,7 +37,7 @@ namespace Network.NetworkApplication
|
||||
|
||||
if (LastAuthoritativeTick.HasValue && state.Tick <= LastAuthoritativeTick.Value)
|
||||
{
|
||||
replayInputs = Array.Empty<PlayerInput>();
|
||||
replayInputs = Array.Empty<MoveInput>();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -47,4 +47,4 @@ namespace Network.NetworkApplication
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Network.NetworkApplication
|
||||
private static readonly IReadOnlyDictionary<MessageType, DeliveryPolicy> DefaultPolicies =
|
||||
new Dictionary<MessageType, DeliveryPolicy>
|
||||
{
|
||||
{ MessageType.PlayerInput, DeliveryPolicy.HighFrequencySync },
|
||||
{ MessageType.MoveInput, DeliveryPolicy.HighFrequencySync },
|
||||
{ MessageType.PlayerState, DeliveryPolicy.HighFrequencySync }
|
||||
};
|
||||
|
||||
@@ -19,4 +19,4 @@ namespace Network.NetworkApplication
|
||||
: DeliveryPolicy.ReliableOrdered;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Network.Defines;
|
||||
@@ -39,9 +38,9 @@ namespace Network.NetworkApplication
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case MessageType.PlayerInput:
|
||||
case MessageType.MoveInput:
|
||||
{
|
||||
var input = PlayerInput.Parser.ParseFrom(payload);
|
||||
var input = MoveInput.Parser.ParseFrom(payload);
|
||||
streamKey = $"input:{Normalize(sender)}:{input.PlayerId}";
|
||||
sequence = input.Tick;
|
||||
return true;
|
||||
@@ -67,4 +66,4 @@ namespace Network.NetworkApplication
|
||||
return sender == null ? "unknown" : sender.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Network.Defines;
|
||||
@@ -153,7 +153,7 @@ public class NetworkManager : MonoBehaviour
|
||||
player.SyncTick(currentServerTick.Value);
|
||||
}
|
||||
|
||||
Debug.Log($"收到PlayerState::PlayerID={message.PlayerId},Position=" + message.Position.ToVector3().ToString());
|
||||
Debug.Log($"收到PlayerState::PlayerID={message.PlayerId},Position=" + message.Position.ToVector3());
|
||||
}
|
||||
|
||||
private void HandleHeartbeatResponse(byte[] data, IPEndPoint sender)
|
||||
@@ -188,20 +188,21 @@ public class NetworkManager : MonoBehaviour
|
||||
Debug.Log($"[NetworkManager] Session {lifecycleEvent.PreviousState} -> {lifecycleEvent.CurrentState} ({lifecycleEvent.Kind}) {lifecycleEvent.Reason}");
|
||||
}
|
||||
|
||||
public void SendPlayerInput(string playerId, Vector3 input)
|
||||
public void SendMoveInput(string playerId, Vector3 input)
|
||||
{
|
||||
var message = new PlayerInput()
|
||||
var message = new MoveInput
|
||||
{
|
||||
PlayerId = playerId,
|
||||
Input = ProtoExtensions.ToProtoVector3(input)
|
||||
MoveX = input.x,
|
||||
MoveY = input.z
|
||||
};
|
||||
_networkRuntime.MessageManager.SendMessage(message, MessageType.PlayerInput);
|
||||
_networkRuntime.MessageManager.SendMessage(message, MessageType.MoveInput);
|
||||
Debug.Log($"PlayerMoveSeq: {_sequence++}");
|
||||
}
|
||||
|
||||
public void SendPlayerInput(PlayerInput message)
|
||||
public void SendMoveInput(MoveInput message)
|
||||
{
|
||||
_networkRuntime.MessageManager.SendMessage(message, MessageType.PlayerInput);
|
||||
_networkRuntime.MessageManager.SendMessage(message, MessageType.MoveInput);
|
||||
Debug.Log($"PlayerMoveSeq: {_sequence++}");
|
||||
}
|
||||
|
||||
@@ -226,4 +227,4 @@ public class NetworkManager : MonoBehaviour
|
||||
_networkRuntime.MessageManager.SendMessage(request, MessageType.LogoutRequest);
|
||||
Debug.Log($"Sent logout request to player {playerId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
@@ -55,7 +55,7 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendMessage_PlayerInput_UsesSyncLanePolicy()
|
||||
public void SendMessage_MoveInput_UsesSyncLanePolicy()
|
||||
{
|
||||
var reliableTransport = new FakeTransport();
|
||||
var syncTransport = new FakeTransport();
|
||||
@@ -64,20 +64,80 @@ namespace Tests.EditMode.Network
|
||||
new MainThreadNetworkDispatcher(),
|
||||
new DefaultMessageDeliveryPolicyResolver(),
|
||||
syncTransport);
|
||||
var message = new PlayerInput
|
||||
var message = new MoveInput
|
||||
{
|
||||
PlayerId = "player-1",
|
||||
Tick = 12
|
||||
Tick = 12,
|
||||
MoveX = 1,
|
||||
MoveY = -1
|
||||
};
|
||||
|
||||
manager.SendMessage(message, MessageType.PlayerInput);
|
||||
manager.SendMessage(message, MessageType.MoveInput);
|
||||
|
||||
Assert.That(reliableTransport.SendCallCount, Is.EqualTo(0));
|
||||
Assert.That(syncTransport.SendCallCount, Is.EqualTo(1));
|
||||
|
||||
var envelope = Envelope.Parser.ParseFrom(syncTransport.LastSentData);
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.PlayerInput));
|
||||
Assert.That(PlayerInput.Parser.ParseFrom(envelope.Payload).Tick, Is.EqualTo(12));
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.MoveInput));
|
||||
Assert.That(MoveInput.Parser.ParseFrom(envelope.Payload).Tick, Is.EqualTo(12));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendMessage_ShootInput_UsesReliableLanePolicy()
|
||||
{
|
||||
var reliableTransport = new FakeTransport();
|
||||
var syncTransport = new FakeTransport();
|
||||
var manager = new MessageManager(
|
||||
reliableTransport,
|
||||
new MainThreadNetworkDispatcher(),
|
||||
new DefaultMessageDeliveryPolicyResolver(),
|
||||
syncTransport);
|
||||
var message = new ShootInput
|
||||
{
|
||||
PlayerId = "player-1",
|
||||
Tick = 15,
|
||||
DirX = 0.5f,
|
||||
DirY = 1f,
|
||||
TargetId = "enemy-1"
|
||||
};
|
||||
|
||||
manager.SendMessage(message, MessageType.ShootInput);
|
||||
|
||||
Assert.That(reliableTransport.SendCallCount, Is.EqualTo(1));
|
||||
Assert.That(syncTransport.SendCallCount, Is.EqualTo(0));
|
||||
|
||||
var envelope = Envelope.Parser.ParseFrom(reliableTransport.LastSentData);
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.ShootInput));
|
||||
Assert.That(ShootInput.Parser.ParseFrom(envelope.Payload).TargetId, Is.EqualTo("enemy-1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendMessage_CombatEvent_UsesReliableLanePolicy()
|
||||
{
|
||||
var reliableTransport = new FakeTransport();
|
||||
var syncTransport = new FakeTransport();
|
||||
var manager = new MessageManager(
|
||||
reliableTransport,
|
||||
new MainThreadNetworkDispatcher(),
|
||||
new DefaultMessageDeliveryPolicyResolver(),
|
||||
syncTransport);
|
||||
var message = new CombatEvent
|
||||
{
|
||||
Tick = 20,
|
||||
EventType = CombatEventType.DamageApplied,
|
||||
AttackerId = "player-1",
|
||||
TargetId = "enemy-1",
|
||||
Damage = 7
|
||||
};
|
||||
|
||||
manager.SendMessage(message, MessageType.CombatEvent);
|
||||
|
||||
Assert.That(reliableTransport.SendCallCount, Is.EqualTo(1));
|
||||
Assert.That(syncTransport.SendCallCount, Is.EqualTo(0));
|
||||
|
||||
var envelope = Envelope.Parser.ParseFrom(reliableTransport.LastSentData);
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.CombatEvent));
|
||||
Assert.That(CombatEvent.Parser.ParseFrom(envelope.Payload).Damage, Is.EqualTo(7));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -184,6 +244,31 @@ namespace Tests.EditMode.Network
|
||||
Assert.That(handledSpeeds, Is.EqualTo(new[] { 1, 2 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Receive_StaleMoveInput_IsDropped()
|
||||
{
|
||||
var transport = new FakeTransport();
|
||||
var manager = new MessageManager(transport, new MainThreadNetworkDispatcher());
|
||||
var handledTicks = new List<long>();
|
||||
|
||||
manager.RegisterHandler(MessageType.MoveInput, (payload, sender) =>
|
||||
{
|
||||
handledTicks.Add(MoveInput.Parser.ParseFrom(payload).Tick);
|
||||
});
|
||||
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.MoveInput, new MoveInput { PlayerId = "player-1", Tick = 8, MoveX = 1 }),
|
||||
Sender);
|
||||
manager.DrainPendingMessagesAsync().GetAwaiter().GetResult();
|
||||
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.MoveInput, new MoveInput { PlayerId = "player-1", Tick = 6, MoveX = -1 }),
|
||||
Sender);
|
||||
manager.DrainPendingMessagesAsync().GetAwaiter().GetResult();
|
||||
|
||||
Assert.That(handledTicks, Is.EqualTo(new long[] { 8 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Receive_StalePlayerState_IsDropped()
|
||||
{
|
||||
@@ -209,6 +294,31 @@ namespace Tests.EditMode.Network
|
||||
Assert.That(handledTicks, Is.EqualTo(new long[] { 8 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Receive_ShootInput_IsNotDroppedBySequenceTracker()
|
||||
{
|
||||
var transport = new FakeTransport();
|
||||
var manager = new MessageManager(transport, new MainThreadNetworkDispatcher());
|
||||
var handledTicks = new List<long>();
|
||||
|
||||
manager.RegisterHandler(MessageType.ShootInput, (payload, sender) =>
|
||||
{
|
||||
handledTicks.Add(ShootInput.Parser.ParseFrom(payload).Tick);
|
||||
});
|
||||
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.ShootInput, new ShootInput { PlayerId = "player-1", Tick = 8, DirX = 1f }),
|
||||
Sender);
|
||||
manager.DrainPendingMessagesAsync().GetAwaiter().GetResult();
|
||||
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.ShootInput, new ShootInput { PlayerId = "player-1", Tick = 6, DirY = 1f }),
|
||||
Sender);
|
||||
manager.DrainPendingMessagesAsync().GetAwaiter().GetResult();
|
||||
|
||||
Assert.That(handledTicks, Is.EqualTo(new long[] { 8, 6 }));
|
||||
}
|
||||
|
||||
private static byte[] BuildEnvelope(MessageType type, IMessage payload)
|
||||
{
|
||||
return new Envelope
|
||||
@@ -282,4 +392,4 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SharedNetworkRuntime_RoutesSyncMessagesThroughConfiguredSyncLane()
|
||||
public void SharedNetworkRuntime_RoutesMoveInputThroughConfiguredSyncLane()
|
||||
{
|
||||
var reliableTransport = new FakeTransport();
|
||||
var syncTransport = new FakeTransport();
|
||||
@@ -84,21 +84,23 @@ namespace Tests.EditMode.Network
|
||||
reliableTransport,
|
||||
new ImmediateNetworkMessageDispatcher(),
|
||||
syncTransport: syncTransport);
|
||||
var message = new PlayerInput
|
||||
var message = new MoveInput
|
||||
{
|
||||
PlayerId = "shared-player",
|
||||
Tick = 33
|
||||
Tick = 33,
|
||||
MoveX = 1f,
|
||||
MoveY = -1f
|
||||
};
|
||||
|
||||
runtime.MessageManager.SendMessage(message, MessageType.PlayerInput);
|
||||
runtime.MessageManager.SendMessage(message, MessageType.MoveInput);
|
||||
|
||||
Assert.That(reliableTransport.SendCallCount, Is.EqualTo(0));
|
||||
Assert.That(syncTransport.SendCallCount, Is.EqualTo(1));
|
||||
Assert.That(syncTransport.LastSentData, Is.Not.Null);
|
||||
|
||||
var envelope = Envelope.Parser.ParseFrom(syncTransport.LastSentData);
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.PlayerInput));
|
||||
Assert.That(PlayerInput.Parser.ParseFrom(envelope.Payload).Tick, Is.EqualTo(33));
|
||||
Assert.That(envelope.Type, Is.EqualTo((int)MessageType.MoveInput));
|
||||
Assert.That(MoveInput.Parser.ParseFrom(envelope.Payload).Tick, Is.EqualTo(33));
|
||||
}
|
||||
|
||||
private static byte[] BuildEnvelope(MessageType type, IMessage payload)
|
||||
@@ -165,4 +167,4 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,12 @@ namespace Tests.EditMode.Network
|
||||
public class SyncStrategyTests
|
||||
{
|
||||
[Test]
|
||||
public void ClientPredictionBuffer_AuthoritativeState_PrunesAcknowledgedInputs()
|
||||
public void ClientPredictionBuffer_AuthoritativeState_PrunesAcknowledgedMoveInputs()
|
||||
{
|
||||
var buffer = new ClientPredictionBuffer();
|
||||
buffer.Record(new PlayerInput { PlayerId = "player-1", Tick = 10 });
|
||||
buffer.Record(new PlayerInput { PlayerId = "player-1", Tick = 11 });
|
||||
buffer.Record(new PlayerInput { PlayerId = "player-1", Tick = 12 });
|
||||
buffer.Record(new MoveInput { PlayerId = "player-1", Tick = 10, MoveX = 1f });
|
||||
buffer.Record(new MoveInput { PlayerId = "player-1", Tick = 11, MoveX = 1f });
|
||||
buffer.Record(new MoveInput { PlayerId = "player-1", Tick = 12, MoveX = 1f });
|
||||
|
||||
var accepted = buffer.TryApplyAuthoritativeState(
|
||||
new PlayerState { PlayerId = "player-1", Tick = 11 },
|
||||
@@ -34,7 +34,7 @@ namespace Tests.EditMode.Network
|
||||
public void ClientPredictionBuffer_StaleAuthoritativeState_IsIgnored()
|
||||
{
|
||||
var buffer = new ClientPredictionBuffer();
|
||||
buffer.Record(new PlayerInput { PlayerId = "player-1", Tick = 10 });
|
||||
buffer.Record(new MoveInput { PlayerId = "player-1", Tick = 10, MoveX = 1f });
|
||||
buffer.TryApplyAuthoritativeState(new PlayerState { PlayerId = "player-1", Tick = 10 }, out _);
|
||||
|
||||
var accepted = buffer.TryApplyAuthoritativeState(
|
||||
@@ -75,7 +75,7 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ServerNetworkHost_RejectsStaleInputPerPeerWithoutCrossPeerInterference()
|
||||
public void ServerNetworkHost_RejectsStaleMoveInputPerPeerWithoutCrossPeerInterference()
|
||||
{
|
||||
var transport = new FakeTransport();
|
||||
var host = new ServerNetworkHost(transport);
|
||||
@@ -83,7 +83,7 @@ namespace Tests.EditMode.Network
|
||||
var peerB = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5002);
|
||||
var handledTicksByPeer = new Dictionary<string, List<long>>();
|
||||
|
||||
host.MessageManager.RegisterHandler(MessageType.PlayerInput, (payload, sender) =>
|
||||
host.MessageManager.RegisterHandler(MessageType.MoveInput, (payload, sender) =>
|
||||
{
|
||||
var key = sender.ToString();
|
||||
if (!handledTicksByPeer.TryGetValue(key, out var ticks))
|
||||
@@ -92,17 +92,17 @@ namespace Tests.EditMode.Network
|
||||
handledTicksByPeer.Add(key, ticks);
|
||||
}
|
||||
|
||||
ticks.Add(PlayerInput.Parser.ParseFrom(payload).Tick);
|
||||
ticks.Add(MoveInput.Parser.ParseFrom(payload).Tick);
|
||||
});
|
||||
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.PlayerInput, new PlayerInput { PlayerId = "player-a", Tick = 5 }),
|
||||
BuildEnvelope(MessageType.MoveInput, new MoveInput { PlayerId = "player-a", Tick = 5, MoveX = 1f }),
|
||||
peerA);
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.PlayerInput, new PlayerInput { PlayerId = "player-a", Tick = 4 }),
|
||||
BuildEnvelope(MessageType.MoveInput, new MoveInput { PlayerId = "player-a", Tick = 4, MoveX = -1f }),
|
||||
peerA);
|
||||
transport.EmitReceive(
|
||||
BuildEnvelope(MessageType.PlayerInput, new PlayerInput { PlayerId = "player-b", Tick = 4 }),
|
||||
BuildEnvelope(MessageType.MoveInput, new MoveInput { PlayerId = "player-b", Tick = 4, MoveY = 1f }),
|
||||
peerB);
|
||||
|
||||
Assert.That(handledTicksByPeer[peerA.ToString()], Is.EqualTo(new long[] { 5 }));
|
||||
@@ -149,4 +149,4 @@ namespace Tests.EditMode.Network
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user