Get playerid from listitem.
#1

Hi, I've problem with players in DIALOG_STYLE_LIST.

I show in dialog PlayerNames, code:
PHP Code:
new string[512], players[512], countPlayers;
            foreach(
Characteri){                
                if(
PlayerInQueue[i] == true){
                    
format(playerssizeof(players), "%s"GetPlayerName(i));
                    
strcat(string"\n");
                    
strcat(stringplayers);
                    
countPlayers++;
                }
             }
            if(
countPlayers == 0){
                
SendClientMessage(playerid, -1"No Players");
            }
            
ShowDialog(playerid34DIALOG_STYLE_LIST"Header"string"Select""Close"); 
Now, I need for example show player stats using function "ShowPlayerStats(playerid)" (this show dialog with stats).
Code:
if(dialogid == 34){
	if(response){
		//here I need get playerid from list
	}
}
How I get listitem == id player on list? Someone have solution?
Reply
#2

There are multiple ways to solve this.

My personal favorite is formatting the ID of the player into the dialog, add a tab between the ID and player name and make it DIALOG_STYLE_TAB_LIST.

Something like this:

Quote:

0\tCherryMond
4\tNaS
7\tWhatever

The ID needs to be the first text in each row.

You might know that when a list dialog calls OnDialogResponse, the inputtext array will always be filled with the content of the row the player selected.

When it's a tab list dialog, only the first part of the row (until the first tab) will be passed. So when you select one of the above entries, inputtext will contain "0", "4" or "7".

So you only need to use strval or sscanf on inputtext to retrieve the ID. If you use strval, make sure to check for the length of the inputtext since there are hacks/cleo scripts to fake dialog data (which could crash the server in this case). For the same reason you should make sure the selected ID is valid etc.
It doesn't need any seperate storing and it's easy to do.

The only disadvantage is having the ID inside the dialog, however for player IDs this shouldn't be a problem.


