-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement Flakkari4Unity library
- Loading branch information
1 parent
f7d8292
commit ceb142b
Showing
5 changed files
with
907 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
using System; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using UnityEngine; | ||
|
||
using Flk_API = Flakkari4Unity.API; | ||
using CurrentProtocol = Flakkari4Unity.Protocol.V1; | ||
using System.Collections.Generic; | ||
|
||
public class NetworkClient : MonoBehaviour | ||
{ | ||
private UdpClient udpClient; | ||
private IPEndPoint serverEndpoint; | ||
private readonly float keepAliveInterval = 3; | ||
[SerializeField] private string serverIP = "127.0.0.1"; | ||
[SerializeField] private int serverPort = 54000; | ||
[SerializeField] private string gameName = "R-Type"; | ||
[SerializeField] private bool enable; | ||
|
||
public NetworkClient(string serverIP, int serverPort, string gameName) | ||
{ | ||
this.serverIP = serverIP; | ||
this.serverPort = serverPort; | ||
this.gameName = gameName; | ||
enable = true; | ||
} | ||
|
||
void Start() | ||
{ | ||
if (!enable) | ||
{ | ||
Destroy(this); | ||
return; | ||
} | ||
|
||
udpClient = new UdpClient(); | ||
serverEndpoint = new IPEndPoint(IPAddress.Parse(serverIP), serverPort); | ||
|
||
udpClient.BeginReceive(OnReceive, null); | ||
|
||
byte[] packet = Flk_API.APIClient.ReqConnect(gameName); | ||
udpClient.Send(packet, packet.Length, serverEndpoint); | ||
InvokeRepeating(nameof(ReqKeepAlive), keepAliveInterval, keepAliveInterval); | ||
} | ||
|
||
public bool Enable | ||
{ | ||
get => enable; | ||
set => enable = value; | ||
} | ||
|
||
internal void Send(byte[] packet) | ||
{ | ||
if (udpClient != null) | ||
{ | ||
udpClient.Send(packet, packet.Length, serverEndpoint); | ||
} | ||
else | ||
{ | ||
Debug.LogError("UDP client is not initialized."); | ||
} | ||
} | ||
|
||
private void ReqKeepAlive() | ||
{ | ||
byte[] packet = Flk_API.APIClient.ReqKeepAlive(); | ||
udpClient.Send(packet, packet.Length, serverEndpoint); | ||
} | ||
|
||
private void OnReceive(IAsyncResult result) | ||
{ | ||
if (!enable) | ||
return; | ||
|
||
try | ||
{ | ||
byte[] receivedData = udpClient.EndReceive(result, ref serverEndpoint); | ||
Flk_API.APIClient.Reply(receivedData, out List<CurrentProtocol.CommandId> commandId, out List<uint> sequenceNumber, out List<byte[]> payload); | ||
|
||
for (int i = 0; i < commandId.Count; i++) | ||
{ | ||
switch (commandId[i]) | ||
{ | ||
case CurrentProtocol.CommandId.REP_CONNECT: | ||
Debug.Log("REP_CONNECT message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REP_HEARTBEAT: | ||
Debug.Log("REP_HEARTBEAT message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REQ_ENTITY_SPAWN: | ||
Debug.Log("REQ_ENTITY_SPAWN message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REQ_ENTITY_UPDATE: | ||
Debug.Log("REQ_ENTITY_UPDATE message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REQ_ENTITY_DESTROY: | ||
Debug.Log("REQ_ENTITY_DESTROY message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REP_USER_UPDATES: | ||
Debug.Log("REP_USER_UPDATES message received from the server."); | ||
break; | ||
case CurrentProtocol.CommandId.REP_USER_UPDATE: | ||
Debug.Log("REP_USER_UPDATE message received from the server."); | ||
break; | ||
default: | ||
Debug.LogWarning("Unknown command ID received from the server."); | ||
break; | ||
} | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Debug.LogError("Error in OnReceive: " + e.Message); | ||
} | ||
udpClient.BeginReceive(OnReceive, null); | ||
} | ||
|
||
private void OnApplicationQuit() | ||
{ | ||
if (!enable) | ||
return; | ||
enable = false; | ||
|
||
udpClient.Close(); | ||
Debug.Log("UDP client closed."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using UnityEngine; | ||
|
||
using CurrentProtocol = Flakkari4Unity.Protocol.V1; | ||
|
||
namespace Flakkari4Unity.API | ||
{ | ||
public class APIClient : MonoBehaviour | ||
{ | ||
/// <summary> | ||
/// Creates a REQ_CONNECT message to connect to the server. | ||
/// </summary> | ||
/// <param name="gameName">The name of the game to connect to.</param> | ||
/// <returns>A byte array representing the serialized REQ_CONNECT message.</returns> | ||
public static byte[] ReqConnect(string gameName) | ||
{ | ||
Debug.Log("REQ_CONNECT message sent to the server."); | ||
return CurrentProtocol.Packet.Serialize( | ||
CurrentProtocol.Priority.HIGH, | ||
CurrentProtocol.CommandId.REQ_CONNECT, | ||
System.Text.Encoding.UTF8.GetBytes(gameName) | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a REQ_HEARTBEAT message to keep the connection alive. | ||
/// </summary> | ||
/// <returns>A byte array representing the serialized REQ_HEARTBEAT message.</returns> | ||
/// <remarks> | ||
/// This message is sent to the server at regular intervals to keep the connection alive. | ||
/// </remarks> | ||
public static byte[] ReqKeepAlive() | ||
{ | ||
// Debug.Log("REQ_HEARTBEAT message sent to the server."); | ||
return CurrentProtocol.Packet.Serialize( | ||
CurrentProtocol.Priority.LOW, | ||
CurrentProtocol.CommandId.REQ_HEARTBEAT | ||
); | ||
} | ||
|
||
public static byte[] ReqUserUpdates(List<CurrentProtocol.Event> events, Dictionary<CurrentProtocol.EventId, float> axisEvents) | ||
{ | ||
byte[] eventCountBytes = BitConverter.GetBytes((ushort)events.Count); | ||
byte[] serializedEvents = CurrentProtocol.Event.Serialize(events); | ||
byte[] axisEventCountBytes = BitConverter.GetBytes((ushort)axisEvents.Count); | ||
byte[] serializedAxisEvents = CurrentProtocol.Event.Serialize(axisEvents); | ||
|
||
byte[] payload = ConcatByteArrays(eventCountBytes, serializedEvents); | ||
payload = ConcatByteArrays(payload, axisEventCountBytes); | ||
payload = ConcatByteArrays(payload, serializedAxisEvents); | ||
|
||
Debug.Log("REQ_USER_UPDATE message sent to the server."); | ||
return CurrentProtocol.Packet.Serialize( | ||
CurrentProtocol.Priority.HIGH, | ||
CurrentProtocol.CommandId.REQ_USER_UPDATES, | ||
payload | ||
); | ||
} | ||
|
||
public static byte[] ReqUserUpdate(CurrentProtocol.EventId id, CurrentProtocol.EventState state) | ||
{ | ||
CurrentProtocol.Event _event = new() | ||
{ | ||
id = id, | ||
state = state | ||
}; | ||
|
||
Debug.Log("REQ_USER_UPDATE message sent to the server."); | ||
return CurrentProtocol.Packet.Serialize( | ||
CurrentProtocol.Priority.HIGH, | ||
CurrentProtocol.CommandId.REQ_USER_UPDATE, | ||
CurrentProtocol.Event.Serialize(_event) | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Processes the received data and extracts the command ID, sequence number, and message. | ||
/// </summary> | ||
/// <param name="receivedData">The byte array containing the received data.</param> | ||
/// <param name="commandIds">The extracted command IDs from the received data.</param> | ||
/// <param name="sequenceNumbers">The extracted sequence numbers from the received data.</param> | ||
/// <param name="payloads">The extracted payloads from the received data.</param> | ||
public static void Reply(byte[] receivedData, out List<CurrentProtocol.CommandId> commandIds, out List<uint> sequenceNumbers, out List<byte[]> payloads) | ||
{ | ||
commandIds = new List<CurrentProtocol.CommandId>(); | ||
sequenceNumbers = new List<uint>(); | ||
payloads = new List<byte[]>(); | ||
|
||
while (receivedData.Length > 0) | ||
{ | ||
CurrentProtocol.Packet.Deserialize(receivedData, out CurrentProtocol.CommandId commandId, out uint sequenceNumber, out byte[] payload); | ||
|
||
Debug.Log($"[RECEIVED] CommandId: {commandId}, delay: {sequenceNumber - (uint)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()} ms, payload: {payload?.Length} bytes"); | ||
|
||
commandIds.Add(commandId); | ||
sequenceNumbers.Add(sequenceNumber); | ||
payloads.Add(payload); | ||
|
||
int headerSize = Marshal.SizeOf<CurrentProtocol.Header>(); | ||
receivedData = receivedData.Skip(headerSize + (payload?.Length ?? 0)).ToArray(); | ||
} | ||
} | ||
|
||
private static byte[] ConcatByteArrays(byte[] first, byte[] second) | ||
{ | ||
byte[] result = new byte[first.Length + second.Length]; | ||
Buffer.BlockCopy(first, 0, result, 0, first.Length); | ||
Buffer.BlockCopy(second, 0, result, first.Length, second.Length); | ||
return result; | ||
} | ||
} | ||
} // namespace Flakkari4Unity.API |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using UnityEngine; | ||
|
||
public class Entity : MonoBehaviour | ||
{ | ||
public ulong Id; | ||
} |
Oops, something went wrong.