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:
- 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!
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
|
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
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:
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_
Nice, but what if Wait is inside a loop, a return, or perhaps like this:
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.