예제 #1
0
        public static void SetupConfig()
        {
            CreateIfNot(RulesPath, "1) Respect all players 2) No griefing/hacking 3) Have fun!");
            CreateIfNot(MotdPath, "This server is running Starrybound Server v%versionNum%. Type /help for a list of commands. There are currently %players% player(s) online.");

            StarryboundServer.motdData  = ReadConfigFile(MotdPath);
            StarryboundServer.rulesData = ReadConfigFile(RulesPath);

            if (File.Exists(ConfigPath))
            {
                StarryboundServer.config = ConfigFile.Read(ConfigPath);
            }

            if (StarryboundServer.IsMono && StarryboundServer.config == null)
            {
                StarryboundServer.config = new ConfigFile();
            }

            StarryboundServer.config.Write(ConfigPath);

#if DEBUG
            StarryboundServer.config.logLevel = LogType.Debug;
            StarryboundServer.logDebug("SetupConfig", "This was compiled in DEBUG, forcing debug logging!");
#endif
        }
예제 #2
0
        public void run()
        {
            try
            {
                for (;;)
                {
                    if (!this.client.connectionAlive)
                    {
                        this.client.forceDisconnect(direction, "Connection no longer alive");
                        return;
                    }


                    if (this.client.kickTargetTimestamp != 0)
                    {
                        if (this.client.kickTargetTimestamp < Utils.getTimestamp())
                        {
                            this.client.closeConnection();
                            return;
                        }
                        continue;
                    }

                    #region Process Packet
                    //Packet ID and Vaildity Check.
                    uint temp = this.incoming.ReadVarUInt32();
                    if (temp < 0 || temp > 48)
                    {
                        this.client.forceDisconnect(direction, "Sent invalid packet ID [" + temp + "].");
                        return;
                    }
                    Packet packetID = (Packet)temp;

                    //Packet Size and Compression Check.
                    bool compressed = false;
                    int  packetSize = this.incoming.ReadVarInt32();
                    if (packetSize < 0)
                    {
                        packetSize = -packetSize;
                        compressed = true;
                    }

                    //Create buffer for forwarding
                    byte[] dataBuffer = this.incoming.ReadFully(packetSize);

                    //Do decompression
                    MemoryStream ms = new MemoryStream();
                    if (compressed)
                    {
                        ZlibStream compressedStream = new ZlibStream(new MemoryStream(dataBuffer), CompressionMode.Decompress);
                        byte[]     buffer           = new byte[32768];
                        for (;;)
                        {
                            int read = compressedStream.Read(buffer, 0, buffer.Length);
                            if (read <= 0)
                            {
                                break;
                            }
                            ms.Write(buffer, 0, read);
                        }
                        ms.Seek(0, SeekOrigin.Begin);
                    }
                    else
                    {
                        ms = new MemoryStream(dataBuffer);
                    }

                    //Create packet parser
                    BinaryReader packetData = new BinaryReader(ms);
                    #endregion

                    //Return data for packet processor
                    object returnData = true;

                    if (packetID != Packet.Heartbeat && packetID != Packet.UniverseTimeUpdate)
                    {
                        if (direction == Direction.Client)
                        #region Handle Client Packets
                        {
                            #region Protocol State Security
                            ClientState curState = this.client.state;
                            if (curState != ClientState.Connected)
                            {
                                if (curState == ClientState.PendingConnect && packetID != Packet.ClientConnect)
                                {
                                    this.client.rejectPreConnected("Violated PendingConnect protocol state with " + packetID);
                                    return;
                                }
                                else if (curState == ClientState.PendingAuthentication && packetID != Packet.HandshakeResponse)
                                {
                                    this.client.rejectPreConnected("Violated PendingAuthentication protocol state with " + packetID);
                                    return;
                                }
                                else if (curState == ClientState.PendingConnectResponse)
                                {
                                    int startTime = Utils.getTimestamp();
                                    while (true)
                                    {
                                        if (this.client.state == ClientState.Connected)
                                        {
                                            break;
                                        }
                                        if (Utils.getTimestamp() > startTime + StarryboundServer.config.connectTimeout)
                                        {
                                            this.client.rejectPreConnected("Connection Failed: Server did not respond in time.");
                                            return;
                                        }
                                    }
                                }
                            }
                            #endregion

                            if (packetID == Packet.ChatSend)
                            {
                                returnData = new Packet11ChatSend(this.client, packetData, this.direction).onReceive();
                            }
                            else if (packetID == Packet.ClientConnect)
                            {
                                this.client.state = ClientState.PendingAuthentication;
                                returnData        = new Packet7ClientConnect(this.client, packetData, this.direction).onReceive();
                                MemoryStream packet      = new MemoryStream();
                                BinaryWriter packetWrite = new BinaryWriter(packet);

                                passwordSalt = Utils.GenerateSecureSalt();
                                packetWrite.WriteStarString("");
                                packetWrite.WriteStarString(passwordSalt);
                                packetWrite.WriteBE(StarryboundServer.config.passwordRounds);
                                this.client.sendClientPacket(Packet.HandshakeChallenge, packet.ToArray());
                            }
                            else if (packetID == Packet.HandshakeResponse)
                            {
                                string claimResponse = packetData.ReadStarString();
                                string passwordHash  = packetData.ReadStarString();

                                string verifyHash = Utils.StarHashPassword(StarryboundServer.config.proxyPass, this.client.playerData.account + passwordSalt, StarryboundServer.config.passwordRounds);
                                if (passwordHash != verifyHash)
                                {
                                    this.client.rejectPreConnected("Your password was incorrect.");
                                    return;
                                }

                                this.client.state = ClientState.PendingConnectResponse;
                                returnData        = false;
                            }
                            else if (packetID == Packet.WarpCommand)
                            {
                                WarpType        cmd    = (WarpType)packetData.ReadUInt32BE();
                                WorldCoordinate coord  = packetData.ReadStarWorldCoordinate();
                                string          player = packetData.ReadStarString();
                                if (cmd == WarpType.WarpToPlayerShip)
                                {
                                    Client target = StarryboundServer.getClient(player);
                                    if (target != null)
                                    {
                                        if (!this.client.playerData.canAccessShip(target.playerData))
                                        {
                                            this.client.sendChatMessage("^#5dc4f4;You cannot access this player's ship due to their ship access settings.");
                                            StarryboundServer.logDebug("ShipAccess", "Preventing " + this.client.playerData.name + " from accessing " + target.playerData.name + "'s ship.");
                                            MemoryStream packetWarp  = new MemoryStream();
                                            BinaryWriter packetWrite = new BinaryWriter(packetWarp);
                                            packetWrite.WriteBE((uint)WarpType.WarpToOwnShip);
                                            packetWrite.Write(new WorldCoordinate());
                                            packetWrite.WriteStarString("");
                                            client.sendServerPacket(Packet.WarpCommand, packetWarp.ToArray());
                                            returnData = false;
                                        }
                                        else
                                        {
                                            this.client.playerData.inPlayerShip = true;
                                        }
                                    }
                                }
                                else if (cmd == WarpType.WarpToOwnShip)
                                {
                                    this.client.playerData.inPlayerShip = true;
                                }
                                else
                                {
                                    this.client.playerData.inPlayerShip = false;
                                }
                                StarryboundServer.logDebug("WarpCommand", "[" + this.client.playerData.client + "][" + cmd + "]" + (coord != null ? "[" + coord.ToString() + "]" : "") + "[" + player + "] inPlayerShip:" + this.client.playerData.inPlayerShip);
                            }
                            else if (packetID == Packet.ModifyTileList || packetID == Packet.DamageTileGroup || packetID == Packet.DamageTile || packetID == Packet.ConnectWire || packetID == Packet.DisconnectAllWires)
                            {
                                if (!this.client.playerData.canIBuild())
                                {
                                    returnData = false;
                                }
                            }
                            else if (packetID == Packet.EntityCreate)
                            {
                                while (true)
                                {
                                    EntityType type = (EntityType)packetData.Read();
                                    if (type == EntityType.EOF)
                                    {
                                        break;
                                    }
                                    byte[] entityData = packetData.ReadStarByteArray();
                                    int    entityId   = packetData.ReadVarInt32();
                                    if (type == EntityType.Projectile)
                                    {
                                        BinaryReader entity        = new BinaryReader(new MemoryStream(entityData));
                                        string       projectileKey = entity.ReadStarString();
                                        object       projParams    = entity.ReadStarVariant();
                                        if (StarryboundServer.config.projectileBlacklist.Contains(projectileKey))
                                        {
                                            MemoryStream packet      = new MemoryStream();
                                            BinaryWriter packetWrite = new BinaryWriter(packet);
                                            packetWrite.WriteVarInt32(entityId);
                                            packetWrite.Write(false);
                                            this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray());
                                            returnData = false;
                                        }
                                        if (StarryboundServer.serverConfig.useDefaultWorldCoordinate && StarryboundServer.config.spawnWorldProtection)
                                        {
                                            if (this.client.playerData.loc != null)
                                            {
                                                if (StarryboundServer.config.projectileBlacklistSpawn.Contains(projectileKey) ^ StarryboundServer.config.projectileSpawnListIsWhitelist)
                                                {
                                                    if (StarryboundServer.spawnPlanet.Equals(this.client.playerData.loc) && !this.client.playerData.group.hasPermission("admin.spawnbuild") && !this.client.playerData.inPlayerShip)
                                                    {
                                                        MemoryStream packet      = new MemoryStream();
                                                        BinaryWriter packetWrite = new BinaryWriter(packet);
                                                        packetWrite.WriteVarInt32(entityId);
                                                        packetWrite.Write(false);
                                                        this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray());
                                                        returnData = false;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                MemoryStream packet      = new MemoryStream();
                                                BinaryWriter packetWrite = new BinaryWriter(packet);
                                                packetWrite.WriteVarInt32(entityId);
                                                packetWrite.Write(false);
                                                this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray());
                                                returnData = false;
                                            }
                                        }
                                    }
                                    else if (type == EntityType.Object || type == EntityType.Plant || type == EntityType.PlantDrop || type == EntityType.Monster)
                                    {
                                        if (!this.client.playerData.canIBuild())
                                        {
                                            MemoryStream packet      = new MemoryStream();
                                            BinaryWriter packetWrite = new BinaryWriter(packet);
                                            packetWrite.WriteVarInt32(entityId);
                                            packetWrite.Write(false);
                                            this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray());
                                            returnData = false;
                                        }
                                    }
                                }
                            }
                            else if (packetID == Packet.SpawnEntity)
                            {
                                while (true)
                                {
                                    EntityType type = (EntityType)packetData.Read();
                                    if (type == EntityType.EOF)
                                    {
                                        break;
                                    }
                                    byte[] entityData = packetData.ReadStarByteArray();
                                    if (type == EntityType.Projectile)
                                    {
                                        BinaryReader entity        = new BinaryReader(new MemoryStream(entityData));
                                        string       projectileKey = entity.ReadStarString();
                                        object       projParams    = entity.ReadStarVariant();
                                        if (StarryboundServer.config.projectileBlacklist.Contains(projectileKey))
                                        {
                                            returnData = false;
                                        }
                                        if (StarryboundServer.serverConfig.useDefaultWorldCoordinate && StarryboundServer.config.spawnWorldProtection)
                                        {
                                            if (this.client.playerData.loc != null)
                                            {
                                                if (StarryboundServer.config.projectileBlacklistSpawn.Contains(projectileKey) ^ StarryboundServer.config.projectileSpawnListIsWhitelist)
                                                {
                                                    if (StarryboundServer.spawnPlanet.Equals(this.client.playerData.loc) && !this.client.playerData.group.hasPermission("admin.spawnbuild") && !this.client.playerData.inPlayerShip)
                                                    {
                                                        returnData = false;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                returnData = false;
                                            }
                                        }
                                    }
                                    else if (type == EntityType.Object || type == EntityType.Plant || type == EntityType.PlantDrop || type == EntityType.Monster)
                                    {
                                        if (!this.client.playerData.canIBuild())
                                        {
                                            returnData = false;
                                        }
                                    }
                                }
                            }
                        }
                        #endregion
                        else
                        #region Handle Server Packets
                        {
                            if (packetID == Packet.ChatReceive)
                            {
                                returnData = new Packet5ChatReceive(this.client, packetData, this.direction).onReceive();
                            }
                            else if (packetID == Packet.ProtocolVersion)
                            {
                                uint protocolVersion = packetData.ReadUInt32BE();
                                if (protocolVersion != StarryboundServer.ProtocolVersion)
                                {
                                    MemoryStream packet      = new MemoryStream();
                                    BinaryWriter packetWrite = new BinaryWriter(packet);
                                    packetWrite.WriteBE(protocolVersion);
                                    this.client.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());

                                    this.client.rejectPreConnected("Connection Failed: Unable to handle parent server protocol version.");
                                    return;
                                }
                            }
                            else if (packetID == Packet.HandshakeChallenge)
                            {
                                string claimMessage   = packetData.ReadString();
                                string passwordSalt   = packetData.ReadStarString();
                                int    passwordRounds = packetData.ReadInt32BE();

                                MemoryStream packet       = new MemoryStream();
                                BinaryWriter packetWrite  = new BinaryWriter(packet);
                                string       passwordHash = Utils.StarHashPassword(StarryboundServer.privatePassword, passwordSalt, passwordRounds);
                                packetWrite.WriteStarString("");
                                packetWrite.WriteStarString(passwordHash);
                                this.client.sendServerPacket(Packet.HandshakeResponse, packet.ToArray());

                                returnData = false;
                            }
                            else if (packetID == Packet.ConnectResponse)
                            {
                                int startTime = Utils.getTimestamp();
                                while (true)
                                {
                                    if (this.client.state == ClientState.PendingConnectResponse)
                                    {
                                        break;
                                    }
                                    if (Utils.getTimestamp() > startTime + StarryboundServer.config.connectTimeout)
                                    {
                                        this.client.rejectPreConnected("Connection Failed: Client did not respond with handshake.");
                                        return;
                                    }
                                }
                                returnData = new Packet2ConnectResponse(this.client, packetData, this.direction).onReceive();
                            }
                            else if (packetID == Packet.WorldStart)
                            {
                                if (!this.client.playerData.sentMotd)
                                {
                                    this.client.sendChatMessage(Config.GetMotd());

                                    if (!this.client.playerData.group.hasPermission("world.build"))
                                    {
                                        this.client.sendChatMessage("^#f75d5d;" + StarryboundServer.config.buildErrorMessage);
                                    }

                                    this.client.playerData.sentMotd = true;
                                }

                                var    unk4          = packetData.ReadStarVariant();
                                var    unk3          = packetData.ReadStarVariant();
                                byte[] unk1          = packetData.ReadStarByteArray();
                                byte[] unk2          = packetData.ReadStarByteArray();
                                float  spawnX        = packetData.ReadSingleBE();
                                float  spawnY        = packetData.ReadSingleBE();
                                var    mapParamsSize = packetData.ReadStarVariant();

                                /*
                                 * for (int i = 0; i < mapParamsSize; i++)
                                 * {
                                 *  string key = packetData.ReadStarString();
                                 *  var value = packetData.ReadStarVariant();
                                 *  mapParams.Add(key, value);
                                 *  if(key == "fuel.level")
                                 *  {
                                 *      isPlayerShip++;
                                 *  }
                                 *  else if(key == "fuel.max")
                                 *  {
                                 *      isPlayerShip++;
                                 *  }
                                 * }
                                 * this.client.playerData.inPlayerShip = (isPlayerShip == 2);
                                 */
                                uint            clientID      = packetData.ReadUInt32BE();
                                bool            interpolation = packetData.ReadBoolean();
                                WorldCoordinate coords        = Utils.findGlobalCoords(unk1);
                                if (coords != null)
                                {
                                    this.client.playerData.loc = coords;
                                    StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + interpolation + ":" + clientID + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]");
                                }
                                else
                                {
                                    StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + interpolation + ":" + clientID + "] InPlayerShip:[" + this.client.playerData.inPlayerShip + "]");
                                }
                            }
                            else if (packetID == Packet.WorldStop)
                            {
                                string status = packetData.ReadStarString();
                            }
                            else if (packetID == Packet.GiveItem)
                            {
                                string name     = packetData.ReadStarString();
                                uint   count    = packetData.ReadVarUInt32();
                                var    itemDesc = packetData.ReadStarVariant();
                            }
                            else if (packetID == Packet.EnvironmentUpdate)
                            {
                                byte[] sky           = packetData.ReadStarByteArray();
                                byte[] serverWeather = packetData.ReadStarByteArray();
                                if (this.client.playerData.loc == null)
                                {
                                    WorldCoordinate coords = Utils.findGlobalCoords(sky);
                                    if (coords != null)
                                    {
                                        this.client.playerData.loc = coords;
                                        StarryboundServer.logDebug("EnvUpdate", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "]");
                                    }
                                }
                            }
                            else if (packetID == Packet.ClientContextUpdate)
                            {
                                try
                                {
                                    byte[] clientContextData = packetData.ReadStarByteArray();
                                    if (clientContextData.Length != 0)
                                    {
                                        BinaryReader clientContextReader = new BinaryReader(new MemoryStream(clientContextData));
                                        byte[]       data = clientContextReader.ReadStarByteArray();
                                        if (data.Length > 8) //Should at least be more than 8 bytes for it to contain the data we want.
                                        {
                                            BinaryReader dataReader       = new BinaryReader(new MemoryStream(data));
                                            byte         dataBufferLength = dataReader.ReadByte();
                                            if (dataBufferLength == 2)
                                            {
                                                byte arrayLength = dataReader.ReadByte();
                                                if (arrayLength == 2 || arrayLength == 4)  //Only observed these being used so far for what we want.
                                                {
                                                    byte dataType = dataReader.ReadByte(); //04 = String, 0E = CelestialLog
                                                    if (dataType == 4)
                                                    {
                                                        string string1 = dataReader.ReadStarString();
                                                        if (dataReader.BaseStream.Position != dataReader.BaseStream.Length)
                                                        {
                                                            if (string1 == "null")
                                                            {
                                                                byte[] worldHeader = dataReader.ReadStarByteArray(); //0008020A000C
                                                                byte[] worldData   = dataReader.ReadStarByteArray();
                                                                byte   typeByte    = dataReader.ReadByte();          //0E = CelestialLog
                                                                if (typeByte == 14)
                                                                {
                                                                    Dictionary <string, WorldCoordinate> log = dataReader.ReadStarCelestialLog();
                                                                    log.TryGetValue("loc", out this.client.playerData.loc);
                                                                    if (!log.TryGetValue("home", out this.client.playerData.home))
                                                                    {
                                                                        this.client.playerData.home = this.client.playerData.loc;
                                                                    }
                                                                    StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]");
                                                                    StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurHome:[" + this.client.playerData.home.ToString() + "]");
                                                                }
                                                            }
                                                        }
                                                    }
                                                    else if (dataType == 14)
                                                    {
                                                        Dictionary <string, WorldCoordinate> log = dataReader.ReadStarCelestialLog();
                                                        log.TryGetValue("loc", out this.client.playerData.loc);
                                                        if (!log.TryGetValue("home", out this.client.playerData.home))
                                                        {
                                                            this.client.playerData.home = this.client.playerData.loc;
                                                        }
                                                        StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]");
                                                        StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurHome:[" + this.client.playerData.home.ToString() + "]");
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] Failed to parse ClientContextUpdate from Server: " + e.ToString());
                                }
                            }
                            else if (packetID == Packet.EntityCreate)
                            {
                                MemoryStream sendStream = new MemoryStream();
                                BinaryWriter sendWriter = new BinaryWriter(sendStream);
                                bool         test       = true;
                                while (true)
                                {
                                    EntityType type = (EntityType)packetData.Read();
                                    if (type == EntityType.EOF)
                                    {
                                        break;
                                    }
                                    byte[] entityData = packetData.ReadStarByteArray();
                                    int    entityId   = packetData.ReadVarInt32();
                                    if (type == EntityType.Player)
                                    {
                                        byte[] buffer = new byte[16];
                                        Buffer.BlockCopy(entityData, 0, buffer, 0, 16);
                                        buffer = Utils.HashUUID(buffer);
                                        Buffer.BlockCopy(buffer, 0, entityData, 0, 16);
                                        returnData = test = false;
                                    }
                                    sendWriter.Write((byte)type);
                                    sendWriter.WriteVarUInt64((ulong)entityData.Length);
                                    sendWriter.Write(entityData);
                                    sendWriter.WriteVarInt32(entityId);
                                }
                                if (test == false)
                                {
                                    this.outgoing.WriteVarUInt32((uint)packetID);
                                    this.outgoing.WriteVarInt32((int)sendStream.Length);
                                    this.outgoing.Write(sendStream.ToArray());
                                    this.outgoing.Flush();
                                }
                            }
                        }
                        #endregion
                    }

                    //Check return data
                    if (returnData is Boolean)
                    {
                        if ((Boolean)returnData == false)
                        {
                            continue;
                        }
                    }
                    else if (returnData is int)
                    {
                        if ((int)returnData == -1)
                        {
                            this.client.forceDisconnect(direction, "Command processor requested to drop client");
                            return;
                        }
                    }

                    #region Forward Packet
                    //Write data to dest
                    this.outgoing.WriteVarUInt32((uint)packetID);
                    if (compressed)
                    {
                        this.outgoing.WriteVarInt32(-packetSize);
                        this.outgoing.Write(dataBuffer, 0, packetSize);
                    }
                    else
                    {
                        this.outgoing.WriteVarInt32(packetSize);
                        this.outgoing.Write(dataBuffer, 0, packetSize);
                    }
                    this.outgoing.Flush();
                    #endregion

                    #region Inject from Packet Queue
                    var chatbuffer = this.client.packetQueue;
                    foreach (Packet11ChatSend chatPacket in chatbuffer)
                    {
                        chatPacket.onSend();
                    }

                    this.client.packetQueue = new List <Packet11ChatSend>();
                    #endregion

                    //If disconnect was forwarded to client, lets disconnect.
                    if (packetID == Packet.ServerDisconnect && direction == Direction.Server)
                    {
                        this.client.closeConnection();
                    }
                }
            }
            catch (ThreadAbortException) { }
            catch (EndOfStreamException)
            {
                this.client.forceDisconnect(direction, "End of stream");
            }
            catch (Exception e)
            {
                if (e.InnerException != null)
                {
                    if (e.InnerException is System.Net.Sockets.SocketException)
                    {
                        this.client.forceDisconnect(direction, e.InnerException.Message);
                        return;
                    }
                }
                this.client.forceDisconnect(direction, "ForwardThread Exception: " + e.ToString());
            }
        }
