Rework SWE boundary control to ghost inflows and boundary profiles

This commit is contained in:
2026-02-10 22:02:20 +01:00
parent 662278858b
commit 9aa9daee79
7 changed files with 1434 additions and 96 deletions

View File

@@ -22,12 +22,20 @@ namespace FloodSWE.Networking
private IPEndPoint serverEndpoint;
private float lastAckTimeUnscaled = -1.0f;
private float lastHelloSentTimeUnscaled = -1.0f;
private float lastStateTimeUnscaled = -1.0f;
private string lastAckMessage = "";
private SweBoundaryStateMessage lastBoundaryState;
private bool connectRequested;
public event Action<SweBoundaryStateMessage> BoundaryStateReceived;
public bool HasReceivedAck => lastAckTimeUnscaled >= 0.0f;
public float LastAckAgeSeconds => HasReceivedAck ? Time.unscaledTime - lastAckTimeUnscaled : float.PositiveInfinity;
public string LastAckMessage => lastAckMessage;
public bool HasBoundaryState => lastStateTimeUnscaled >= 0.0f;
public float LastBoundaryStateAgeSeconds =>
HasBoundaryState ? Time.unscaledTime - lastStateTimeUnscaled : float.PositiveInfinity;
public SweBoundaryStateMessage LastBoundaryState => lastBoundaryState;
public bool IsConnectionAlive => HasReceivedAck && LastAckAgeSeconds <= Mathf.Max(0.1f, ackTimeoutSeconds);
public bool IsWaitingForAck => connectRequested && !IsConnectionAlive && !HasReceivedAck;
@@ -46,7 +54,7 @@ namespace FloodSWE.Networking
private void Update()
{
PollAcks();
PollMessages();
TickKeepAlive();
}
@@ -89,7 +97,9 @@ namespace FloodSWE.Networking
serverEndpoint = null;
lastAckTimeUnscaled = -1.0f;
lastStateTimeUnscaled = -1.0f;
lastAckMessage = "";
lastBoundaryState = null;
connectRequested = false;
}
@@ -104,21 +114,79 @@ namespace FloodSWE.Networking
public void SetSourceLevel(int sourceId, float level)
{
Send(new SweControlCommand
{
command = "set_source_level",
sourceId = sourceId,
sourceLevel = level,
});
SetBoundaryProfile(
"source_area",
sourceId,
true,
0.0f,
0.0f,
0.0f,
Mathf.Max(0.0f, level));
}
public void SetSinkLevel(int sinkId, float level)
{
SetBoundaryProfile(
"sink",
sinkId,
true,
0.0f,
0.0f,
0.0f,
-Mathf.Max(0.0f, level));
}
public void SetBoundaryProfile(
string boundaryKind,
int boundaryId,
bool enabled,
float waterLevelM,
float velocityUMps,
float velocityVMps,
float depthRateMps)
{
Send(new SweControlCommand
{
command = "set_sink_level",
sinkId = sinkId,
sinkLevel = level,
command = "set_boundary_profile",
boundaryKind = boundaryKind,
boundaryId = boundaryId,
enabled = enabled ? 1 : 0,
waterLevelM = waterLevelM,
velocityUMps = velocityUMps,
velocityVMps = velocityVMps,
depthRateMps = depthRateMps,
});
}
public void SetBoundariesBulk(SweBoundaryProfile[] profiles, bool replaceAll = false)
{
if (profiles == null)
{
return;
}
Send(new SweControlCommand
{
command = "set_boundaries_bulk",
replaceAll = replaceAll,
boundaries = profiles,
});
}
public void RequestBoundaryConfig()
{
Send(new SweControlCommand
{
command = "get_boundary_config",
});
}
public void SubscribeBoundaryUpdates(bool subscribe = true)
{
Send(new SweControlCommand
{
command = "subscribe_boundary_updates",
subscribe = subscribe,
});
}
@@ -214,7 +282,7 @@ namespace FloodSWE.Networking
socket.Send(payload, payload.Length, serverEndpoint);
}
private void PollAcks()
private void PollMessages()
{
if (socket == null)
{
@@ -234,17 +302,33 @@ namespace FloodSWE.Networking
break;
}
if (!SweUdpProtocol.TryDecodeAck(payload, out string message))
if (SweUdpProtocol.TryDecodeAck(payload, out string message))
{
lastAckTimeUnscaled = Time.unscaledTime;
lastAckMessage = message ?? "";
if (verboseLogging)
{
Debug.Log($"SweQuestControlClient: ack from {sender}: {lastAckMessage}");
}
continue;
}
lastAckTimeUnscaled = Time.unscaledTime;
lastAckMessage = message ?? "";
if (verboseLogging)
if (SweUdpProtocol.TryDecodeState(payload, out SweBoundaryStateMessage state))
{
Debug.Log($"SweQuestControlClient: ack from {sender}: {lastAckMessage}");
lastStateTimeUnscaled = Time.unscaledTime;
lastBoundaryState = state;
BoundaryStateReceived?.Invoke(state);
if (verboseLogging)
{
int count = state != null && state.boundaries != null ? state.boundaries.Length : 0;
Debug.Log(
$"SweQuestControlClient: boundary state from {sender}: type={state?.messageType} entries={count}");
}
continue;
}
}
}