1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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();
}
}
|