Пример #1
0
        void AcceptConnection()
        {
            Socket newSocket;

            try
            {
                if (!listener.Server.IsBound)
                {
                    return;
                }

                newSocket = listener.AcceptSocket();
            }
            catch (Exception e)
            {
                /* TODO: Could have an exception here when listener 'goes away' when calling AcceptConnection! */
                /* Alternative would be to use locking but the listener doesn't go away without a reason. */
                //Log.Write("server", "Accepting the connection failed.", e);
                return;
            }

            var newConn = new ServerConnectoinDefault()
            {
                Socket = newSocket
            };

            try
            {
                newConn.Socket.Blocking = false;
                newConn.Socket.NoDelay  = true;

                // assign the player number.
                newConn.PlayerIndex = ChooseFreePlayerIndex();
                SendData(newConn.Socket, BitConverter.GetBytes(ProtocolVersion.Version));
                SendData(newConn.Socket, BitConverter.GetBytes(newConn.PlayerIndex));
                PreConns.Add(newConn);

                // Dispatch a handshake order
                var request = new HandshakeRequest
                {
                    Mod     = ModData.Manifest.Id,
                    Version = ModData.Manifest.Metadata.Version,
                    Map     = LobbyInfo.GlobalSettings.Map
                };

                DispatchOrdersToClient(newConn, 0, 0, new ServerOrderDefault("HandshakeRequest", request.Serialize()).Serialize());
            }
            catch (Exception e)
            {
                DropClient(newConn);
                //Log.Write("server", "Dropping client {0} because handshake failed: {1}", newConn.PlayerIndex.ToString(CultureInfo.InvariantCulture), e);
            }
        }
Пример #2
0
        public void StartGame()
        {
            listener.Stop();

            Console.WriteLine("[{0}] Game started", DateTime.Now.ToString(ServerSettings.TimestampFormat));

            // Drop any unvalidated clients
            foreach (var c in PreConns.ToArray())
            {
                DropClient(c);
            }

            // Drop any players who are not ready
            foreach (var c in Conns.Where(c => GetClient(c).IsInvalid).ToArray())
            {
                SendOrderTo(c, "ServerError", "You have been kicked from the server!");
                DropClient(c);
            }

            // HACK: Turn down the latency if there is only one real player
            if (LobbyInfo.NonBotClients.Count() == 1)
            {
                LobbyInfo.GlobalSettings.OrderLatency = 1;
            }

            SyncLobbyInfo();
            State = ServerState.GameStarted;

            foreach (var c in Conns)
            {
                foreach (var d in Conns)
                {
                    DispatchOrdersToClient(c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF });
                }
            }

            DispatchOrders(null, 0,
                           new ServerOrderDefault("StartGame", "").Serialize());

            foreach (var t in serverTraits.WithInterface <IStartGame <ClientDefault, ClientPingDefault> >())
            {
                t.GameStarted(this);
            }
        }
