258 lines
7.7 KiB
C#
258 lines
7.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using FloodSWE.Streaming;
|
|
using FloodSWE.TileGraph;
|
|
using UnityEngine;
|
|
|
|
namespace FloodSWE.Networking
|
|
{
|
|
public static class SweUdpProtocol
|
|
{
|
|
public const byte FrameType = 1;
|
|
public const byte ControlType = 2;
|
|
public const byte AckType = 3;
|
|
public const byte StateType = 4;
|
|
|
|
public static byte[] EncodeFrame(HeightmapPacket packet)
|
|
{
|
|
using (var stream = new MemoryStream(64 + (packet.Payload?.Length ?? 0)))
|
|
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
|
|
{
|
|
writer.Write(FrameType);
|
|
writer.Write(packet.FrameId);
|
|
writer.Write(packet.Tile.Lod);
|
|
writer.Write(packet.Tile.X);
|
|
writer.Write(packet.Tile.Y);
|
|
writer.Write(packet.Resolution);
|
|
writer.Write(packet.MinHeight);
|
|
writer.Write(packet.MaxHeight);
|
|
|
|
int length = packet.Payload != null ? packet.Payload.Length : 0;
|
|
writer.Write(length);
|
|
if (length > 0)
|
|
{
|
|
writer.Write(packet.Payload);
|
|
}
|
|
|
|
writer.Flush();
|
|
return stream.ToArray();
|
|
}
|
|
}
|
|
|
|
public static bool TryDecodeFrame(byte[] data, out HeightmapPacket packet)
|
|
{
|
|
packet = default;
|
|
if (data == null || data.Length < 32)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
using (var stream = new MemoryStream(data))
|
|
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
|
{
|
|
if (reader.ReadByte() != FrameType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int frameId = reader.ReadInt32();
|
|
int lod = reader.ReadInt32();
|
|
int x = reader.ReadInt32();
|
|
int y = reader.ReadInt32();
|
|
int resolution = reader.ReadInt32();
|
|
float minHeight = reader.ReadSingle();
|
|
float maxHeight = reader.ReadSingle();
|
|
int payloadLen = reader.ReadInt32();
|
|
|
|
if (payloadLen <= 0 || payloadLen > data.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
byte[] payload = reader.ReadBytes(payloadLen);
|
|
if (payload.Length != payloadLen)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
packet = new HeightmapPacket
|
|
{
|
|
FrameId = frameId,
|
|
Tile = new TileId(lod, x, y),
|
|
Resolution = resolution,
|
|
MinHeight = minHeight,
|
|
MaxHeight = maxHeight,
|
|
Payload = payload,
|
|
};
|
|
|
|
return packet.IsValid;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static byte[] EncodeControl(SweControlCommand command)
|
|
{
|
|
string json = JsonUtility.ToJson(command);
|
|
byte[] utf8 = Encoding.UTF8.GetBytes(json);
|
|
byte[] payload = new byte[utf8.Length + 1];
|
|
payload[0] = ControlType;
|
|
Buffer.BlockCopy(utf8, 0, payload, 1, utf8.Length);
|
|
return payload;
|
|
}
|
|
|
|
public static bool TryDecodeControl(byte[] data, out SweControlCommand command)
|
|
{
|
|
command = null;
|
|
if (data == null || data.Length < 2 || data[0] != ControlType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
string json = Encoding.UTF8.GetString(data, 1, data.Length - 1);
|
|
command = JsonUtility.FromJson<SweControlCommand>(json);
|
|
return command != null;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static byte[] EncodeAck(string message)
|
|
{
|
|
byte[] utf8 = Encoding.UTF8.GetBytes(message ?? string.Empty);
|
|
byte[] payload = new byte[utf8.Length + 1];
|
|
payload[0] = AckType;
|
|
Buffer.BlockCopy(utf8, 0, payload, 1, utf8.Length);
|
|
return payload;
|
|
}
|
|
|
|
public static bool TryDecodeAck(byte[] data, out string message)
|
|
{
|
|
message = null;
|
|
if (data == null || data.Length < 1 || data[0] != AckType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
message = data.Length == 1
|
|
? string.Empty
|
|
: Encoding.UTF8.GetString(data, 1, data.Length - 1);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
message = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static byte[] EncodeState(SweBoundaryStateMessage message)
|
|
{
|
|
string json = JsonUtility.ToJson(message);
|
|
byte[] utf8 = Encoding.UTF8.GetBytes(json);
|
|
byte[] payload = new byte[utf8.Length + 1];
|
|
payload[0] = StateType;
|
|
Buffer.BlockCopy(utf8, 0, payload, 1, utf8.Length);
|
|
return payload;
|
|
}
|
|
|
|
public static bool TryDecodeState(byte[] data, out SweBoundaryStateMessage message)
|
|
{
|
|
message = null;
|
|
if (data == null || data.Length < 2 || data[0] != StateType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
string json = Encoding.UTF8.GetString(data, 1, data.Length - 1);
|
|
message = JsonUtility.FromJson<SweBoundaryStateMessage>(json);
|
|
return message != null;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class SweControlCommand
|
|
{
|
|
public string command;
|
|
public string lod;
|
|
public int tileX;
|
|
public int tileY;
|
|
public int sourceId;
|
|
public float sourceLevel;
|
|
public int sinkId;
|
|
public float sinkLevel;
|
|
public string checkpoint;
|
|
public float u;
|
|
public float v;
|
|
public float radius;
|
|
public float porosity;
|
|
|
|
public string boundaryKind;
|
|
public int boundaryId;
|
|
public int enabled;
|
|
public float waterLevelM;
|
|
public float velocityUMps;
|
|
public float velocityVMps;
|
|
public float depthRateMps;
|
|
public bool replaceAll;
|
|
public bool subscribe;
|
|
public SweBoundaryProfile[] boundaries;
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class SweBoundaryProfile
|
|
{
|
|
public string boundaryKind;
|
|
public int boundaryId;
|
|
public bool enabled;
|
|
public float waterLevelM;
|
|
public float velocityUMps;
|
|
public float velocityVMps;
|
|
public float depthRateMps;
|
|
|
|
public SweBoundaryProfile Clone()
|
|
{
|
|
return new SweBoundaryProfile
|
|
{
|
|
boundaryKind = boundaryKind,
|
|
boundaryId = boundaryId,
|
|
enabled = enabled,
|
|
waterLevelM = waterLevelM,
|
|
velocityUMps = velocityUMps,
|
|
velocityVMps = velocityVMps,
|
|
depthRateMps = depthRateMps,
|
|
};
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class SweBoundaryStateMessage
|
|
{
|
|
public string messageType;
|
|
public int schemaVersion;
|
|
public string lod;
|
|
public int tileX;
|
|
public int tileY;
|
|
public SweBoundaryProfile[] boundaries;
|
|
}
|
|
}
|