[Tutorial] y_dialog and y_inline
#1

Introduction

This tutorial continues my series on the new features available in YSI 3.0. As I strive to get it stable and released, these tutorials should give people an idea of what's available and thus make it easier for people to test them and find bugs (please report any you find).

There are a number of dialog processing systems already, but they all have (IMHO) one fundamental flaw - they all still rely on dialog IDs. "y_dialog" does away with this requirement, instead maintaining a record of what IDs are in use internally and providing an API to get an available free one (if you even need to).

Example

pawn Код:
new
    id = Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1");
This is basically the same API as before (you can still use the old functions and the system will register those IDs as in use), but with no "dialog" parameter. In actual fact, it is still there, it's just at the end.

Reuse

The optional existence of the "dialog" parameter means you can ignore it entirely (the second button parameter can also be left out), or you can give an ID when it is appropriate.

Showing a dialog to some set of players:


pawn Код:
new
    id = Dialog_ObtainID();
foreach (new i : Player)
{
    if (ShouldSeeDialog(i))
    {
        Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
    }
}
This way the same dialog seen by every player will always have the same ID (making processing easier). You could even register the ID in "OnGameModeInit" and always use that ID, ensuring that no two dialogs will ever conflict (and as with any YSI library, this works in all scripts at once):

pawn Код:
#include <YSI\y_dialog>

new
    gID = -1;

public OnGameModeInit()
{
    gID = Dialog_ObtainID();
}

public OnPlayerConnect(playerid)
{
    Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Welcome", "Welcome to the server!", "OK", "Cancel", gID);
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if (dialogid == gID)
    {
        printf("player %d pressed %d", playerid, response);
    }
    return 1;
}
Or, if it is a dialog that will only be used once, you can tell the system to reclaim the ID after no-one can see it ("garbage" collection):

pawn Код:
new
    id = Dialog_ObtainID();
foreach (new i : Player)
{
    if (ShouldSeeDialog(i))
    {
        Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
    }
}
Dialog_Garbage(id);
"Garbage" will be automatically set for any dialog which is only shown to one player and for which no explicit dialog ID was provided:

pawn Код:
new
    id = -1;
foreach (new i : Player)
{
    if (ShouldSeeDialog(i))
    {
        id = Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
    }
}
In the code above "id" is initially set to "-1" (which means "assign an ID"), so the system assigns an ID for the first player, marks the ID as garbage (to be reclaimed when no-one can see the dialog any more) and returns this new ID. When the dialog is shown to the second player the existing ID is re-used but "garbage" status IS NOT cleared. This makes the code above DIFFERENT to the code in which "Dialog_ObtainID" is explicitly called first. Your choice of function call should reflect this difference.

Functions

There are a few other functions available for use:
  • Dialog_Get(playerid)

    Get the ID of the dialog this player can currently see. Note that if you call this function in "OnDialogResponse" it WILL NOT return the correct ID as the player can no longer see it (but you still have "dialogid" there anyway).

  • Dialog_Set(playerid, dialogid)

    It's doubtful that you will ever need this function, but this is the opposite of "Dialog_Get".

  • Dialog_Hide(playerid)

    Hide the dialog that the player is currently viewing.

  • ShowPlayerDialog(playerid, dialog, style, string:title[], string:caption[], string:button1[], string:button2[])
Hooked function to show a dialog with the given ID, and reserve that ID in the system.


Callbacks

There is one very important feature of y_dialogs that makes it (again, IMHO) vastly better than any other dialog processing system and that is it's ability to use "y_inline" for single dialog response processing instead of "OnDialogResponse":

pawn Код:
public OnPlayerConnect(playerid)
{
    inline Response(pid, dialogid, response, listitem, string:inputtext[])
    {
        #pragma unused pid, dialogid, response, listitem, inputtext
        SendClientMessage(playerid, 0xFF0000AA, "You clicked a button!  Good for you!");
        // Inline function will end here.
    }
    Dialog_ShowCallback(playerid, using inline Response, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1");
    // Main function will end here.
}
That is all there is to processing a dialog using this system. The dialog id does not appear anywhere in that code (there is the variable "dialogid" passed to the inline function, but you don't need it). "inline" functions are mostly like normal functions, except they can be embedded inside other functions (including inside other "inline" functions).

There are a few VERY important things to note here:
  • The callback "OnPlayerConnect" has a parameter called "playerid", the callback "OnDialogResponse" ALSO has a parameter called "playerid", and the "Response" inline function has the same parameters as "OnDialogResponse". However, you can't have two variables with the same name in one function so the second "playerid" has been renamed "pid".
  • 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".
  • Strings do work, but strings passed to the enclosing function (there are none here) DO NOT work as they're a little different. Also, any string that is a parameter to an inline function (for example "inputtext") must be declared with the tag "string:", as above.
This style of coding keeps the reponse processing of a dialog with the place where it is shown, and removes the worry of dialog IDs entirely. You can also use public callbacks instead of inline functions with "using callback Whatever" instead of "using inline Whatever".

You can also combine processing and show a dialog with a callback to mulitple people (and mark it as garbage or not).
Reply
#2

I got strange bug:

Код:
				
				inline Dialog_Register(pid, response, listitem, string:inputtext[])
				{
				    if(!response)
				    {
				        Kick(playerid);
				    }
				}
response doesn't work well, although i press button 1 or button 2, that just kick me ._.
Reply
#3

Quote:
Originally Posted by RaeF
Посмотреть сообщение
I got strange bug:

Код:
				
				inline Dialog_Register(pid, response, listitem, string:inputtext[])
				{
				    if(!response)
				    {
				        Kick(playerid);
				    }
				}
response doesn't work well, although i press button 1 or button 2, that just kick me ._.
One button return a canceled response, the other sends a true response. Btw, why would you use kick as a test method? XD

Why not just do this?
Код:
				
				inline Dialog_Register(pid, response, listitem, string:inputtext[])
				{
				    switch(response)
				    {
				        case 0: SendClientMessage(playerid, -1, "Negative");
				        default: SendClientMessage(playerid, -1, "Positive");
				    }
				}
Reply
#4

DELETED, already solved

im missing dialogid param lol
Reply
#5

Need help, inline not getting called
It just print

Debug: Called 3
Debug: Called 1
Debug: Called
and Lel doens't getting called.
But the Dialog show up.
Код:
public OnPlayerClickPlayerTextDraw(playerid, PlayerText:playertextid)
{
	print("Debug: CAlled 3");
	if(playertextid == textdraw_panel_player[playerid][5])
	{
		print("Debug: CAlled 1");
		inline Response(pid, dialogid, response, listitem, string:inputtext[])
		{
			#pragma unused pid, dialogid, response, listitem, inputtext
			print("Lel");
		}
		print("Debug: CAlled");
		Dialog_ShowCallback(playerid, using inline Response, DIALOG_STYLE_INPUT, "Masukan password baru", "Masukan password baru akun anda dibawah ini:", "Ok", "Batal");
	}
	return 1;
}
But when use standar ( Not using inline ), it's called.
Reply
#6

Hello! I have found a bug. Dialogs(ShowPlayerDialog or Dialog_Show(playerid, ....., .dialog = 8 are not working when this library is included. Do you have any tip?
It is from:
hook OnDialogResponse, i tried to change the timer with the content of the function but a bug appeared:
Simple dialogs are working( Dialog_Show(..... ,.dialog = value) ) but the complex one aren't working. (Dialog_ShowCallback).
Thank you!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)