예제 #1
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 < 1 || 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;
                                        }
                                    }
                                }
                                StarryboundServer.logDebug("WarpCommand", "[" + this.client.playerData.client + "][" + cmd + "]" + (coord != null ? "[" + coord.ToString() + "]" : "") + "[" + player + "]");
                            }
                            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.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;
                                }

                                byte[] planet = packetData.ReadStarByteArray();
                                byte[] worldStructure = packetData.ReadStarByteArray();
                                byte[] sky = packetData.ReadStarByteArray();
                                byte[] serverWeather = packetData.ReadStarByteArray();
                                float spawnX = packetData.ReadSingleBE();
                                float spawnY = packetData.ReadSingleBE();
                                uint mapParamsSize = packetData.ReadVarUInt32();
                                Dictionary<string, object> mapParams = new Dictionary<string, object>();
                                int isPlayerShip = 0;
                                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 bool1 = packetData.ReadBoolean();
                                WorldCoordinate coords = Utils.findGlobalCoords(sky);
                                if (coords != null)
                                {
                                    this.client.playerData.loc = coords;
                                    StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + bool1 + ":" + clientID + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]");
                                }
                                else
                                    StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + bool1 + ":" + 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

                    //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());
            }
        }
예제 #2
0
        public void run()
        {
            try
            {
                for (;;)
                {
                    if (!this.mParent.connectionAlive)
                    {
                        this.mParent.forceDisconnect("Connection Lost");
                        return;
                    }

                    if (this.mParent.kickTargetTimestamp != 0)
                    {
                        if (this.mParent.kickTargetTimestamp < Utils.getTimestamp())
                        {
                            this.mParent.forceDisconnect("Kicked from server");
                            return;
                        }
                        continue;
                    }

                    #region Process Packet
                    //Packet ID and Vaildity Check.
                    uint temp = this.mInput.ReadVarUInt32();
                    if (temp < 1 || temp > 48)
                    {
                        this.mParent.errorDisconnect(mDirection, "Sent invalid packet ID [" + temp + "].");
                        return;
                    }
                    Packet packetID = (Packet)temp;

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

                    //Create buffer for forwarding
                    byte[] dataBuffer = this.mInput.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 (mDirection == Direction.Client)
                        #region Handle Client Packets
                        {
                            #region Protocol State Security
                            ClientState curState = this.mParent.clientState;
                            if (curState != ClientState.Connected)
                            {
                                if (curState == ClientState.PendingConnect && packetID != Packet.ClientConnect)
                                {
                                    this.mParent.forceDisconnect("Violated PendingConnect protocol state with " + packetID);
                                }
                                else if (curState == ClientState.PendingAuthentication && packetID != Packet.HandshakeResponse)
                                {
                                    this.mParent.forceDisconnect("Violated PendingAuthentication protocol state with " + packetID);
                                }
                                else if (curState == ClientState.PendingConnectResponse)
                                {
                                    this.mParent.forceDisconnect("Violated PendingConnectResponse protocol state with " + packetID);
                                }
                            }
                            #endregion

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

                                passwordSalt = Utils.GenerateSecureSalt();
                                packetWrite.WriteStarString("");
                                packetWrite.WriteStarString(passwordSalt);
                                packetWrite.WriteBE(StarryboundServer.config.passwordRounds);
                                this.mParent.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.mParent.playerData.account + passwordSalt, StarryboundServer.config.passwordRounds);
                                if (passwordHash != verifyHash)
                                {
                                    this.mParent.rejectPreConnected("Your password was incorrect.");
                                }

                                this.mParent.clientState = ClientState.PendingConnectResponse;
                                returnData = false;
                            }
                            else if (packetID == Packet.WarpCommand)
                            {
                                uint warp = packetData.ReadUInt32BE();
                                WorldCoordinate coord = packetData.ReadStarWorldCoordinate();
                                string player = packetData.ReadStarString();
                                WarpType cmd = (WarpType)warp;
                                if (cmd == WarpType.WarpToHomePlanet)
                                {
                                    this.mParent.playerData.inPlayerShip = false;
                                }
                                else if (cmd == WarpType.WarpToOrbitedPlanet)
                                {
                                    this.mParent.playerData.inPlayerShip = false;
                                }
                                else if (cmd == WarpType.WarpToOwnShip)
                                {
                                    this.mParent.playerData.inPlayerShip = true;
                                }
                                else if (cmd == WarpType.WarpToPlayerShip)
                                {
                                    this.mParent.playerData.inPlayerShip = true;
                                }

                                StarryboundServer.logDebug("WarpCommand", "[" + this.mParent.playerData.client + "][" + warp + "]" + (coord != null ? "[" + coord.ToString() + "]" : "") + "[" + player + "]");
                            }
                            else if (packetID == Packet.ModifyTileList || packetID == Packet.DamageTileGroup || packetID == Packet.DamageTile || packetID == Packet.ConnectWire || packetID == Packet.DisconnectAllWires)
                            {
                                if (!this.mParent.playerData.canBuild) continue;
                                if (this.mParent.playerData.loc != null)
                                {
                                    string planetCheck = this.mParent.playerData.loc.ToString();
                                    string spawnPlanet = StarryboundServer.serverConfig.defaultWorldCoordinate;

                                    if (StarryboundServer.serverConfig.defaultWorldCoordinate.Split(':').Length == 5) spawnPlanet = spawnPlanet + ":0";

                                    if ((planetCheck == spawnPlanet) && !this.mParent.playerData.group.hasPermission("admin.spawnbuild") && !this.mParent.playerData.inPlayerShip)
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                        #endregion
                        else
                        #region Handle Server Packets
                        {
                            if (packetID == Packet.ChatReceive)
                            {
                                returnData = new Packet5ChatReceive(this.mParent, packetData, this.mDirection).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.mParent.sendClientPacket(Packet.ProtocolVersion, packet.ToArray());

                                    this.mParent.rejectPreConnected("Starrybound Server was unable to handle the parent server protocol version.");
                                    returnData = false;
                                }
                            }
                            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.config.serverPass, StarryboundServer.config.serverAccount + passwordSalt, passwordRounds);
                                packetWrite.WriteStarString("");
                                packetWrite.WriteStarString(passwordHash);
                                this.mParent.sendServerPacket(Packet.HandshakeResponse, packet.ToArray());

                                returnData = false;
                            }
                            else if (packetID == Packet.ConnectResponse)
                            {
                                while (this.mParent.clientState != ClientState.PendingConnectResponse) { } //TODO: needs timeout
                                returnData = new Packet2ConnectResponse(this.mParent, packetData, this.mDirection).onReceive();
                            }
                            else if (packetID == Packet.WorldStart)
                            {
                                if (!this.mParent.playerData.sentMotd)
                                {
                                    this.mParent.sendChatMessage(Config.GetMotd());
                                    this.mParent.playerData.sentMotd = true;
                                }

                                byte[] planet = packetData.ReadStarByteArray();
                                byte[] worldStructure = packetData.ReadStarByteArray();
                                byte[] sky = packetData.ReadStarByteArray();
                                byte[] serverWeather = packetData.ReadStarByteArray();
                                float spawnX = packetData.ReadSingleBE();
                                float spawnY = packetData.ReadSingleBE();
                                uint mapParamsSize = packetData.ReadVarUInt32();
                                Dictionary<string, object> mapParams = new Dictionary<string, object>();
                                for (int i = 0; i < mapParamsSize; i++)
                                {
                                    mapParams.Add(packetData.ReadStarString(), packetData.ReadStarVariant());
                                }
                                uint clientID = packetData.ReadUInt32BE();
                                bool bool1 = packetData.ReadBoolean();
                                WorldCoordinate coords = Utils.findGlobalCoords(sky);
                                if (coords != null)
                                {
                                    this.mParent.playerData.loc = coords;
                                    StarryboundServer.logDebug("WorldStart", "[" + this.mParent.playerData.client + "][" + bool1 + ":" + clientID + "] CurLoc:[" + this.mParent.playerData.loc.ToString() + "][" + this.mParent.playerData.inPlayerShip + "]");
                                }
                            }
                            else if (packetID == Packet.WorldStop)
                            {
                                string status = packetData.ReadStarString();
                            }
                            else if (packetID == Packet.GiveItem)
                            {
                                string name = packetData.ReadStarString();
                                uint count = packetData.ReadVarUInt32();
                                List<object> itemDesc = packetData.ReadStarVariant();
                            }
                            else if (packetID == Packet.EnvironmentUpdate)
                            {
                                byte[] sky = packetData.ReadStarByteArray();
                                byte[] serverWeather = packetData.ReadStarByteArray();
                                /*WorldCoordinate coords = Utils.findGlobalCoords(sky);
                                if (coords != null)
                                {
                                    this.mParent.playerData.loc = coords;
                                    StarryboundServer.logDebug("EnvUpdate", "[" + this.mParent.playerData.client + "] CurLoc:[" + this.mParent.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.mParent.playerData.loc);
                                                                    if (!log.TryGetValue("home", out this.mParent.playerData.home))
                                                                        this.mParent.playerData.home = this.mParent.playerData.loc;
                                                                    StarryboundServer.logDebug("ClientContext", "[" + this.mParent.playerData.client + "] CurLoc:[" + this.mParent.playerData.loc.ToString() + "][" + this.mParent.playerData.inPlayerShip + "]");
                                                                    StarryboundServer.logDebug("ClientContext", "[" + this.mParent.playerData.client + "] CurHome:[" + this.mParent.playerData.home.ToString() + "]");
                                                                }
                                                            }
                                                        }
                                                    }
                                                    else if (dataType == 14)
                                                    {
                                                        Dictionary<string, WorldCoordinate> log = dataReader.ReadStarCelestialLog();
                                                        log.TryGetValue("loc", out this.mParent.playerData.loc);
                                                        if (!log.TryGetValue("home", out this.mParent.playerData.home))
                                                            this.mParent.playerData.home = this.mParent.playerData.loc;
                                                        StarryboundServer.logDebug("ClientContext", "[" + this.mParent.playerData.client + "] CurLoc:[" + this.mParent.playerData.loc.ToString() + "][" + this.mParent.playerData.inPlayerShip + "]");
                                                        StarryboundServer.logDebug("ClientContext", "[" + this.mParent.playerData.client + "] CurHome:[" + this.mParent.playerData.home.ToString() + "]");
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    StarryboundServer.logException("[" + this.mParent.playerData.client + "] Failed to parse ClientContextUpdate from Server: " + e.Message);
                                }
                            }
                        }
                        #endregion
                    }

                    #if DEBUG
                    if(packetID != Packet.Heartbeat)
                    {
                        //if (ms.Position != ms.Length)
                            //StarryboundServer.logDebug("ForwardThread", "[" + this.mParent.playerData.client + "] [" + this.mDirection.ToString() + "][" + packetID + "] failed parse (" + ms.Position + " != " + ms.Length + ")");
                        //StarryboundServer.logDebug("ForwardThread", "[" + this.mParent.playerData.client + "] [" + this.mDirection.ToString() + "][" + packetID + "] Dumping " + ms.Length + " bytes: " + Utils.ByteArrayToString(ms.ToArray()));
                    }
                    #endif

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

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

                    //If disconnect was forwarded to client, lets disconnect.
                    if(packetID == Packet.ServerDisconnect && mDirection == Direction.Server)
                    {
                        this.mParent.forceDisconnect();
                    }
                }
            }
            catch (EndOfStreamException)
            {
                this.mParent.forceDisconnect();
            }
            catch (Exception e)
            {
                this.mParent.errorDisconnect(mDirection, "ForwardThread Exception: " + e.ToString());
            }
        }