Example #1
0
        void IOLoop()
        {
            byte[] loginPacket = CreateLoginPacket(migratedUsername ?? _username, _ver);
            ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try {
                if(EndPoint.Port > IPEndPoint.MaxPort || EndPoint.Port < IPEndPoint.MinPort) throw new SocketException(-1);
                //Do not continue if the user attempts to connect on a port larger than possible.
                ServerSocket.Connect(EndPoint);
                ServerSocket.Send(loginPacket);
            } catch( SocketException ex ) {
                Log( LogType.Error, HandleSocketError( ex.ErrorCode ), ex.ToString() );
                return;
            }

            BinaryReader reader = new BinaryReader(new NetworkStream(ServerSocket));

            while (true)
            {
                try
                {
                    byte OpCode = reader.ReadByte();
                    PacketEventArgs opcodeEvent = new PacketEventArgs((ServerPackets)OpCode);
                    Events.RaisePacketReceived(opcodeEvent);

                    switch ((ServerPackets)OpCode)
                    {
                        case ServerPackets.ServerIdentification://0x00
                            {
                                ProtocolVersion = reader.ReadByte(); // Protocol version should be seven.
                                string Name = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim();
                                string MOTD = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim();
                                if(!serverLoaded)
                                {
                                    ServerName = Name;
                                    ServerMOTD = MOTD;
                                    serverLoaded = true;
                                }
                                UserType = reader.ReadByte();//Get the type. 0x64 = Op, 0x00 = Normal user.
                            }
                            break;

                        case ServerPackets.Ping://0x01
                            break; // Server only requires we read the packet ID.

                        case ServerPackets.LevelInitialize://0x02
                            Players.Clear();
                            if(_savemap) mapStream = new MemoryStream();
                            CanReconnectAfterKick = true;
                            break;

                        case ServerPackets.LevelDataChunk://0x03
                            {
                                int chunkLength = IPAddress.HostToNetworkOrder(reader.ReadInt16()); // Length of non padded data.
                                byte[] chunkData = reader.ReadBytes(1024); // May be padded with extra data.
                                byte progress = reader.ReadByte();
                                if(_savemap) {
                                    mapStream.Write( chunkData, 0, chunkLength );
                                }
                                MapProgressEventArgs e = new MapProgressEventArgs(progress);
                                Events.RaiseMapProgress(e);
                            }
                            break;

                        case ServerPackets.LevelFinalize://0x04:
                            {
                                MapSizeX = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                MapSizeZ = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                MapSizeY = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                Connected = true; //At this state, we've loaded the map and we're ready to send chat etc.
                                if(_savemap) {
                                    Log( LogType.BotActivity, "Beginning to save map.." );
                                    mapStream.Seek(0, SeekOrigin.Begin);
                                    Map map = new Map(MapSizeX, MapSizeY, MapSizeZ);
                                    using (GZipStream decompressed = new GZipStream( mapStream,CompressionMode.Decompress ) ) {
                                        decompressed.Read( new byte[4], 0, 4 ); //Ignore size of stream.
                                        int sizeX = MapSizeX, sizeY = MapSizeY, sizeZ = MapSizeZ;
                                        for( int z = 0; z < sizeZ; z++ ) {
                                            for( int y = 0; y < sizeY; y++ ) {
                                                for( int x = 0; x < sizeX; x++ ) {
                                                    byte next = (byte)decompressed.ReadByte();
                                                    map.SetBlock( x, y, z, next );
                                                }
                                            }
                                        }
                                    }
                                    mapStream.Dispose();
                                    map.Save("map_" + DateTime.Now.ToString("ddHHmmssfffffff")); //Formatting for DateTime.
                                    map.Dispose();
                                    Log( LogType.BotActivity, "Saved map" );
                                }
                                MapLoadedEventArgs e = new MapLoadedEventArgs();
                                Events.RaiseMapLoaded(e);
                            }
                            break;

                        case ServerPackets.SetBlock://0x06:
                            {
                                int blockX = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                int blockZ = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                int blockY = IPAddress.HostToNetworkOrder(reader.ReadInt16());
                                byte blockType = reader.ReadByte();
                                BlockPlacedEventArgs e = new BlockPlacedEventArgs(blockX, blockY, blockZ, blockType);
                                Events.RaiseBlockPlaced(e);
                                if(marksLeft > 0 && blockType == 39 && CubID != null)
                                {
                                    byte id = CubID.Value;
                                    if(Players[id].X < 0 || Players[id].Y < 0 || Players[id].Z < 0) {
                                        SendMessagePacket("Error: You are too far away from the bot.");
                                        break;
                                    }

                                    if(new Vector3I(blockX, blockY, blockZ).DistanceTo(new Vector3I(
                                        (int)Players[id].X, (int)Players[id].Y, (int)Players[id].Z)) > 11) {
                                        break; //Another player probably tried placing a block somewhere else.
                                    }
                                    marks[marks.Length - marksLeft] = new Vector3I(blockX, blockY, blockZ);
                                    marksLeft--; //Go from smallest to largest.
                                    if(marksLeft == 0 && QueuedDrawer != null) {
                                        Draw(QueuedDrawer, marks, cuboidType);
                                    }
                                }
                            }
                            break;

                        case ServerPackets.SpawnPlayer://0x07:
                            {
                                byte pID = reader.ReadByte();
                                string playername = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim();
                                Players[pID] = new Player();
                                Players[pID].Name = playername;
                                Players[pID].X = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Z = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Y = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Yaw = reader.ReadByte();
                                Players[pID].Pitch = reader.ReadByte();
                                PositionEventArgs e = new PositionEventArgs(pID, Players[pID]);
                                Events.RaisePlayerMoved(e);
                            }
                            break;

                        case ServerPackets.PlayerTeleport://0x08
                            {
                                byte pID = reader.ReadByte();
                                Players[pID].X = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Z = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Y = IPAddress.HostToNetworkOrder(reader.ReadInt16()) / 32f;
                                Players[pID].Yaw = reader.ReadByte();
                                Players[pID].Pitch = reader.ReadByte();
                                PositionEventArgs e = new PositionEventArgs(pID, Players[pID]);
                                Events.RaisePlayerMoved(e);
                            }
                            break;

                        case ServerPackets.PositionandOrientationUpdate://0x09
                            {
                                byte pID = reader.ReadByte();
                                Players[pID].X += reader.ReadSByte() / 32f;
                                Players[pID].Z += reader.ReadSByte() / 32f;
                                Players[pID].Y += reader.ReadSByte() / 32f;
                                Players[pID].Yaw = reader.ReadByte();
                                Players[pID].Pitch = reader.ReadByte();
                                PositionEventArgs e = new PositionEventArgs(pID, Players[pID]);
                                Events.RaisePlayerMoved(e);
                            }
                            break;

                        case ServerPackets.PositionUpdate://0x0a
                            {
                                byte pID = reader.ReadByte();
                                Players[pID].X += (reader.ReadSByte() / 32f);
                                Players[pID].Z += (reader.ReadSByte() / 32f);
                                Players[pID].Y += (reader.ReadSByte() / 32f);
                                PositionEventArgs e = new PositionEventArgs(pID, Players[pID]);
                                Events.RaisePlayerMoved(e);
                            }
                            break;

                        case ServerPackets.OrientationUpdate://0x0b
                            {
                                byte pID = reader.ReadByte();
                                Players[pID].Yaw = reader.ReadByte();
                                Players[pID].Pitch = reader.ReadByte();
                                PositionEventArgs e = new PositionEventArgs(pID, Players[pID]);
                                Events.RaisePlayerMoved(e);
                            }
                            break;

                        case ServerPackets.DespawnPlayer://0x0c
                            {
                                byte playerID = reader.ReadByte();
                                Players.Remove(playerID); // Also sent when the player joins another map.
                            }
                            break;

                        case ServerPackets.Message://0x0d
                            {
                                reader.ReadByte(); // Most servers don't send the ID.
                                string Line = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim();
                                MessageEventArgs e = new MessageEventArgs(Line); //Raise the event, let the event handler take care of splitting.
                                Events.RaiseChatMessage(e);
                                Log( LogType.Chat, Line );

                                if (Line.Contains(_delimiter.ToString())) { //Most servers use : as the delimiter.
                                    string[] lineSplit = Line.Split(new char[] { _delimiter }, 2);
                                    string Message = Extensions.StripColors(lineSplit[1]).TrimStart(' ');
                                    string User = Extensions.StripColors(lineSplit[0]);

                                    if (!IgnoredUserList.Contains(User)) {
                                        string strippedcommandheader = Message.Split(' ')[0].ToLower();
                                        foreach(KeyValuePair<string,CommandDelegate> command in RegisteredCommands)
                                        {
                                            if(strippedcommandheader == "." + command.Key.ToLower()) {
                                                if(_requiresop) {
                                                    if(Users.Contains(User)) {
                                                        EnqueueCommand(command.Value,Line);
                                                        break;
                                                    } else {
                                                        SendMessagePacket(User +", you are not allowed to use the bot.");
                                                    }
                                                } else {
                                                    EnqueueCommand(command.Value,Line);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                                ProcessCommandQueue();
                            }
                            break;

                        case ServerPackets.DisconnectSelf://0x0e
                            {
                                string reason = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim();
                                KickedEventArgs e = new KickedEventArgs(reason, CanReconnectAfterKick);
                                Events.RaiseGotKicked(e);
                                if( _reconnectonkick == true && CanReconnectAfterKick == true ) {
                                    Log( LogType.BotActivity, "Kicked from the server. Reconnecting.", reason );
                                    CanReconnectAfterKick = false;
                                    Thread thread = new Thread(IOLoop);
                                    thread.Name = "LibClassicBotIO";
                                    thread.IsBackground = true;
                                    thread.Start();
                                } else if(_reconnectonkick == false) {
                                    Log( LogType.Warning, "Kicked from the server. Not attempting to reconnect.", reason );
                                } else {
                                    ServerSocket.Close();
                                    Log( LogType.Error, "The bot was prevented from reconnecting.", "(Kick packet received before a LevelBegin packet.)" );
                                }
                                return;
                            }

                        case ServerPackets.SetPermission://0x0f
                            UserType = reader.ReadByte();//Issued in Vanilla when someone calls /op, used in fCraft for bedrock permission checking.
                            break;

                        default:
                            throw new IOException("Unrecognised packet. Opcode: " + OpCode.ToString());
                    }
                } catch ( IOException ex ) {
                    if( _reconnectonkick == true && CanReconnectAfterKick == true ) {
                        CancelDrawer();
                        CanReconnectAfterKick = false;
                        Thread thread = new Thread(IOLoop);
                        thread.Name = "LibClassicBotIO";
                        thread.IsBackground = true;
                        thread.Start();
                    } else {
                        Log( LogType.Error, "An I/O error has occured. The connection have been closed uncleanly. Exiting the bot.", ex.ToString() );
                    }
                    return;

                }
            }
        }
Example #2
0
 /// <summary>Raises a new PacketReceived Event.</summary>
 internal void RaisePacketReceived(PacketEventArgs e)
 {
     if (PacketReceived != null) PacketReceived(null, e);
 }