예제 #3
0
        private void SourceRequest(byte[] data, EndPoint remote)
        {
            byte headerByte = data[4];

            byte[] dataArray;

            switch (headerByte)
            {
            case 0x54:
                dataArray = new byte[data.Length - 6];

                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                string text   = Encoding.UTF8.GetString(dataArray);
                string needle = "Source Engine Query";

                if (text != needle)
                {
                    StarryboundServer.logError("RCON: Received invalid A2S_INFO request: " + text + " is invalid.");
                    return;
                }
                else
                {
                    StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Matched A2S_INFO request!");
                }

                try
                {
                    byte   header      = 0x49;
                    byte   protocol    = 0x02;
                    byte[] name        = encodeString(StarryboundServer.config.serverName);
                    byte[] map         = encodeString("Starbound");
                    byte[] folder      = encodeString("na");
                    byte[] game        = encodeString("Starbound");
                    byte[] appID       = BitConverter.GetBytes(Convert.ToUInt16(1337));
                    byte   players     = Convert.ToByte((uint)StarryboundServer.clientCount);
                    byte   maxplayers  = Convert.ToByte((uint)StarryboundServer.config.maxClients);
                    byte   bots        = Convert.ToByte((uint)0);
                    byte   servertype  = Convert.ToByte('d');
                    byte   environment = Convert.ToByte((StarryboundServer.IsMono ? 'l' : 'w'));
                    byte   visibility  = Convert.ToByte((uint)(StarryboundServer.config.proxyPass == "" ? 0 : 1));
                    byte   vac         = Convert.ToByte((uint)0);
                    byte[] version     = encodeString(StarryboundServer.starboundVersion.Name);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(header);
                    s.WriteByte(protocol);
                    s.Write(name, 0, name.Length);
                    s.Write(map, 0, map.Length);
                    s.Write(folder, 0, folder.Length);
                    s.Write(game, 0, game.Length);
                    s.Write(appID, 0, appID.Length);
                    s.WriteByte(players);
                    s.WriteByte(maxplayers);
                    s.WriteByte(bots);
                    s.WriteByte(servertype);
                    s.WriteByte(environment);
                    s.WriteByte(visibility);
                    s.WriteByte(vac);
                    s.Write(version, 0, version.Length);

                    StarryboundServer.logInfo("RCON: Sending A2S_INFO Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                catch (Exception e)
                {
                    StarryboundServer.logError("RCON: Unable to send data to stream! An error occurred.");
                    StarryboundServer.logError("RCON: " + e.ToString());
                }
                break;

            case 0x55:
                StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Received A2S_PLAYER request from " + remote);

                dataArray = new byte[4];
                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                if (dataArray.SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }))
                {
                    var buffer = new byte[4];
                    new Random().NextBytes(buffer);

                    if (challengeData.ContainsKey(remote))
                    {
                        challengeData.Remove(remote);
                    }
                    challengeData.Add(remote, buffer);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(0x41);
                    s.Write(buffer, 0, 4);

                    StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Challenge Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                else
                {
                    if (!challengeData.ContainsKey(remote))
                    {
                        StarryboundServer.logError("RCON: Illegal A2S_PLAYER request received from " + remote + ". No challenge number has been issued to this address.");
                    }
                    else
                    {
                        var s = new MemoryStream();
                        s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                        s.WriteByte(0x44);

                        s.WriteByte(Convert.ToByte((uint)StarryboundServer.clientCount));

                        List <Client> clientList = StarryboundServer.getClients();

                        for (var i = 0; i < clientList.Count; i++)
                        {
                            Client client = clientList[i];
                            s.WriteByte(Convert.ToByte((uint)i));

                            byte[] name = encodeString(client.playerData.name);
                            s.Write(name, 0, name.Length);

                            byte[] score = new byte[4];
                            score = BitConverter.GetBytes((int)0);
                            s.Write(score, 0, score.Length);

                            float  seconds   = Utils.getTimestamp() - client.connectedTime;
                            byte[] connected = new byte[4];
                            connected = BitConverter.GetBytes(seconds);
                            s.Write(connected, 0, connected.Length);

                            //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "Client ID #" + i + ": " + Utils.ByteArrayToString(new byte[] { Convert.ToByte((uint)i) }) + Utils.ByteArrayToString(name) + Utils.ByteArrayToString(score) + Utils.ByteArrayToString(connected));
                        }

                        StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Response packet for " + StarryboundServer.clientCount + " player(s) to " + remote);
                        //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "RCON: Dump packet: " + Utils.ByteArrayToString(s.ToArray()));
                        udpSocket.SendTo(s.ToArray(), remote);
                    }
                }
                break;

            default:
                StarryboundServer.logError("RCON: Received unknown or unsupported header byte - " + headerByte);
                break;
            }
        }