Пример #1
0
 internal void UpdateStreamLogInvokable(GameAction gameAction, NetworkPlayer player, bool isSending)
 {
     if (!InvokeRequired) UpdateStreamLog(gameAction, player, isSending); else Invoke((MethodInvoker)(() => UpdateStreamLog(gameAction, player, isSending))); //allows other threads to update this form
 }
Пример #2
0
 private void UpdateStreamLog(GameAction gameAction, NetworkPlayer player, bool isSending)
 {
     //here we can look at the ActionType and decide if we dont want to spam the log, such as for PlayerMove
     if (gameAction.ActionType == ActionType.PlayerMove && !cbShowPlayerMove.Checked) return;
     try
     {
         lbTcpStream.Items.Add(string.Format("{0} [{1}] {2} ({3}b) {4}", isSending ? "SEND" : "RECV", player.Id, player.UserName, gameAction.DataLength, gameAction));
         if (lbTcpStream.Items.Count > MAX_STREAM_LOG_LENGTH) lbTcpStream.Items.RemoveAt(0);
         lbTcpStream.TopIndex = lbTcpStream.Items.Count - 1;
     }
     catch (Exception ex)
     {
         Misc.MessageError("Error updating server console stream: " + ex.Message);
     }
 }
Пример #3
0
        // ReSharper restore FunctionNeverReturns
        private static void PlayerThread(NetworkPlayer player)
        {
            NetworkStream clientStream;

            //make all the introductions. we do this before sending the world so the client doesn't see them as new connections
            foreach (var otherPlayer in Players.Values)
            {
                try
                {
                    new Connect(otherPlayer.Id, otherPlayer.UserName, otherPlayer.Coords) { ConnectedPlayer = player, Immediate = true }.Send();
                }
                catch (Exception ex)
                {
                    WriteToServerConsoleLog(string.Format("{0} {1} caused an exception and was removed: {2}", player.UserName, player.IpAddress, ex.Message));
            #if DEBUG
                    WriteToServerConsoleLog(ex.StackTrace);
            #endif
                }

                new Connect(player.Id, player.UserName, player.Coords) { ConnectedPlayer = otherPlayer }.Send();
            }

            try
            {
                Players.TryAdd(player.Id, player); //note: it is not possible for the add to fail on ConcurrentDictionary, see: http://www.albahari.com/threading/part5.aspx#_Concurrent_Collections
                UpdateServerConsolePlayerList();

                var getWorld = new GetWorld { ConnectedPlayer = player };
                getWorld.Send();
                WriteToServerConsoleLog(String.Format("World send complete to {0} ({1} compressed, {2} uncompressed)", player.IpAddress, getWorld.DataLength, getWorld.UncompressedLength));

                //create a thread to handle communication with connected client
                player.TcpClient.NoDelay = true;
                clientStream = player.TcpClient.GetStream();
            }
            catch (Exception ex)
            {
                HandleNetworkError(player, ex);
                return;
            }

            var actionTypebytes = new byte[sizeof(ushort)];
            try
            {
                if (!string.IsNullOrWhiteSpace(Config.MOTD)) new ServerMsg(Config.MOTD, player).Send();

                while (true)
                {
                    Thread.Sleep(10); //bm: polling is expensive. don't remove this or the server will pin your machine when only a couple users are online
                    GameAction gameAction;
                    while (player.SendQueue.Count > 0 && player.SendQueue.TryDequeue(out gameAction))
                    {
                        gameAction.Immediate = true;
                        gameAction.Send();
                    }

                    if (!clientStream.DataAvailable) continue;
                    var bytesRead = 0;
                    while (bytesRead < actionTypebytes.Length) bytesRead += clientStream.Read(actionTypebytes, bytesRead, actionTypebytes.Length - bytesRead);
                    var actionType = (ActionType)BitConverter.ToUInt16(actionTypebytes, 0);
                    switch (actionType)
                    {
                        case ActionType.AddBlock:
                            gameAction = new AddBlock();
                            break;
                        case ActionType.AddBlockItem:
                            gameAction = new AddBlockItem();
                            break;
                        case ActionType.AddBlockMulti:
                            gameAction = new AddBlockMulti();
                            break;
                        case ActionType.AddCuboid:
                            gameAction = new AddCuboid();
                            break;
                        case ActionType.AddProjectile:
                            gameAction = new AddProjectile();
                            break;
                        case ActionType.AddStaticItem:
                            gameAction = new AddStaticItem();
                            break;
                        case ActionType.AddStructure:
                            gameAction = new AddStructure();
                            break;
                        case ActionType.ChatMsg:
                            gameAction = new ChatMsg();
                            break;
                        case ActionType.Disconnect:
                            gameAction = new Disconnect();
                            break;
                        case ActionType.PickupBlockItem:
                            gameAction = new PickupBlockItem();
                            break;
                        case ActionType.PlayerInfo:
                            gameAction = new PlayerInfo();
                            break;
                        case ActionType.PlayerMove:
                            gameAction = new PlayerMove();
                            break;
                        case ActionType.PlayerOption:
                            gameAction = new PlayerOption();
                            break;
                        case ActionType.RemoveBlock:
                            gameAction = new RemoveBlock();
                            break;
                        case ActionType.RemoveBlockItem:
                            gameAction = new RemoveBlockItem();
                            break;
                        case ActionType.RemoveBlockMulti:
                            gameAction = new RemoveBlockMulti();
                            break;
                        case ActionType.ServerCommand:
                            gameAction = new ServerCommand();
                            break;
                        case ActionType.Connect:
                        case ActionType.ServerMsg:
                        case ActionType.ServerSync:
                        case ActionType.GetWorld:
                            throw new Exception(string.Format("Server should not receive action type: {0}", actionType));
                        case ActionType.Error:
                            var bytes = 0;
                            while (clientStream.ReadByte() != -1)
                            {
                                bytes++;
                            }
                            throw new Exception("GameAction 'Error' received. " + bytes + " byte(s) remained in the stream.");
                        default:
                            throw new Exception(string.Format("Unknown action type: {0}", actionType));
                    }
                    gameAction.ConnectedPlayer = player;
                    gameAction.Receive();
                    if (HasServerConsole && CaptureIncoming) //only stream messages if there is a console window and it has requested to display them
                    {
                        _serverConsole.UpdateStreamLogInvokable(gameAction, player, false);
                    }
                    if (actionType == ActionType.Disconnect) return;
                }
            }
            catch (Exception ex)
            {
                HandleNetworkError(player, ex);
            }
        }
