Beispiel #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;
                }
            }
        }