Message parsing and Player.ReadLine() method.

Message parsing and Player.ReadLine() method.

Postby dzienny » 22 May 2013, 19:14

Requires: MCDzienny version 10.1+

There's a new class that helps in parsing the command arguments. It's Misc.Message.

Code: Select all
namespace MCDzienny.Misc
{
    public class Message
    {
        // Represents a position of the reader.
        public int Pointer

        // Gets the number of arguments.
        public int Count

        // Constructor that takes the string message as argument.
        public Message(string message)

        // Reads a next argument as string. If argument doesn't exist it returns null.
        public string ReadString()

        // Same as ReadString but it returns a lower case string, or null if the argument doesn't exist.
        public string ReadStringLower()

        // Reads the rest of the arguments and returns them as string. They are seperated by spaces.
        // It returns null if there is no next argument.
        public string ReadToEnd()

        // Returns true if the next argument is an integer number. False otherwise.
        public bool IsNextInt()

        // It reads the next argument as an integer. It throws exception if the argument doesn't exist,
        // or is not a valid integer number.
        public int ReadInt()
    }
}


There's also a new method Player.ReadLine() that captures the player next chat message.
It can be escaped by a player by using "/a". In this case Player.ReadLine() will return null. Otherwise it will return the player input. Also, player can bypass it by starting his message with a dot. For example ".Hi Jack" message will be sent to global/level chat without the dot i.e. "Hi Jack", but the next statement not starting with a dot will be captured by the Player.ReadLine() method. But the player has to be informed about it, otherwise it's wise to assume they will never use /a or . escape characters on purpose.

Below is an example of a command that uses both mentioned features:
Code: Select all
namespace MCDzienny
{
    public class CmdCone : Command
    {
        public override string name { get { return "cone"; } }
        public override string shortcut { get { return ""; } }
        public override string type { get { return "build"; } }
        public override bool museumUsable { get { return false; } }
        public override LevelPermission defaultRank { get { return LevelPermission.Builder; } }
        public override bool ConsoleAccess { get { return false; } }

        public override void Use(Player p, string message)
        {
            Misc.Message msg = new Misc.Message(message);
            int radius = 0;
            int height = 0;

            // If the radius and height values are not specified, ask about them.
            if (!msg.IsNextInt())
            {
                string givenRadius = ReadConeRadius(p);
                while (true)
                {
                    if (givenRadius == null)
                        return;
                    try
                    {
                        radius = int.Parse(givenRadius.Trim());
                    }
                    catch
                    {
                        Player.SendMessage(p, "Given value is not a number.");
                        givenRadius = ReadConeRadius(p);
                        continue;
                    }
                    if (radius <= 0)
                    {
                        Player.SendMessage(p, "Radius has to be greater than 0.");
                        givenRadius = ReadConeRadius(p);
                        continue;
                    }
                    break;
                }
                Player.SendMessage(p, "Cone radius: %a" + radius.ToString());
                string givenHeight = ReadConeHeight(p);
                while (true)
                {
                    if (givenHeight == null)
                        return;
                    try
                    {
                        height = int.Parse(givenHeight.Trim());
                    }
                    catch
                    {
                        Player.SendMessage(p, "Given value is not a number.");
                        givenHeight = ReadConeHeight(p);
                        continue;
                    }
                    if (height <= 0)
                    {
                        Player.SendMessage(p, "Height has to be greater than 0.");
                        givenHeight = ReadConeHeight(p);
                        continue;
                    }
                    break;
                }
                Player.SendMessage(p, "Cone height: %a" + height.ToString());
            }
            else
            {
                // Try to parse the given radius and height values.
                radius = msg.ReadInt();
                if (radius <= 0)
                {
                    Player.SendMessage(p, "Incorrect radius value.");
                    return;
                }

                if (msg.IsNextInt())
                    height = msg.ReadInt();
                if (height <= 0)
                {
                    Player.SendMessage(p, "Incorrect height value.");
                    return;
                }
            }

            // Check if a block type was specified. If yes check if the player can place it.
            byte block = Block.Zero;
            string blockName = msg.ReadString();
            if (blockName != null)
            {
                block = Block.Parse(blockName);
                if (block == Block.Zero)
                {
                    Player.SendMessage(p, "Unknown block type: " + blockName);
                    return;
                }
                if (!Block.canPlace(p, block))
                {
                    Player.SendMessage(p, "Cannot place this block type.");
                    return;
                }
            }

            // Capture one block change then call the draw method.
            BlockCatch.CaptureOneBlock(p, DrawCone, new ExtendedDrawArgs(block, radius, height));
        }

