Best method for storing command strings for a "Hot Commands" interface -
Pro - 21.08.2011
Hi,
For my server I would like to create a textdraw under the HUD showing HOT commands. In other words, commands that have been used a lot, recently.
So like, say 5 players type two commands: /race and /jump. These two would become hot since they've been used recently and a lot, so they would display in the textdraw.
Just wondering the best way to do this? An example would be great. Storing all commands inputted into a large string and then comparing which command has been used the most at the end? meh dunno
Re: Hot Commands -
Bakr - 21.08.2011
There are a few ways to approach this. I would personally make an array with the amount of cells as there is commands. Assign each command a unique ID, then add to the array's appropriate cell 1 for each time it's used. Unique IDs so you don't have to worry about the slower string comparison. Then, when it's time to update the textdraw, use some sort of algorithm to sort them and see which was used the most. You can find it on ******, or even this forums.
An example of how it would look
pawn Code:
#define COMMAND_JUMP (0)
#define COMMAND_RACE (1)
new g_Command[ MAX_COMMANDS ]; // Adjust MAX_COMMANDS to however many commands you have
COMMAND:jump( playerid, params[ ] )
{
// command stuff
g_Command[ COMMAND_JUMP ]++;
return 1;
}
Re: Hot Commands -
Pro - 21.08.2011
Hmm, I was hoping for a more dynamic approach. This is one method I had in mind:
pawn Code:
#define HOT_CMD_INDEX 30
static szHotCmds[HOT_CMD_INDEX][128];
static iHotCmdUsed[HOT_CMD_INDEX];
static iHotCommandCount;
public OnPlayerCommandText(playerid, cmdtext[])
{
if(iHotCommandStorage == HOT_CMD_INDEX - 1) // Array has reached its limit so we start again
{
iHotCommandCount = 0;
}
// loop through all previously stored commands and see if the
// cmd we're using now is already stored. if it is, then it's obviously
// been used more than once very recently.
for(new i = 0; i < iHotCommandCount; i++)
{
// we found a match. Just increase the amount of times this
// cmd has been used
if(!strcmp(szHotCmds[i], cmdtext, false))
{
iHotCmdUsed[i]++;
break;
}
// Reached the end of the loop with no match
// so store this as a new cmd
if(i == iHotCommandCount - 1)
{
format(szHotCmds[iHotCommandCount], 128, "%s", cmdtext);
// Increase both the overall count of commands stored
// as well as the current number of times this particular cmd has been used
iHotCommandCount++;
iHotCmd[iHotCommandCount]++;
}
}
Writing a little function from there to determine which commands are hot is then easy.
The problem is though not only is it horribly inefficient but after 30 commands have globally been used it would result in the counter being reset thus those "hot" commands loosing their "hot" aspect.
I'm pretty sure there are other more efficient, dynamic and easier methods. Hopefully if a few experienced scripters see this topic it will turn into a good discussion.
Re: Hot Commands -
Bakr - 21.08.2011
That way will work, but as you said, it would be rather slow. Instead of adding it in and checking with string manipulation, as it is far slower, just use a hash function with a unique key to store and compare the values of the command (by name, don't hash the value of times they've been used). That would quicken the process up slightly.
And if you want endless amount of commands to be added, you could simply use properties.
EDIT: And a possible flaw with the above code would be this:
pawn Code:
if(!strcmp(szHotCmds[i], cmdtext, false))
{
iHotCmdUsed[i]++;
break;
}
If you had commands that would have optional or per-player input, like inserting of IDs or messages, it would count "kick 1" and "kick 2" differently.