This commit is contained in:
SepComet 2026-04-06 12:23:09 +08:00
parent 3446dcd6f1
commit a1ede230bb
4 changed files with 47 additions and 16 deletions

View File

@ -5,7 +5,8 @@
"Bash(openspec status:*)",
"Bash(openspec instructions:*)",
"Bash(dotnet build:*)",
"Bash(dotnet test:*)"
"Bash(dotnet test:*)",
"Bash(dotnet Temp/Bin/Debug/Network.EditMode.Tests/Network.EditMode.Tests.dll)"
]
},
"outputStyle": "default"

View File

@ -1,22 +1,60 @@
using System.Collections.Generic;
using System.Linq;
using Network.Defines;
namespace Network.NetworkApplication
{
/// <summary>
/// Resolves the delivery policy for each <see cref="MessageType"/>.
/// Policies are intentionally explicit here so that adding a new <see cref="MessageType"/>
/// requires an intentional decision rather than silently falling through to a default.
/// </summary>
public sealed class DefaultMessageDeliveryPolicyResolver : IMessageDeliveryPolicyResolver
{
private static readonly IReadOnlyDictionary<MessageType, DeliveryPolicy> DefaultPolicies =
private static readonly IReadOnlyDictionary<MessageType, DeliveryPolicy> Policies =
new Dictionary<MessageType, DeliveryPolicy>
{
// High-frequency sync lane: latest-wins, stale-drop.
// These messages are sent every frame and a stale value is never useful.
{ MessageType.MoveInput, DeliveryPolicy.HighFrequencySync },
{ MessageType.PlayerState, DeliveryPolicy.HighFrequencySync }
{ MessageType.PlayerState, DeliveryPolicy.HighFrequencySync },
// Reliable ordered lane: guaranteed delivery, ordered.
// ShootInput carries player intent; losing or reordering it changes gameplay outcomes.
{ MessageType.ShootInput, DeliveryPolicy.ReliableOrdered },
// CombatEvent is a server-authoritative result; clients must receive it reliably
// and in order to maintain consistent HP/death state.
{ MessageType.CombatEvent, DeliveryPolicy.ReliableOrdered },
// PlayerJoin carries spawn data that the client needs to instantiate a player.
// Reliable ordered ensures the client receives it before gameplay begins.
{ MessageType.PlayerJoin, DeliveryPolicy.ReliableOrdered },
// Login/logout are session-control messages that must not be lost or reordered.
{ MessageType.LoginRequest, DeliveryPolicy.ReliableOrdered },
{ MessageType.LoginResponse, DeliveryPolicy.ReliableOrdered },
{ MessageType.LogoutRequest, DeliveryPolicy.ReliableOrdered },
// Heartbeat carries server tick used for clock sync; a missing sample is
// simply a lost sample — no value in stale delivery.
{ MessageType.Heartbeat, DeliveryPolicy.ReliableOrdered },
{ MessageType.HeartbeatResponse, DeliveryPolicy.ReliableOrdered },
};
public DeliveryPolicy Resolve(MessageType messageType)
{
return DefaultPolicies.TryGetValue(messageType, out var policy)
? policy
: DeliveryPolicy.ReliableOrdered;
if (Policies.TryGetValue(messageType, out var policy))
{
return policy;
}
// A new MessageType was added without an explicit policy decision.
// Fail fast so the omission is noticed rather than silently defaulting.
throw new System.ArgumentException(
$"MessageType '{messageType}' has no assigned {nameof(DeliveryPolicy)}. " +
"Add an explicit entry in the policy dictionary.",
nameof(messageType));
}
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using Network.NetworkHost;
using Network.NetworkTransport;
@ -63,8 +62,6 @@ namespace Network.NetworkApplication
ServerAuthoritativeCombatConfiguration authoritativeCombat = null,
IAuthoritativeMovementWorldValidator authoritativeMovementWorldValidator = null)
{
ValidateDualPortConfiguration(reliablePort, syncPort);
transportFactory ??= static port => new KcpTransport(port);
var reliableTransport = transportFactory(reliablePort)
@ -91,11 +88,6 @@ namespace Network.NetworkApplication
authoritativeMovementWorldValidator ?? PermissiveAuthoritativeMovementWorldValidator.Instance);
}
public static Task<ServerRuntimeHandle> StartServerRuntimeAsync(ServerRuntimeConfiguration configuration)
{
return ServerRuntimeEntryPoint.StartAsync(configuration);
}
private static void ValidateDualPortConfiguration(int reliablePort, int? syncPort)
{
if (reliablePort <= 0)

View File

@ -24,7 +24,7 @@ namespace Tests.EditMode.Network
TransportFactory = port => CreateTransport(createdTransports, port)
};
using var runtime = NetworkIntegrationFactory.StartServerRuntimeAsync(configuration).GetAwaiter().GetResult();
using var runtime = ServerRuntimeEntryPoint.StartAsync(configuration).GetAwaiter().GetResult();
Assert.That(createdTransports.Keys, Is.EquivalentTo(new[] { 9000 }));
Assert.That(runtime.IsRunning, Is.True);