SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Scripting Help > Discussion

Reply
 
Thread Tools Display Modes
Old 02/01/2014, 12:59 PM   #1
Emmet_
Guest
 
Posts: n/a
Default Alternative implementation of "wait".

Hey,

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

http://forum.sa-mp.com/showthread.php?t=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:
  • Loading the address and CIP of the current function and saving it somewhere.
  • Halting the execution of the current function (at the location Wait was used).
  • Setting up a timer for xx milliseconds that will call the saved function.
  • When the timer is called, jump to the saved function and CIP + 1.
(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!
  Reply With Quote
Old 02/01/2014, 01:07 PM   #2
Patrick
Guest
 
Posts: n/a
Default Re: Alternative implementation of "wait".

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);
}
  Reply With Quote
Old 02/01/2014, 06:18 PM   #3
Emmet_
Guest
 
Posts: n/a
Default Re: Alternative implementation of "wait".

Quote:
Originally Posted by ****** 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)?
  Reply With Quote
Old 02/01/2014, 07:08 PM   #4
IPrototypeI
Banned
 
Join Date: Jan 2013
Posts: 112
Reputation: 48
Default Re: Alternative implementation of "wait".

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.
IPrototypeI is offline   Reply With Quote
Old 02/01/2014, 08:03 PM   #5
IPrototypeI
Banned
 
Join Date: Jan 2013
Posts: 112
Reputation: 48
Default Re: Alternative implementation of "wait".

Quote:
Originally Posted by ****** 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
IPrototypeI is offline   Reply With Quote
Old 02/01/2014, 08:11 PM   #6
Emmet_
Guest
 
Posts: n/a
Default Re: Alternative implementation of "wait".

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"
}
  Reply With Quote
Old 02/01/2014, 08:22 PM   #7
IPrototypeI
Banned
 
Join Date: Jan 2013
Posts: 112
Reputation: 48
Default Re: Alternative implementation of "wait".

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
}
IPrototypeI is offline   Reply With Quote
Old 02/01/2014, 08:38 PM   #8
Emmet_
Guest
 
Posts: n/a
Default Re: Alternative implementation of "wait".

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.
  Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
error: undefine symbol "j" and expected token ";" but found "]" JEkvall95 Scripting Help 9 27/07/2013 11:09 AM
5 Dialog errors - Input line too long, undefined symbol "t","is" and "only" Deal-or-die Scripting Help 6 01/05/2012 01:08 PM
Whats with the "120 second" wait limit between posts? Marvin81 Everything and Nothing 13 20/08/2010 02:48 AM
Admin script requires "ReturnUser", "strtok" and "IsNumeric" Rubennnnn Help Archive 1 02/12/2009 07:08 PM


All times are GMT. The time now is 02:45 AM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.