Пример #4
0
        // ReSharper restore FunctionNeverReturns
        private static void ListenForNewConnectionThread()
        {
            try
            {
                _tcpListener.Start();
            }
            catch (SocketException ex)
            {
                //todo: this will cause hard crash on the client, need a nicer way for the client to handle errors here
                if (ex.ErrorCode == 10048) throw new Exception("Only one server allowed at a time.");
            }

            while (true)
            {
                TcpClient client;
                System.Net.EndPoint endPoint;
                //blocks until a client has connected to the server
                try
                {
                    client = _tcpListener.AcceptTcpClient();
                    client.GetStream().WriteTimeout = 30000;
                    endPoint = client.Client.RemoteEndPoint;
                }
                catch
                {
                    WriteToServerConsoleLog("Failed to accept connection");
                    continue;
                }

                try
                {
                    WriteToServerConsoleLog(string.Format("Accepting connection from {0}", endPoint));
                    var connect = new Connect();
                    connect.AcceptNewConnection(client); //backdoor constructor because a player does not exist yet

                    var player = new NetworkPlayer(_nextPlayerId, connect.UserName, client) {Coords = new Coords(WorldData.SizeInBlocksX / 2f, 0, WorldData.SizeInBlocksZ / 2f)};
                    player.Coords.Yf = WorldData.Chunks[player.Coords].HeightMap[player.Coords.Xblock % Chunk.CHUNK_SIZE, player.Coords.Zblock % Chunk.CHUNK_SIZE] + 1; //start player on block above the surface
                    new Connect(player.Id, player.UserName, player.Coords) { ConnectedPlayer = player, Immediate = true }.Send();
                    _nextPlayerId++;

                    WriteToServerConsoleLog(String.Format("{0} (id {1}, ip {2}) Connected", player.UserName, player.Id, player.IpAddress));
                    var tcpThread = new Thread(() => PlayerThread(player)) { IsBackground = true, Name = "PlayerThread" };
                    tcpThread.Start();
                }
                catch (Exception ex)
                {
                    WriteToServerConsoleLog(string.Format("Failed to accept connection from {0}: {1}", endPoint, ex.Message));
                }
            }
            // ReSharper disable FunctionNeverReturns
        }
Пример #5
0
 internal static void WriteToServerStreamLog(GameAction gameAction, NetworkPlayer player, bool isSending)
 {
     _serverConsole.UpdateStreamLogInvokable(gameAction, player, isSending);
 }
Пример #6
0
        internal static void HandleNetworkError(NetworkPlayer player, Exception ex)
        {
            NetworkPlayer removedPlayer;
            if (Players.TryRemove(player.Id, out removedPlayer))
            {
                UpdateServerConsolePlayerList();
                WriteToServerConsoleLog(string.Format("{0} {1} caused an exception and was removed: {2}", player.UserName, player.IpAddress, ex.Message));
            #if DEBUG
                WriteToServerConsoleLog(ex.StackTrace);
            #endif
                foreach (var otherPlayer in Players.Values)
                {
                    new Disconnect(player.Id, "Network Error") { ConnectedPlayer = otherPlayer }.Send(); //inform other connected players of this player disconnect
                }
            }

            lock (player.TcpClient)
            {
                if (player.TcpClient.Connected)
                {
                    player.TcpClient.GetStream().Close();
                    player.TcpClient.Close();
                }
            }
        }