using LiteNetLib; using LiteNetLib.Utils; namespace OnekoOnline.Net; class Server { public static bool ServerRunning = false; readonly Dictionary users = []; readonly EventBasedNetListener Listener; readonly NetManager NetServer; public Server(int Port, int MaxConnections, string ServerPassword = "") { Listener = new(); NetServer = new(Listener); ServerRunning = NetServer.Start(Port); if (!ServerRunning) return; Listener.ConnectionRequestEvent += request => { if (NetServer.ConnectedPeersCount < MaxConnections) request.AcceptIfKey(ServerPassword); else request.Reject(); }; Listener.PeerConnectedEvent += peer => { Console.WriteLine($"New connection from {peer.EndPoint}!"); users.Add(peer.Id, new ServerUser(peer.Id, peer)); }; Listener.PeerDisconnectedEvent += (peer, info) => { Console.WriteLine($"{peer.EndPoint} Disconnected! Reason: {info.Reason}"); users.Remove(peer.Id); NetDataWriter writer = new(); //Send all users a disconnect message foreach (ServerUser user in users.Values) { user.Peer.Send(new PacketInfo(PacketType.Disconnect, peer.Id).Serialize(), DeliveryMethod.ReliableUnordered); } }; Listener.NetworkReceiveEvent += (fromPeer, dataReader, channel, DeliveryMethod) => { PacketInfo info = dataReader.GetPacketInfo(); ServerUser user = users[fromPeer.Id]; //Size limits for packet types if (info.Type == PacketType.OnekoSpritesheet && dataReader.AvailableBytes > 30000) return; else if (info.Type != PacketType.OnekoSpritesheet && dataReader.AvailableBytes > 500) return; if (info.Type == PacketType.OnekoSpritesheet) user.SpriteSheet = dataReader.GetRemainingBytes(); else if (info.Type == PacketType.Username) user.Username = dataReader.GetString(64); if (user.ExchangedData && !user.sentId) { NetDataWriter writer = new(); //Send ID writer.Put(user.Id); fromPeer.Send(writer, DeliveryMethod.ReliableUnordered); user.sentId = true; Console.WriteLine($"{fromPeer.EndPoint} is {user.Username}!"); foreach (ServerUser toSend in users.Values) { if (!toSend.ExchangedData || toSend == user) continue; //Send all current users spritesheets to this user. writer.ResetWithInfo(new PacketInfo(PacketType.OnekoSpritesheet, toSend.Id), toSend.SpriteSheet!.Length); writer.Put(toSend.SpriteSheet); fromPeer.Send(writer, DeliveryMethod.ReliableUnordered); writer.ResetWithInfo(new PacketInfo(PacketType.Username, toSend.Id)); writer.Put(toSend.Username); fromPeer.Send(writer, DeliveryMethod.ReliableUnordered); //Send all current users this users spritesheet writer.ResetWithInfo(new PacketInfo(PacketType.OnekoSpritesheet, user.Id), user.SpriteSheet!.Length); writer.Put(user.SpriteSheet); toSend.Peer.Send(writer, DeliveryMethod.ReliableUnordered); writer.ResetWithInfo(new PacketInfo(PacketType.Username, user.Id)); writer.Put(user.Username); toSend.Peer.Send(writer, DeliveryMethod.ReliableUnordered); } } }; Console.WriteLine("Server Initialized!"); } public void Poll() { NetServer.PollEvents(); } public void Disconnect() { NetServer.DisconnectAll(); } } class ServerUser(int id, NetPeer peer) : User(id), IDisposable { //Network public readonly NetPeer Peer = peer; public bool sentId = false; public void Dispose() { Peer.Disconnect(); } }