23.08.2008, 11:12
Hello!
jtp10181 showed in a topic that there are still person which use strtok to get a nice looking command processor. But it is slow and it won't work like it should if you have more commands behind each other.
Thatswhy I decided to show a way (dcmd) which also looks gentle but is much faster then strtok only and in my opinion better organized.
Our implementation will look like this (it has protection like /meso is not allowed, but /me hello is.):
I tested (calling 1000000 times) the implementations above, without print-stuff (this would make lag, which isn't called by the function itself!) and had this results:
63 Seconds for first implementation.
18 Seconds for my implementation.
Here is my testcase:
If I add two more /commands (for example /give and /me in both implementation) the results where: 19 seconds for mine, and already 70 seconds for the first implementation.
You can see that it is much faster without extra vars and stuff.
Why is it so much faster, even in this small example?
The magic thing is using procedures and good organized if-statement, instead of lots of strtok's.
Our macro:
With parameter me,2,cmdtext will result into:
But how does this work? Lets split it:
#1 (strcmp(cmdtext, "/me", true, 2+1) == 0)
#2.1 ((cmdtext[2+1]==0)&&(dcmd_me(playerid,""))
#2.2 ((cmdtext[2+1]==32)&&(dcmd_me(playerid,cmdtext[2+2]))
If #1 is true, the beginning is /me, but this doesn't filter stuff like /meso yet.
Now #2.1 or #2.2 must be true. The #2.1 is true, if "/me" is the whole string, and dcmd_me returns true. The #2.2 returns true, if "/me " has a space after /me, so its for example "/me hello." and transfers the array beginning from the "hello" (therefor we have cmdtext[2+2]). The cool thing is, that dcmd_me won't be executed if already #1 isn't true, so it doesn't take extra space/speed.
Regards,
Jan (DracoBlue)
[Hint] This topic got lost, when updating/converting the forums, so you may find an archive at webarchive.org
jtp10181 showed in a topic that there are still person which use strtok to get a nice looking command processor. But it is slow and it won't work like it should if you have more commands behind each other.
Thatswhy I decided to show a way (dcmd) which also looks gentle but is much faster then strtok only and in my opinion better organized.
How To: [iurl=http://forum.sa-mp.com/index.php?topic=70925.msg461044#msg461044]Add Multiple Parameters[/iurl]
This way, is often used (I am not using params now, because that would decrease strtok-method again) (Remember it hasn't even protection if somebody uses commands like /meso or something like this!)pawn Code:
public OnPlayerCommandText(playerid,text[])
{
new cmd[MAX_STRING];
new tmp[MAX_STRING];
new idx;
cmd=strtok(text,idx);
if (equal(cmd,"me",true)) {
/* Ok it was a emote command */
format(tmp,sizeof(tmp),"%s",text);
strdel(tmp,0,3);
// tmp has the message now!
printf("[%d] /ME %s",playerid,tmp);
return 1;
}
if (equal(cmd,"die",true)) {
/* Ok it was a die command */
printf("[%d] /DIE",playerid);
return 1;
}
// This command is not supported.
return 0;
}
pawn Code:
#define dcmd(%1,%2,%3) if ((strcmp((%3)[1], #%1, true, (%2)) == 0) && ((((%3)[(%2) + 1] == 0) && (dcmd_%1(playerid, "")))||(((%3)[(%2) + 1] == 32) && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
dcmd_me(const playerid,const params[]) {
printf("[%d] /ME %s",playerid,params);
return true;
}
dcmd_die(const playerid,const params[]) {
// following line states, that we won't use params in that command.
#pragma unused params
printf("[%d] /DIE",playerid);
return true;
}
public OnPlayerCommandText(playerid, const cmdtext[])
{
dcmd(me,2,cmdtext);
dcmd(die,3,cmdtext);
// This command is not supported.
return 0;
}
63 Seconds for first implementation.
18 Seconds for my implementation.
Here is my testcase:
pawn Code:
OnPlayerCommandText(1,"/me looks evil to somebody.");
OnPlayerCommandText(1,"/me");
OnPlayerCommandText(1,"/me ");
OnPlayerCommandText(1,"/meso askljdaslkjdaslkjdaslkdj"); // is unknown
OnPlayerCommandText(1,"/die");
OnPlayerCommandText(1,"/die ");
OnPlayerCommandText(1,"/die jashdasjk");
You can see that it is much faster without extra vars and stuff.
Why is it so much faster, even in this small example?
The magic thing is using procedures and good organized if-statement, instead of lots of strtok's.
Our macro:
pawn Code:
#define dcmd(%1,%2,%3) if ((strcmp((%3)[1], #%1, true, (%2)) == 0) && ((((%3)[(%2) + 1] == 0) && (dcmd_%1(playerid, "")))||(((%3)[(%2) + 1] == 32) && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
pawn Code:
if ((strcmp(cmdtext, "/me", true, 2+1) == 0)&&(((cmdtext[2+1]==0)&&(dcmd_me(playerid,"")))||((cmdtext[2+1]==32)&&(dcmd_me(playerid,cmdtext[2+2]))))) return 1
#1 (strcmp(cmdtext, "/me", true, 2+1) == 0)
#2.1 ((cmdtext[2+1]==0)&&(dcmd_me(playerid,""))
#2.2 ((cmdtext[2+1]==32)&&(dcmd_me(playerid,cmdtext[2+2]))
If #1 is true, the beginning is /me, but this doesn't filter stuff like /meso yet.
Now #2.1 or #2.2 must be true. The #2.1 is true, if "/me" is the whole string, and dcmd_me returns true. The #2.2 returns true, if "/me " has a space after /me, so its for example "/me hello." and transfers the array beginning from the "hello" (therefor we have cmdtext[2+2]). The cool thing is, that dcmd_me won't be executed if already #1 isn't true, so it doesn't take extra space/speed.
Regards,
Jan (DracoBlue)
[Hint] This topic got lost, when updating/converting the forums, so you may find an archive at webarchive.org