Пример #3
0
        public ServerDefault(IPEndPoint endpoint, ServerSettings serverSettings, ModData modData, bool dedicated)
        {
            listener = new TcpListener(endpoint);
            listener.Start();
            var localEndpoint = (IPEndPoint)listener.LocalEndpoint;

            Ip             = localEndpoint.Address;
            Port           = localEndpoint.Port;
            Dedicated      = dedicated;
            ServerSettings = serverSettings;

            ServerSettings.Name = Engine.Settings.SanitizedServerName(ServerSettings.Name);

            ModData = modData;

            randomSeed = (int)DateTime.Now.ToBinary();

            // UPnP is only supported for servers created by the game client.
            //if (!dedicated && ServerSettings.AllowPortForward)
            //    UPnP.ForwardPort(ServerSettings.ListenPort, ServerSettings.ExternalPort).Wait();

            foreach (var trait in modData.Manifest.ServerTraits)
            {
                serverTraits.Add(modData.ObjectCreator.CreateObject <ServerTrait>(trait));
            }

            LobbyInfo = new Session <ClientDefault, ClientPingDefault>
            {
                GlobalSettings =
                {
                    RandomSeed         = randomSeed,
                    Map                = serverSettings.Map,
                    ServerName         = serverSettings.Name,
                    EnableSingleplayer = serverSettings.EnableSingleplayer || !dedicated,
                    GameUid            = Guid.NewGuid().ToString()
                }
            };

            new Thread(_ =>
            {
                foreach (var t in serverTraits.WithInterface <INotifyServerStart <ClientDefault, ClientPingDefault> >())
                {
                    t.ServerStarted(this);
                }

                //Log.Write("server", "Initial mod: {0}", ModData.Manifest.Id);
                //Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);

                var timeout = serverTraits.WithInterface <ITick <ClientDefault, ClientPingDefault> >().Min(t => t.TickTimeout);
                for (;;)
                {
                    var checkRead = new List <Socket>();
                    if (State == ServerState.WaitingPlayers)
                    {
                        checkRead.Add(listener.Server);
                    }

                    checkRead.AddRange(Conns.Select(c => c.Socket));
                    checkRead.AddRange(PreConns.Select(c => c.Socket));

                    if (checkRead.Count > 0)
                    {
                        Socket.Select(checkRead, null, null, timeout);
                    }

                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        break;
                    }

                    foreach (var s in checkRead)
                    {
                        if (s == listener.Server)
                        {
                            AcceptConnection();
                            continue;
                        }

                        var preConn = PreConns.SingleOrDefault(c => c.Socket == s);
                        if (preConn != null)
                        {
                            preConn.ReadData(this);
                            continue;
                        }

                        var conn = Conns.SingleOrDefault(c => c.Socket == s);
                        if (conn != null)
                        {
                            conn.ReadData(this);
                        }
                    }

                    foreach (var t in serverTraits.WithInterface <ITick <ClientDefault, ClientPingDefault> >())
                    {
                        t.Tick(this);
                    }

                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        //if (!dedicated && ServerSettings.AllowPortForward)
                        //    UPnP.RemovePortForward().Wait();
                        break;
                    }
                }

                foreach (var t in serverTraits.WithInterface <INotifyServerShutdown <ClientDefault, ClientPingDefault> >())
                {
                    t.ServerShutdown(this);
                }

                PreConns.Clear();
                Conns.Clear();
                try { listener.Stop(); }
                catch { }
            })
            {
                IsBackground = true
            }.Start();
        }
Пример #4
0
        public void DropClient(IServerConnectoin <ClientDefault, ClientPingDefault> toDrop)
        {
            if (!PreConns.Remove(toDrop))
            {
                Conns.Remove(toDrop);

                var dropClient = LobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex);
                if (dropClient == null)
                {
                    return;
                }

                var suffix = "";
                if (State == ServerState.GameStarted)
                {
                    suffix = dropClient.IsObserver ? " (Spectator)" :  "";
                }
                SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix));

                // Send disconnected order, even if still in the lobby
                DispatchOrdersToClients(toDrop, 0, new ServerOrderDefault("Disconnected", "").Serialize());

                LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
                LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex);

                // Client was the server admin
                // TODO: Reassign admin for game in progress via an order
                if (Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
                {
                    // Remove any bots controlled by the admin
                    LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex);

                    var nextAdmin = LobbyInfo.Clients.Where(c1 => c1.Bot == null)
                                    .MinByOrDefault(c => c.Index);

                    if (nextAdmin != null)
                    {
                        nextAdmin.IsAdmin = true;
                        SendMessage("{0} is now the admin.".F(nextAdmin.Name));
                    }
                }

                DispatchOrders(toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf });

                // All clients have left: clean up
                if (!Conns.Any())
                {
                    foreach (var t in serverTraits.WithInterface <INotifyServerEmpty <ClientDefault, ClientPingDefault> >())
                    {
                        t.ServerEmpty(this);
                    }
                }

                if (Conns.Any() || Dedicated)
                {
                    SyncLobbyClients();
                }

                if (!Dedicated && dropClient.IsAdmin)
                {
                    Shutdown();
                }
            }

            try
            {
                toDrop.Socket.Disconnect(false);
            }
            catch { }
        }