[Include] rCmd.inc - Easiest way to create commands!
#1

Introduction

You're probably like "Oh no, another command system!" - Yes, but this one is different than all others and I'm pretty sure you'll like it! You can use dynamic parameters in your command function which makes everything faster and easier to use for you. The best thing is, in this new version, sscanf2 plugin is integrated and it automatically makes use of it. See more below!

Syntax

Код:
rCmd["specifiers"]->commandname(playerid, success, ...)
NEW (IMPORTANT NOTES):
  • You can use all sscanf specifiers in the specifiers input, yes, literally whole sscanf.
  • Note the quotes around specifiers in this new version. It's not necessary, but when you use brackets for optional parameters, it will give you errors without the quotes.
  • You have to use & in front of all non-array variables (floats, integers, ..., NOT playerid and success) because DynamicParams.inc is passes the address of the value. If you skip this, the value of the integer/float will be wrong. Example:
    Код:
    rCmd["us[24]"]->setname(playerid, success, &targetid, name[]) {
    	// ...
    	return 1;
    }
Specifiers

Simple answer, sscanf is integrated with this new version, so just use it as you would use sscanf, it will behave the same, without any problems.


Example(s)

pawn Код:
rCmd["uiI(500)"]->giveweapon(playerid, success, &targetid, &weaponid, &ammo) {
    if(!success) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: /giveweapon [player id/name] [weapon] [ammo (default 500)]");
    if(targetid == INVALID_PLAYER_ID) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player is not connected!");
   
    GivePlayerWeapon(targetid, weaponid, ammo);
    SendClientMessage(playerid, -1, "You gave the player a weapon!");
    return 1;
}
Note the beastliness of sscanf integrated (with optional parameters and stuff).

pawn Код:
rCmd["us[24]"]->setname(playerid, success, &targetid, name[]) {
    if(!success) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: /setname [player id/name] [name]");
    if(targetid == INVALID_PLAYER_ID) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player is not connected!");
   
    SetPlayerName(targetid, name);
    SendClientMessage(playerid, -1, "You changed the players name!");
    return 1;
}
Please make sure to use & before all your non-array variables (integers, floats, ..., NOT playerid and success).

pawn Код:
rCmd["iI(-1)I(-1)"]->vehicle(playerid, success, &model, &color1, &color2) {
    if(!success) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: /vehicle [model] [color 1 (default -1)] [color 2 (default -1)]");
    if(!(400 <= model <= 611)) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Invalid vehicle model!");
   
    new Float: x, Float: y, Float: z;
    GetPlayerPos(playerid, x, y, z);
    CreateVehicle(model, x, y, z, 0.0, color1, color2, 60);
    SendClientMessage(playerid, -1, "You spawned a vehicle!");
   
    return 1;
}
Beautiful, isn't it?

pawn Код:
rCmd[]->time(playerid) {
    new
        szTime[32]
    ;
    gettime(szTime[0], szTime[1], szTime[2]);
    format(szTime, sizeof(szTime), "<> Time: %02d:%02d:%02d", szTime[0], szTime[1], szTime[2]);
    SendClientMessage(playerid, 0x00FF00FF, szTime);
    return 1;
}
Note that there are no parameters.
pawn Код:
rCmd["uF(100.0)"]->sethealth(playerid, success, &targetid, &Float: health) {
    if(!success) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: /sethealth [player id/name] [health (default = 100.0)]");
    if(targetid == INVALID_PLAYER_ID) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player is not connected!");
    if(!(0.0 <= health <= 100.0)) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Health has to be between 0.0 and 100.0!");

    SetPlayerHealth(playerid, health);
    SendClientMessage(playerid, -1, "You have set players health!");
    return 1;
}
Some float example. Again, please don't forget the & sign!

Callback(s)

We have two callbacks:
pawn Код:
forward OnPlayerCommandReceived(playerid, cmdtext[]);
This gets called before the actual command gets executed. So returning 0 here means the command won't be executed.

pawn Код:
forward OnPlayerCommandPerformed(playerid, cmdtext[], success);
This gets called after the command gets executed. Returning 0 in here will result in standart "SERVER: Unknown Command" message. You can adjust that message under this callback.

As you probably may have noticed, I used the same callbacks as used in zcmd as they were pretty useful.
pawn Код:
public OnPlayerCommandReceived(playerid, cmdtext[]) {
    if(!strcmp(cmdtext, "/setname", true, 8)) {
        SendClientMessage(playerid, 0xFF0000FF, "ERROR: This command is not enabled right now!");
        return 0; // Command won't be executed
    }
    return 1;
}
pawn Код:
public OnPlayerCommandPerformed(playerid, cmdtext[], success) {
    if(!success) {
        return SendClientMessage(playerid, 0xFF0000FF, "ERROR: That command is unknown!");
    }
    return 1;
}
Download
  • rCmd.inc
  • DynamicParams.inc has also been updated, please make sure you redownload this!
  • You can download sscanf here! Also, I want to thank ****** for this beautiful plugin!
