[Tutorial] Explanation for sscanf2 and ZCMD
#1

Introduction
Tired of these newbies using strcmp along with strtok. When will they learn? They say it's too hard to learn sscanf2 and zcmd. I thought it was hard too, but I had to focus, take a coffee and look the code. I learnt it in 2 minutes. I will teach you how to use ZCMD as COMMAND PROCESSORS and with sscanf2 to help us to split the parameters.

What we will need?
For this tutorial you need to download the plugin sscanf2 and the include zcmd

Sscanf2: http://forum.sa-mp.com/showthread.ph...hlight=sscanf2
Zcmd: http://forum.sa-mp.com/showthread.ph...highlight=zcmd

There is also a function version of sscanf2, no need to download anything just copy & paste in your gamemode it and sscanf2 is ready to go, but it's slow, probably just slow as strtok so for your own good im not posting it.

Remember zcmd can be implemented in apart functions so they should NOT be inside any callback, so if you are not going to use strcmp to process commands you can delete 'OnPlayerCommandText' as we won't use it

Let's get to work

To make a basic command without parameters, you will first see this.
pawn Код:
COMMAND:heal(playerid, params[]) // 'heal' is the command, so you type /heal and this will be called
{
     SetPlayerHealth( playerid, 100.00 ); // Set players health
     return true; // Returning a value is VERY important ! Your commands won't work if you don't do so
}
It works the SAME way as strcmp command just change the start to COMMAND:...., and code like you would always do in PAWN.

However, if you want to heal other player, the thing gets more complex.

pawn Код:
COMMAND:healplayer(playerid, params[]) // hence we've changed to 'healplayer'
{
     new id; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "u", id)) return SendClientMessage(playerid,0xFFFFFFFF, "Incomplete input");
     SetPlayerHealth(id, 100.00);
     return 1;
}
Now the explanation
pawn Код:
if (sscanf(params, "u", id)) return SendClientMessage(playerid,0xFFFFFFFF, "Incomplete input");
As first, we need to put always that to split the parameters, if they weren't there it will return something (in this case 'Incomplete value' error.

In every command, it should be "if (sscanf(params," untill that point. Then you will need to choose a operator. Where "u" means a playerid OR a part of a name.

We can also use "q" and "r" for player names / ids.
We use "i" or "d" for numbers.
We use "s[size]" for strings.
We use "x" for hexadecimals
We use "f" for floats (health, positions and armour)

More operators can be also found in the official sscanf2 thread.

Also it's important to contain the parameters after the operators.
For example, a common mistake is to copy paste the previous command, and change the functions to make it a different command, but if this command has more parameters it will fail.

Example:
pawn Код:
COMMAND:healplayer(playerid, params[]) // hence we've changed to 'healplayer'
{
     new id, Float:ammount; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "uf", id)) return SendClientMessage(playerid,0xFFFFFFFF, "Incomplete input");
     SetPlayerHealth(id, ammount);
     return 1;
}
Do you spot the error? I do, do you? Probably not.
pawn Код:
new id, ammount; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "uf", id)) return SendClientMessage(playerid,0xFFFFFFFF, "Incomplete input");
Here it checks if 'id' is not put, but what about 'ammount'? If you don't put the 'id' parameter it will say Incomplete input, but if you don't put ammount it will keep processing, and probably cause a bug. Therefore, the right usage is.

pawn Код:
COMMAND:healplayer(playerid, params[]) // hence we've changed to 'healplayer'
{
     new id, ammount; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "uf", id, ammount)) return SendClientMessage(playerid,0xFFFFFFFF, "Incomplete input");
     SetPlayerHealth(id, ammount);
     return 1;
}
While you more play with it, you will learn HOW easy it's to deal with.
After you've defined the parameters and used sscanf to check them, theire automatically READY TO USE!

Now let's make a /report command for our final challenge.
If you don't understand, please don't go further and re-read.

