void Process(TimeSpan time) { while (!localPackets.IsEmpty && localPackets.TryDequeue(out var local)) { LocalPlayer.ProcessPacket(local); } Action a; if (worldRequests.Count > 0 && worldRequests.TryDequeue(out a)) { a(); } //Update if (!(LocalPlayer?.World?.Paused ?? false)) { LocalPlayer?.UpdateMissionRuntime(time.TotalSeconds); } ConcurrentBag <StarSystem> toSpinDown = new ConcurrentBag <StarSystem>(); Parallel.ForEach(worlds, (world) => { if (!world.Value.Update(time.TotalSeconds)) { toSpinDown.Add(world.Key); } }); //Remove if (toSpinDown.Count > 0) { lock (availableWorlds) { foreach (var w in toSpinDown) { if (worlds[w].PlayerCount <= 0) { worlds[w].Finish(); availableWorlds.Remove(w); worlds.Remove(w); FLLog.Info("Server", $"Shut down world {w.Nickname} ({w.Name})"); } } } } processingLoop.TimeStep = worlds.Count > 0 ? RATE_60 : RATE_30; if (!running) { processingLoop.Stop(); } }
void NetThread() { EventBasedNetListener listener = new EventBasedNetListener(); int unique = Environment.TickCount; listener.ConnectionRequestEvent += request => { if (Server.ConnectedPeersCount > MaxConnections) { request.Reject(); } else { request.AcceptIfKey(AppIdentifier); } }; listener.PeerConnectedEvent += peer => { FLLog.Info("Server", $"Connected: {peer.EndPoint}"); BeginAuthentication(peer); }; listener.PeerDisconnectedEvent += (peer, info) => { FLLog.Info("Server", $"Disconnected: {peer.EndPoint}"); if (peer.Tag is Player player) { player.Disconnected(); lock (game.ConnectedPlayers) { game.ConnectedPlayers.Remove(player); } } }; listener.NetworkReceiveUnconnectedEvent += (point, reader, type) => { try { if (type == UnconnectedMessageType.Broadcast) { if (!reader.TryGetString(out string str)) { return; } if (str != LNetConst.BROADCAST_KEY) { return; } var dw = new NetDataWriter(); dw.Put((int)1); dw.Put(unique); dw.Put(game.ServerName); dw.Put(game.ServerDescription); dw.Put(game.GameData.DataVersion); dw.Put(Server.ConnectedPeersCount); dw.Put(MaxConnections); Server.SendUnconnectedMessage(dw, point); } else if (type == UnconnectedMessageType.BasicMessage) { if (!reader.TryGetUInt(out uint magic)) { return; } if (magic != LNetConst.PING_MAGIC) { return; } var dw = new NetDataWriter(); dw.Put((int)0); Server.SendUnconnectedMessage(dw, point); } } finally { reader.Recycle(); } }; listener.NetworkReceiveEvent += (peer, reader, channel, method) => { try { var pkt = Packets.Read(reader); if (peer.Tag == TagConnecting) { if (pkt is AuthenticationReplyPacket) { var auth = (AuthenticationReplyPacket)pkt; if (auth.Guid == Guid.Empty) { var dw = new NetDataWriter(); dw.Put("bad GUID"); peer.Disconnect(dw); } else { var p = new Player(new RemotePacketClient(peer), game, auth.Guid); peer.Tag = p; Task.Run(() => p.DoAuthSuccess()); lock (game.ConnectedPlayers) { game.ConnectedPlayers.Add(p); } } } else { var dw = new NetDataWriter(); dw.Put("Invalid packet"); peer.Disconnect(dw); } } else { var player = (Player)peer.Tag; //Task.Run(() => player.ProcessPacket(pkt)); player.ProcessPacket(pkt); } } catch (Exception) { throw; var dw = new NetDataWriter(); dw.Put("Packet processing error"); peer.Disconnect(dw); if (peer.Tag is Player p) { p.Disconnected(); } } finally { reader.Recycle(); } }; listener.DeliveryEvent += (peer, data) => { if (data is Action onAck) { onAck(); } }; Server = new NetManager(listener); Server.IPv6Mode = IPv6Mode.SeparateSocket; Server.UnconnectedMessagesEnabled = true; Server.BroadcastReceiveEnabled = true; Server.ChannelsCount = 3; Server.UnsyncedEvents = true; Server.Start(Port); FLLog.Info("Server", "Listening on port " + Port); var sw = Stopwatch.StartNew(); var last = 0.0; ServerLoop sendLoop = null; sendLoop = new ServerLoop((time) => { foreach (var p in Server.ConnectedPeerList) { if (p.Tag is Player player) { (player.Client as RemotePacketClient)?.Update(time.TotalSeconds); } } if (!running) { sendLoop.Stop(); } }); sendLoop.Start(); Server.Stop(); }