Notes
  • When a command doesn't work, it most probably means that the value MAX_FUNCTIONS (1024) has been exceeded. Just increase it and recompile it and you should be good to go.
  • The max length of the specifiers you can use is currently set to MAX_SSCANF_FORMAT (32). If you need longer specifiers, just increase it.
  • You can use MAX_DYNAMIC_PARAMS (16) parameters with the current settings. Just increase if you would ever need more than 16 parameters.
Changelog
  • 07/03/2012 - v0.1.0:
    • Initial release
  • 08/03/2012 - v0.1.1:
    • Fixed some important bugs. Please re-download if you're using it.
  • 21/04/2012 - v0.1.2:
    • Changed the whole syntax so there's not rCmd_Init anymore (thanks ******):
      Код:
      rCmd[specifiers]->commandname(playerid, success, ...)
    • Added some new useful specifiers h, b and u:
      StringCharacterIntegerFloatUser name/idHexBinary
      s
      c
      i or d
      f
      u
      h
      b
    • Fixed a bug where the stack didn't get restored when your command was incomplete.
  • 06/01/2013 - v0.2.0:
    • Rewrote the whole include, as well as DynamicParams.inc. I found some critical bugs that made this include completely worthless, but I'm sure it's completely fixed now and is %100 to use.
    • sscanf plugin is fully integrated now and automatically makes use of all features of the sscanf plugin.
    • Just make sure you read "Syntax" part of the topic again as there are some important things to note:
      Quote:
      Syntax

      Код:
      rCmd["specifiers"]->commandname(playerid, success, ...)
      NEW (IMPORTANT NOTES):
      • You can use all sscanf specifiers in the specifiers input, yes, literally whole sscanf.
      • Note the quotes around specifiers in this new version. It's not necessary, but when you use brackets for optional parameters, it will give you errors without the quotes.
      • You have to use & in front of all non-array variables (floats, integers, ..., NOT playerid and success) because DynamicParams.inc is passes the address of the value. If you skip this, the value of the integer/float will be wrong. Example:
        Код:
        rCmd["us[24]"]->setname(playerid, success, &targetid, name[]) {
        	// ...
        	return 1;
        }
Have fun using this!
Reply
#2

Wow, nice job! finally a new style of creating commands!
Reply
#3

Wow.. I never expected something like this, i'm going to use it on my next script you know that.
Reply
#4

Wow.
sscanf's use will become less but still gonna use sscanf
Reply
#5

Nice work ! Maybe this will be my next use xp
Reply
#6

wow nice!
Reply
#7

Good job RyDeR`
Reply
#8

I shall convert soon my friend <3

EDIT: I'm blind if you have posted this already, but any speed results?
Reply
#9

Looks nice but I don't want to use it as I'm used to the simple zcmd and sscanf.
Reply
#10

I think this would be way better if you combined it with sscanf to support optional parameters, arrays etc.
Reply
#11

Wow, very cool rep+

also, can you make some benchmarks with ycmd, zcmd etc.. ?
Reply
#12

I thought, "is just more a command processor", but you had a nice idea with these params pre-included.
Reply
#13

Thanks! That's the power of emit.

I have no idea about the performance but this is obviosly slower than zcmd. Will do a test later though. Don't mind about the performance.
Reply
#14

Nice idea, I didn't think I'd ever see parameter splitting in the header of a command.
Reply
#15

Very nice RyDeR`
Reply
#16

Added the specifiers in the first post.

Small update:
Quote:
Changelog
  • 08/03/2012 - v0.1.1:
    • Fixed some important bugs. Please re-download if you're using it.
Reply
#17

Amazing! This will make creating commands much more easier.
Reply
#18

Sorry double post.
Reply
#19

I have some benchmarks:
pawn Code:
[Benchmark] 'signle_int_zcmd' executed about 164.09 times/ms.
[Benchmark] 'signle_int_rcmd' executed about 109.70 times/ms.

[Benchmark] 'signle_string_zcmd' executed about 150.49 times/ms.
[Benchmark] 'signle_string_rcmd' executed about 72.40 times/ms.

[Benchmark] 'no_params_zcmd' executed about 187.40 times/ms.  
[Benchmark] 'no_params_rcmd' executed about 136.98 times/ms.

[Benchmark] 'mixed_params_zcmd_sscanf' executed about 86.96 times/ms.
[Benchmark] 'mixed_params_rcmd' executed about 49.35 times/ms.
In most cases it's ~2 times slower than zcmd. It's actually still pretty fast! I will see in future versions if I'll be able to increase performance. But again, those results are nothing you should really worry about.
Reply
#20

Really good job RyDeR`.
But I prefer zcmd.
Anyway, good job! 5/5
Reply


Forum Jump:


Users browsing this thread: 7 Guest(s)