The curious case of Display + how to freeze the engine and Editor

Started by Monsieur OUXX, Fri 13/10/2017 20:21:33

Previous topic - Next topic

Monsieur OUXX

Here is a simple experiment :

EDIT: code below was edited to take in account CW's feedback in next message)
Code: ags

void repeatedly_execute_always()
{
    while (!mouse.IsButtonDown(eMouseRight))
    {
        mouse.Update();
    }
    Display("Done!");
}


You'll notice that the engine freezes and you can't exit the loop even by pressing a key or left-clicking.
What are your thoughts on this?

I'm looking for ways (as inconventional as needed!) to intercept user input during repeatedly_execute_always. Oh, and to reflect something on screen.
 

Crimson Wizard

#1
IsKeyPressed(eKeyNone) -- this will always return false. You are asking if "KeyNone" is pressed, but there is no such key, it's just a way to initialize a variable to undefined value.

I'd rather suppose that calling Display from rep_exec_always is causing it to freeze.

PS. What is "interpect"?

Cassiebsg

There are those who believe that life here began out there...

Crimson Wizard

Quote from: Cassiebsg on Fri 13/10/2017 23:07:42
Quote from: Crimson Wizard on Fri 13/10/2017 21:09:57
PS. What is "interpect"?

Intercept.

Oh. I was wondering if that's some fancy word I never heard of.
Anyway, Monsieur OUXX, do you mean "intercept" as in "check" or "do not let through"?

Monsieur OUXX

#4
The "Display" is never reached, it's after the loop. Thinking about it, it would even crash the game because you can't call Display in blocking functions EDIT: it's Wait(1) that you can't call in blocking functions.
Also, forget about my misuse of "iskeypressed(ekyNone)"; there's still "IsButtonDown" that should do the job.

