summaryrefslogtreecommitdiff
path: root/NetServer.cs
diff options
context:
space:
mode:
authorSarah Bradley <git@sarahduck.ca>2023-12-01 20:33:42 -0800
committerSarah Bradley <git@sarahduck.ca>2023-12-01 20:33:42 -0800
commit2793b94040a473538f01723d5ca5f53c4535e2af (patch)
treecb30f0dae20bda6ef9d1c005325bfd9c986b3c8f /NetServer.cs
What I've got so far
Diffstat (limited to 'NetServer.cs')
-rw-r--r--NetServer.cs110
1 files changed, 110 insertions, 0 deletions
diff --git a/NetServer.cs b/NetServer.cs
new file mode 100644
index 0000000..cab6a00
--- /dev/null
+++ b/NetServer.cs
@@ -0,0 +1,110 @@
+using System.Buffers.Binary;
+using System.Collections.Concurrent;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Channels;
+
+namespace OnekoOnline.Net;
+
+static class Server
+{
+ public static bool ServerRunning = false;
+
+ static readonly ConcurrentDictionary<int, ServerUser> users = [];
+
+ public static async void Init(int port)
+ {
+ TcpListener listener = new(IPAddress.Any, port);
+ listener.Start(10);
+ ServerRunning = true;
+
+ while (ServerRunning)
+ {
+ TcpClient tcpSocket = await listener.AcceptTcpClientAsync();
+ UdpClient udpSocket = new((IPEndPoint)tcpSocket.Client.RemoteEndPoint!);
+
+ ServerUser newUser = new(tcpSocket.GetHashCode(), tcpSocket, udpSocket);
+
+ Console.WriteLine("Accepted a connection from: " + tcpSocket.Client.RemoteEndPoint);
+
+ await Task.Factory.StartNew(() => SetupUser(newUser));
+ }
+ }
+
+ static async Task SetupUser(ServerUser user)
+ {
+ await Task.WhenAny(ExchangeUserData(user), Task.Delay(7000));
+
+ if (user.ExchangedData) {
+ //Send current user data
+ foreach (ServerUser otherUser in users.Values.Where(u => u.ExchangedData)) {
+ //Send username and spritesheet
+ await NetBase.SendReliableData(new Packet(PacketType.OnekoSpritesheet, otherUser.SpriteSheet!, otherUser.Id), user.Tcp.GetStream());
+ await NetBase.SendReliableData(new Packet(PacketType.Username, Encoding.UTF8.GetBytes(otherUser.Username!), otherUser.Id), user.Tcp.GetStream());
+ //Ask users to take your data
+ await otherUser.ToSend.Writer.WriteAsync(new Packet(PacketType.Username, Encoding.UTF8.GetBytes(user.Username!), user.Id));
+ await otherUser.ToSend.Writer.WriteAsync(new Packet(PacketType.OnekoSpritesheet, user.SpriteSheet!, user.Id));
+ Console.WriteLine($"Sent {otherUser.Username}'s Data to {user.Username}");
+ }
+
+ users.GetOrAdd(user.Id, user);
+ await Task.Factory.StartNew(() => UpdateUser(user));
+ } else {
+ Console.WriteLine($"{user.Tcp.Client.RemoteEndPoint} failed to send required data, terminating connection.");
+ user.Dispose();
+ }
+ }
+
+ static async Task ExchangeUserData(ServerUser user)
+ {
+ while (!user.ExchangedData)
+ {
+ Packet packet = await NetBase.GetReliableData(user.Tcp.GetStream());
+
+ if (packet.Data.Length > 50000) break;
+
+ if (packet.Type == PacketType.Username) {
+ user.Username = Encoding.UTF8.GetString(packet.Data);
+ } else if (packet.Type == PacketType.OnekoSpritesheet) {
+ user.SpriteSheet = packet.Data;
+ }
+ }
+
+ if (!user.ExchangedData) return;
+
+ //Send ID
+ byte[] idData = new byte[sizeof(int)];
+ BinaryPrimitives.WriteInt32LittleEndian(idData, user.Id);
+ await NetBase.SendReliableData(new Packet(PacketType.UserId, idData, 0), user.Tcp.GetStream());
+
+ Console.WriteLine($"{user.Tcp.Client.RemoteEndPoint} is {user.Username}!");
+ }
+
+ static async Task UpdateUser(ServerUser user)
+ {
+ while (user.Tcp.Connected) {
+ Packet toSend = await user.ToSend.Reader.ReadAsync(user.UpdateCancel.Token);
+ await NetBase.SendReliableData(toSend, user.Tcp.GetStream(), user.UpdateCancel.Token);
+ }
+ //users.TryRemove(user.Id, out _);
+ //user.Dispose();
+ }
+}
+
+class ServerUser(int id, TcpClient tcp, UdpClient udp) : User(id), IDisposable
+{
+ //Network
+ public readonly TcpClient Tcp = tcp;
+ public readonly UdpClient Udp = udp;
+ public readonly Channel<Packet> ToSend = Channel.CreateUnbounded<Packet>();
+ public CancellationTokenSource UpdateCancel = new();
+
+ public void Dispose()
+ {
+ UpdateCancel.Cancel();
+ Tcp.Dispose();
+ Udp.Dispose();
+ }
+} \ No newline at end of file