        private string ReadConeRadius(Player p)
        {
            // Get input from the player.
            Player.SendMessage(p, "Write cone radius:");
            return p.ReadLine();
        }

        private string ReadConeHeight(Player p)
        {
            // Get input from the player.
            Player.SendMessage(p, "Write cone height:");
            return p.ReadLine();
        }

        private void DrawCone(Player p, ChangeInfo ci, ExtendedDrawArgs da)
        {
            int radius = da.Integer;
            int height = da.Integers[0];
            int x = ci.X;
            int y = ci.Y;
            int z = ci.Z;

            // If the block type was given earlier use it, otherwise use the last placed block.
            byte block = da.Type1 == Block.Zero ? ci.Type : da.Type1;
            if (!Block.canPlace(p, block))
            {
                Player.SendMessage(p, "Cannot place this block type.");
                return;
            }

            // Draw a cone to the block changes list.
            Core.PrepareCone(p, radius, height, x, y, z, block);

            // Check if player can change that many blocks. If not abort block changes.
            if (p.BlockChanges.Count > p.group.maxBlocks)
            {
                Player.SendMessage(p, "You tried to change {0} blocks. It's more than your current limit: {1}."
                    , p.BlockChanges.Count, p.group.maxBlocks);
                p.BlockChanges.Abort();
                return;
            }

            // Send block changes.
            int blockCount = p.BlockChanges.Count;
            p.BlockChanges.Commit();
            Player.SendMessage(p, "You've built a cone of radius: {0} and height: {1}, which consists of {2} blocks."
                , radius + 1, height, blockCount);

            // If the static mode is on, repeat.
            if (p.staticCommands)
                BlockCatch.CaptureOneBlock(p, DrawCone, da);
        }

        public override void Help(Player p)
        {
            Player.SendMessage(p, "/cone - draws a cone.");
            Player.SendMessage(p, "For quick drawing:");
            Player.SendMessage(p, "/cone [radius] [height] <block>");
            Player.SendMessage(p, "/cone <block>");
        }
    }
}
User avatar
dzienny
Administrator
 
Posts: 1181
Joined: 23 Jan 2011, 14:27

Re: Message parsing and Player.ReadLine() method.

Postby Conor » 22 May 2013, 20:28

How do you come up with so many useful ideas?
Conor (Conanza121)
User avatar
Conor
Coder
 
Posts: 390
Joined: 10 Oct 2012, 21:36
Location: @21Conor

Re: Message parsing and Player.ReadLine() method.

Postby dzienny » 23 May 2013, 20:09

@Conor
Well, the message parsing class was inspired by fCraft CommandReaderclass that does exactly the same thing as Misc.Message class in MCDzienny. Although, the API is slightly different, and the inner mechanics are very different.

I decided to add Player.ReadLine() method during the /mymap command development. It's because otherwise a creation of a new mymap would require a lot of arguments e.g. "/mymap new sunshine 64 64 64 mountains" and some players wouldn't be even able to type it. It's because the classic minecraft client shortens the space for the chat message by the length of a player nickname. If someone logs in with a long email address then he or she can type only relatively short chat messages. This problem was fixed in XWOM, but not everyone uses it. Anyway, Player.ReadLine() came up as a good solution.
User avatar
dzienny
Administrator
 
Posts: 1181
Joined: 23 Jan 2011, 14:27

Re: Message parsing and Player.ReadLine() method.

Postby Conor » 23 May 2013, 21:00

dzienny wrote:@Conor
Well, the message parsing class was inspired by fCraft CommandReaderclass that does exactly the same thing as Misc.Message class in MCDzienny. Although, the API is slightly different, and the inner mechanics are very different.

I decided to add Player.ReadLine() method during the /mymap command development. It's because otherwise a creation of a new mymap would require a lot of arguments e.g. "/mymap new sunshine 64 64 64 mountains" and some players wouldn't be even able to type it. It's because the classic minecraft client shortens the space for the chat message by the length of a player nickname. If someone logs in with a long email address then he or she can type only relatively short chat messages. This problem was fixed in XWOM, but not everyone uses it. Anyway, Player.ReadLine() came up as a good solution.


Ahh I understand, thats cool :)
Conor (Conanza121)
User avatar
Conor
Coder
 
Posts: 390
Joined: 10 Oct 2012, 21:36
Location: @21Conor


Return to Knowledge Base

Who is online

Users browsing this forum: No registered users and 1 guest

cron