Another way would be getting the Player ID from the Player Name (since the player name will be passed to inputtext if you don't add an ID).
Reply
#3

When I use sscanf - This should be like:
PHP Code:
if(response){
    new 
id;
    if(!
sscanf(inputtext"u"id)){
        
ShowPlayerStats(id);
        return 
true;
    }

or first tab inputtext[0]?
PHP Code:
if(response){
    new 
id;
    if(!
sscanf(inputtext[0], "u"id)){
        
ShowPlayerStats(id);
        return 
true;
    }

Reply
#4

When you use the dialog tab list like NaS suggested, you only need to convert the inputtext using strval
Code:
if (response) {
	new id = strval(inputtext);
	if (IsPlayerConnected(id)) {
		ShowPlayerStats(id);
		return 1;
	} else {
		// selected player is no longer online
	}
}
And your dialog tab list is formatted like this:
Code:
format(players, sizeof (players), "%i\t%s", i, GetPlayerName(i));
inputtext will only return the first column of the tab list.

But if you wish to stay with your own code (dialog list of player names only), you do this:
Code:
if (response) {
	new id;
	if (!sscanf(inputtext, "u", id)) {
		if (id != INVALID_PLAYER_ID)
		{
			ShowPlayerStats(id);
			return true;
		} else {
			// selected player is no longer online
		}
	}
}
if you only do inputtext[0], it will only take the first digit... so ID "12" will be only "1"

Note it is important to handle if the regarding player is still connected or not, because the players from the list might have been left the server OR changed name before the player response the dialog.
Reply
#5

If it's ever not conveniently formatted to use with sscanf, you could always do something like:

pawn Code:
new tmpstr[80];

format(tmpstr, sizeof(tmpstr), "PLIST_%i_USERID", countPlayers);
SetPVarInt(playerid, tmpstr, get_players_id);
That would be inside your iteration. How do you use it?

pawn Code:
new tmpstr[80], get_player_id;

format(tmpstr, sizeof(tmpstr), "PLIST_%i_USERID", listitem);
get_player_id = GetPVarInt(playerid, tmpstr);
Inside your OnDialogResponse. Delete it after.

We're using the listitem the player would be at in OnDialogResponse and setting their ID through the PVar.

listitems start at 0 and as does your countPlayers variable.

It's pretty simple and self explanatory but if you don't understand, let me know and I'll explain further.
Reply
#6

Thank You, could you explain in more detail?
Reply
#7

Quote:
Originally Posted by Kane_
View Post
If it's ever not conveniently formatted to use with sscanf, you could always do something like:

pawn Code:
new tmpstr[80];

format(tmpstr, sizeof(tmpstr), "PLIST_%i_USERID", countPlayers);
SetPVarInt(playerid, tmpstr, get_players_id);
That would be inside your iteration. How do you use it?

pawn Code:
new tmpstr[80], get_player_id;

format(tmpstr, sizeof(tmpstr), "PLIST_%i_USERID", listitem);
get_player_id = GetPVarInt(playerid, tmpstr);
Inside your OnDialogResponse. Delete it after.

We're using the listitem the player would be at in OnDialogResponse and setting their ID through the PVar.

listitems start at 0 and as does your countPlayers variable.

It's pretty simple and self explanatory but if you don't understand, let me know and I'll explain further.
Why using PVar for this? Because they are slow, and especially when you us them with the format function. You could just use an array and store the ID's of the players in it...

I should do it like this:
PHP Code:
// Somewhere above your script (global variable), not inside any functions:
new dialogPlayerStatsList[MAX_PLAYERS][MAX_PLAYERS];
// Inside your foreach loop where you generate the list of players:
foreach(Characteri){
    if(
PlayerInQueue[i] == true){
        
format(playerssizeof(players), "%s"GetPlayerName(i));
        
strcat(string"\n");
        
strcat(stringplayers);
        
        
dialogPlayerStatsList[playerid][countPlayers] = i;
        
countPlayers++;
    }
}
// OnDialogResponse:
if(dialogid == 34){
    if(
response){
        
// Selected playerid:
        
new selected_playerid dialogPlayerStatsList[playerid][listitem];
        
GivePlayerMoney(selected_playerid1337); // Give selected player from list money (example)
    
}

Reply
#8

when you say PVars are slow you're talking tens of thousands of a millisecond like 0.00023 ms according to some speed tests, meaning you'd have to use over ten thousand in the one function to notice any slow down
Reply
#9

Quote:
Originally Posted by cessil
View Post
when you say PVars are slow you're talking tens of thousands of a millisecond like 0.00023 ms according to some speed tests, meaning you'd have to use over ten thousand in the one function to notice any slow down
True, but using it together with format is slow.
Reply
#10

Quote:
Originally Posted by BlackBank
View Post
True, but using it together with format is slow.
Quote:
Originally Posted by cessil
View Post
when you say PVars are slow you’re talking tens of thousands of a millisecond like 0.00023 ms according to some speed tests, meaning you’d have to use over ten thousand in the one function to notice any slow down
Replace “PVar” with “format”…
Reply
#11

Just remember, inputtext can be altered by players. So make sure you treat it as an unsanitised input.
Reply
#12

Quote:
Originally Posted by Y_Less
View Post
Replace “PVar” with “format”…
with format and pvar you still need to enter the thousands for it to start taking over 1ms
Reply
#13

Quote:
Originally Posted by cessil
View Post
with format and pvar you still need to enter the thousands for it to start taking over 1ms
I wasn\'t objecting to your statement , I was using it as the correct response. That maybe didn\'t come out clearly.
Reply
#14

Quote:
Originally Posted by cessil
View Post
when you say PVars are slow you\'re talking tens of thousands of a millisecond like 0.00023 ms according to some speed tests, meaning you\'d have to use over ten thousand in the one function to notice any slow down
Quote:
Originally Posted by cessil
View Post
with format and pvar you still need to enter the thousands for it to start taking over 1ms
Well i did some benchmarking, and it takes like 1ms when you iterate over 900 items and with 10.000 it takes 5ms to run the code. Ofcourse almost nobody will reach more then 900 players and for a dialog list is it okay to use it this way yeah, but it still takes some time to run this, then what you did stated.


Also the code i use to benchmark it:
PHP Code:
    new tick GetTickCount();
    new 
string[20];
    for (new 
0!= 10000; ++i) {
        
format(stringsizeof(string), "stats_%d_player"i);
        
SetPVarInt(playeridstringi);
    }
    
printf("End: %dms", (GetTickCount() - tick)); 
Reply
#15

Thank you all for your interest in the thread. Is fine.
Reply
#16

https://sampforum.blast.hk/showthread.php?tid=570904


Further to the point above, "SendClientMessage" uses "playerid" NOT "pid". "OnPlayerConnect" is called when the player connects, "Response" is called when the player clicks something on the dialog (which could be many hours later if they\'re AFK). Despite this fact, you can still use "playerid" (and any other variable from the enclosing function) inside "Response" thanks to a feature called "closures".


That eliminates the need for a two dimensional array.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)