pawn Код:
COMMAND:report(playerid, params[])
{
   new id, reason[128]; // Strings are usually text, and they need a size. Make them 128, NOT 256!
   if (sscanf(params, "us[128]", id, reason)) return SendClientMessage(playerid, 0xFFFFFFFF,"report > incorrect usage");
   new string[128]; // you should know how to work with strings already
   format(string, 128, "report > you've reported playerid %i for %s", id, reason); // we format it
   SendClientMessage(playerid, 0xFFFFFFFF, string); // and we send the string
   return true;
}
This will make a 'fake' report message, just saying you report someone for a specific reason but it doesn't send a message to admins. Just a example.

pawn Код:
if (sscanf(params, "us[128]", id, reason)) return SendClientMessage(playerid, 0xFFFFFFFF,"report > incorrect usage");
Why it says a [128]?. When dealing with sscanf, you need to specify string sizes, or it will return a warning in RCON console and it will spam your console. Also it will have to match with string size declaration.
You can't have this:

pawn Код:
new string[32];
if (sscanf(params, "s[64]")) return 1;
Since 64 is not 32.

Also remember you can't use OnPlayerCommandText when you use shis system

That's all for now
I hope you've enjoy and learnt from my tutorial.
Made by Admantis.
Reply
#2

Very nice work, I will sure be linking people here, who have no clue how to use these tools.
Reply
#3

I heard YCMD was faster than zcmd.
Reply
#4

Quote:
Originally Posted by Retardedwolf
Посмотреть сообщение
I heard YCMD was faster than zcmd.
zcmd: "clean, easy to read, short and efficent command processor"

Not bad, will help lot of newbies.
Reply
#5

About time someone posted a (decent) tutorial on this, though a few things:

1. Like RetardedWolf said, YCMD is faster then ZCMD. Nor is sscanf a command processor

2. This code:
pawn Код:
new id, ammount; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "uf", id, ammount))
'amount' is an integer, but you try to store a float in it.

3. You forgot to post that you can't use OnPlayerCommandText anymore when using ZCMD, you could also explain something about OnPlayerCommandReceived and OnPlayerCommandPerformed.
Reply
#6

Quote:
Originally Posted by Hiddos
Посмотреть сообщение
About time someone posted a (decent) tutorial on this, though a few things:

1. Like RetardedWolf said, YCMD is faster then ZCMD. Nor is sscanf a command processor

2. This code:
pawn Код:
new id, ammount; // Here we will define ALL our parameters like 'id', 'heal ammount', 'reason', and others.
     if (sscanf(params, "uf", id, ammount))
'amount' is an integer, but you try to store a float in it.

3. You forgot to post that you can't use OnPlayerCommandText anymore when using ZCMD, you could also explain something about OnPlayerCommandReceived and OnPlayerCommandPerformed.
Sorry about my errors, but I meant zcmd as the processor and sscanf2 as the tool to split the parameters.

Also that code 'ammount' is meant to be a float, because armour ammounts are floats, not integers.
Reply
#7

You spell "amount" incorrectly, and you show this example:

pawn Код:
new string[64];
if (sscanf(params, "s[32]")) return 1;
There's no point in using sscanf if you're just parsing one value (that isn't a userid/name) as you can use strval(params) or just directly use the params variable.
Reply
#8

Quote:
Originally Posted by Calg00ne
Посмотреть сообщение
You spell "amount" incorrectly, and you show this example:

pawn Код:
new string[64];
if (sscanf(params, "s[32]")) return 1;
There's no point in using sscanf if you're just parsing one value (that isn't a userid/name) as you can use strval(params) or just directly use the params variable.
Of course. I just gave a quick example, but thanks for pointing that out.
Reply
#9

Quote:
Originally Posted by admantis
Посмотреть сообщение
Introduction
You can't have this:

pawn Код:
new string[64];
if (sscanf(params, "s[32]")) return 1;
Since 64 is not 32.
You CAN do that, since the size you have to specify is not the size of the array but the size of the input you are expecting to go through the function. In both cases, if the size of the input is greater than the size you specified, the server console will give you a warning.

Quote:
Originally Posted by admantis
Посмотреть сообщение
Sorry about my errors, but I meant zcmd as the processor and sscanf2 as the tool to split the parameters.

Also that code 'ammount' is meant to be a float, because armour ammounts are floats, not integers.
It should be:
pawn Код:
new Float:ammount;
Reply
#10

Oh right lol I didn't realise, I edit it.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)