A truly infinite loop in repeatedly_execite_always definitely freezes the engine and the Editor (even clicking "pause" in the editor won't work), and have yet to find a way to intercept any player input, as in "detect" it.
 

Crimson Wizard

#5
Ok, this is weird, because I tried using that code in a test game and my results are different, they are also different from what I previously expected.

Quote from: Monsieur OUXX on Sat 14/10/2017 22:18:50
The "display is never reached". Thinking about it, it would even crash the game because you can't call Display in blocking unctions.
Also, forget about my misuse of "iskeypressed(ekyNone); there's still "IsButtonDown".

Well, you see, thing is that you were calling two conditions with AND operator. According to the "fast calculation" rule, if first condition is already false, the second should be skipped, going directly to Display. At least that's what happened when I tried your code.

Anyway, if you remove IsKeyPressed, there will be a (sort of) endless loop indeed, which will cause game to crash very fast with a friendly "your game may be hanging in a loop" warning.

After I added noloopcheck game stopped crashing, and were hanging there properly until I click the mouse, after which it went to Display and... actually showed display message.
So here is where I was wrong - you can actually call Display from rep-exec-always.

So, I did another experiment:

Code: ags

bool do_intercept_input;

function on_key_press(eKeyCode keycode) {
  
  if (keycode == eKey0){
    do_intercept_input = true;
    Speech.SkipStyle = eSkipKeyMouse;
    DisplayTopBar(10, 10, 20, "asdasdasdasdasd","asdasdasdasdasdasdasdasdas");
    Speech.SkipStyle = eSkipKeyMouseTime;
    do_intercept_input = false;
  }
}

function noloopcheck repeatedly_execute_always() {
 if (do_intercept_input) {

    while (!mouse.IsButtonDown(eMouseLeft))
    {
        mouse.Update();
    }
    Display("Done!");
 }
}



What happened is that as soon as I hit "0" on my keyboard the game hanged in the rep-exec-always loop until I clicked the mouse, after that it quickly displayed "Done!", and did not display DisplayToBar at all (maybe because second Display override it?).

If I remove Display("Done!"), and set Speech.SkipStyle = eSkipKey; to prevent DisplayTopBar skipping immediately by mouse click, then it will actually show up after game breaks out of the loop.


Anyway, results might depend on other things that are going on in your game. I have seen same commands working differently under some circumstances. Like Display in game_start, for example, sometimes it causes game to crash and sometimes it does not...




Quote from: Monsieur OUXX on Sat 14/10/2017 22:18:50
Ani infinite loop in repeatedly_execite_always definitely saturates the engine(even clicking "pause" in the editor won't work)
Clicking on "Pause" in editor sends a message to the engine. Depending on how this is implemented, if engine does not check for these messages in certain circumstances, then there won't be any answer or reaction ofcourse. I mean, that could be another oversight in program.

Actually, for me clicking on "Pause" had frozen both Editor and engine, which means Editor has a bug there too...

Monsieur OUXX

#6
I'm baffled by the fact that the test worked for you. My repeatedly_execute_always is in a room. I'll try to reproduce exactly every behaviour you described.
 

Crimson Wizard

Quote from: Monsieur OUXX on Sat 14/10/2017 23:50:49
My repeatedly_execute_always is in a room.

Hmm, mine was in global script...

Monsieur OUXX

#8
I've run some tests.
Just to be clear : The point in this thread was not to say "AGS is flawed in this way or that way", or even to request some fixes. I just wanted to try and find some dirty hacks to get more from my buck and push the limits.
Display seems to be one of these dirty hacks. Read below.

About the game freezing :

Apparently, when the game is in an infinite loop, especially inside repeatedly_execute_always, then clicking on the "pause" button will not be taken in account until a Display or game loop occurs. I don't know how it's coded internally, but maybe pressing "pause" sends a flag to the engine, which in turn waits for its next global internal refresh (actual game loop or the closest similar event) to take this flag in account and be ready to pause next time it encounters a game loop start.

It means that "pause" does not work the same way as breakpoint.

More importantly, it means that pressing "pause" in the editor, or trying to close the game window while the game is inside an infinite loop (with absolutely no instruction causing a game loop or a Display), will just freeze the Editor or the game until you kill the game process.
Another proof of this supposed behaviour is that while the game is in that so-called infinite loop, you can't add a breakpoint in the Editor window.

The curious case of Display

In a nutshell, my research suggests that :
- Display(""); does strictly nothing
- Display("some text"); does a half-baked game loop (updating game and GUIs) but without calling repeatedly_execute or any player-customized script tied to the end of a game loop. It makes Display a perfect alternative to Wait(1), even in repeatedly_execute_always where Wait(1) can't be called.
- The drawnback is that you'll need to display the Display popup on top of your GUI to benefit from the Display behaviour

========================================


Consider this code, placed in a script:
Code: ags

void repeatedly_execute_always()
{
  for (int i=0; i<10; i++)
  {
    gBlockingGUI.Visible = true;
    LabelTest.Text = String.Format("i=%d", i);

    bool exit;
    while (!exit)
    {
        mouse.Update();
        if (mouse.IsButtonDown(eMouseRight))
            exit=true;        
    }
    //Display("");
    Display("Done! (%d)", i);

    gBlockingGUI.Visible = false;   
  }  
}

int frameCount=0;
void repeatedly_execute()
{
    LabelTest2.Text = String.Format("frame=%d", frameCount); //This is never executed
}



If you execute it you will see that the Display instruction forces the game to refresh all its internal variables and animate the game (GUIs) BUT without ever going into repeatedly_execute. It's like some sort of half-baked Wait(1), that forces a game loop without call all the related functions normally hooked to a game loop. That's pretty cool. Also it refreshes the game TWICE, I think: once before displaying the Display popup, and once after (not sure about that, but I'm 100% sure that it does the resfresh at least once before Display).

Another undocumented feature of Display is that calling Display("") doesn't make any popup appear on-screen and doesn't even block the game. It's like a totally useless instruction because it's doesn't refresh the screen in any way.

Finally, I wrote just above that the game refreshes the in-game scene like in a normal game loop. Well, it's not true with the script above (character doesn't move when you click, only the GUi gets refreshed) BUT I swear there was a situation where it was happening for me even though I can't reproduce it. I've searched, and it was happening in some specific conditions, and now it doesn't happen anymore. Maybe someone will be luckier than me. I'm less and less sure that it actually happened. I might have gotten confused in all my tests.

 

SMF spam blocked by CleanTalk