SA-MP Forums Archive
Alternative implementation of "wait". - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Scripting Help (https://sampforum.blast.hk/forumdisplay.php?fid=12)
+---- Forum: Discussion (https://sampforum.blast.hk/forumdisplay.php?fid=84)
+---- Thread: Alternative implementation of "wait". (/showthread.php?tid=484959)



Alternative implementation of "wait". - Emmet_ - 02.01.2014

Hey,

As you may know, Y_Less once stated that "wait/Sleep is considered harmful" here:

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

So anyways, I've been working on a library recently that allows the ability to use "Wait" inside another function without hanging the server. This is achieved by:
(CIP means code instruction pointer, by the way).

The explanation above sounds complex, however the only to achieve this is to dig down into assembly by relying on the "LCTRL" and "SCTRL" instructions.

This will allow code like:

pawn Code:
Countdown(playerid)
{
    GameTextForPlayer(playerid, "~g~3", 3000, 3);
    Wait(1000);

    GameTextForPlayer(playerid, "~g~2", 3000, 3);
    Wait(1000);

    GameTextForPlayer(playerid, "~g~1", 3000, 3);
    Wait(1000);

    GameTextForPlayer(playerid, "~g~Go!", 3000, 3);
}
AFAIK, there's also a neat way to do it with y_inline, however the purpose of this is to implement a single-use function that can be used anywhere.

Is this a good idea or not? Thanks!


Re: Alternative implementation of "wait". - Patrick - 02.01.2014

I'd say good idea _Emmet instead of doing this, I'd like to see this released soon :P, anyways good luck with this.

pawn Code:
forward Wait1();
public Wait1()
{
    GameTextForPlayer(playerid, "~g~3", 3000, 3);
    SetTimer("Wait2", 1000, false);
}

forward Wait2();
public Wait2()
{
    GameTextForPlayer(playerid, "~g~2", 3000, 3);
    SetTimer("Wait3", 1000, false);
}

forward Wait3();
public Wait3()
{
    GameTextForPlayer(playerid, "~g~1", 3000, 3);
    SetTimer("WaitGo", 1000, false);
}

forward WaitGo();
public WaitGo()
{
    GameTextForPlayer(playerid, "~g~GO", 3000, 3);
}



Re: Alternative implementation of "wait". - Emmet_ - 02.01.2014

Quote:
Originally Posted by Y_Less
View Post
I did write a "W" macro in QWERTYUIOP that did this:

http://ysi.wikia.com/wiki/Library:QWERTYUIOP

But it hasn't been updated for YSI 4.0 (and doing so could be tricky). There are also numerous implementation issues (especially regarding the heap) discussed here:

http://forum.sa-mp.com/showthread.ph...05#post1944105

A stand-alone version might be useful, but one based on y_inline would take advantage of the vast optimisations done in there.
Great, nice. I noticed that the one on "QWERTYUIOP" does it much simpler than my method! I was thinking of using it, but are there any limitations that I should be aware of (e.g. using it in loops, in a return, etc)?


Re: Alternative implementation of "wait". - IPrototypeI - 02.01.2014

You can do an easy trick with a Define

Code:
#define Wait(%0)<%1> return SetTimer("@wait_"#%1,%0,false); } \
					forward @wait_%1(); @wait_%1() {
usage:

Code:
public OnGameModeInit()
{
	// Don't use these lines if it's a filterscript
	SetGameModeText("Blank Script");
	AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
	print("1");
 	Wait(1000)<a>
	print("2");
	Wait(1000)<b>
	print("3");
	Wait(1000)<c>
	print("4");
	return 1;
}
I thought about a other way but i don't know if it possible to get the address of a goto label to jump to a label anywhere in your code.


Re: Alternative implementation of "wait". - IPrototypeI - 02.01.2014

Quote:
Originally Posted by Y_Less
View Post
That is a good solution when it works, but if you have local variables it will fail:

pawn Code:
public OnGameModeInit()
{
    new a = 42;
    print("1");
    Wait(1000)<x>
    printf("2 %d", a); // Error.
    return 1;
}
But there is even the possibility to use SetTimerEx
Code:
#define Wait(%0)<%1,%2,%3> return SetTimerEx("@wait_"#%1,%0,false,%2,%3); } \
					forward @wait_%1(%3); @wait_%1(%3) {
but the only problem of this method is that you can't use strings


Re: Alternative implementation of "wait". - Emmet_ - 02.01.2014

Nice, but what if Wait is inside a loop, a return, or perhaps like this:

pawn Code:
if (Wait(1000)<a>)
Or perhaps this:

pawn Code:
public OnPlayerConnect(playerid)
{
    Wait(1000)<a>;
    SendClientMessage(playerid, -1, "Welcome."); // Undefined symbol "playerid"
}



Re: Alternative implementation of "wait". - IPrototypeI - 02.01.2014

Quote:
Originally Posted by Emmet_
View Post
Nice, but what if Wait is inside a loop, a return, or perhaps like this:

pawn Code:
if (Wait(1000)<a>)
Or perhaps this:

pawn Code:
public OnPlayerConnect(playerid)
{
    Wait(1000)<a>;
    SendClientMessage(playerid, -1, "Welcome."); // No Undefined symbol "playerid" :D
}
with the secound method you can do something like that

Code:
#define Wait(%0)<%1,%2,%3> return SetTimerEx("@wait_"#%1,%0,false,%2,%3); } \
					forward @wait_%1(%3); @wait_%1(%3) {
Code:
public OnPlayerConnect(playerid)
{
    Wait(1000)<a,"i",playerid>;
    SendClientMessage(playerid, -1, "Welcome."); // No Undefined symbol "playerid" :D
}



Re: Alternative implementation of "wait". - Emmet_ - 02.01.2014

The idea of this concept is to introduce a Wait(ms) function that can be used on the fly, without having to pass any extra arguments or make adjustments to the code. This is a complex operation that can't be implemented in any other means of PAWN code, in this case we use assembly instructions for implementing the final code.

While I agree that the macro would be a nice method, it would entirely break with most things. I've had functions with over 10 arguments once, imagine doing this:

pawn Code:
Wait(10000)<a, "ddddffffff", playerid, playerobject, objectid, response, Float:fX, Float:fY, Float:fZ, Float:fRotX, Float:fRotY, Float:fRotZ);
It just doesn't seem convenient to me.