Dialogs, PauseGame() and repeatedly_execute_always()

Started by monkey0506, Thu 18/07/2013 20:51:58

Previous topic - Next topic

monkey0506

Quote from: Snarky on Thu 18/07/2013 10:45:25
Another bug. This one crashes the editor (well, it keeps running, but I can't save the project, it just makes it crash again):

Spoiler


QuoteError: Index was outside the bounds of the array.
Version: AGS 3.3.0.1140

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at AGS.CScript.Compiler.FastString.get_Item(Int32 index)
   at AGS.Editor.AutoComplete.AdjustFunctionListForExtenderFunction(List`1 structs, List`1& functionList, FastString& script)
   at AGS.Editor.AutoComplete.ConstructCache(Script scriptToCache, Boolean isBackgroundThread)
   at AGS.Editor.ScriptEditor.scintilla_OnBeforeShowingAutoComplete(Object sender, EventArgs e)
   at AGS.Editor.ScintillaWrapper.ShowAutoComplete(Int32 charsTyped, String autoCompleteList)
   at AGS.Editor.ScintillaWrapper.ShowAutoCompleteIfAppropriate(Int32 minimumLength)
   at AGS.Editor.ScintillaWrapper.OnUpdateUI(Object sender, EventArgs e)
   at Scintilla.ScintillaControl.DispatchScintillaEvent(SCNotification notification)
   at Scintilla.ScintillaControl.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
[close]

Happens as I'm trying to type "(this Dialog*)" after entering the first three letters "Dia" (though in the screenshot I had time to add a typo). Even if I close the editor, restart, and try again, it still crashes. Perhaps the project is corrupted? Here it is in case it's needed for examination: https://www.dropbox.com/s/2uy1xb3u5bn0z8q/testcursor-crash.rar

Obviously the crash should be looked into, but for what you're doing there may be a better way. Are you using the custom dialog options rendering methods, or just using the built-in rendering? If you're using the custom functions then you can use dialog_options_get_dimensions as a form of "dialog_start" and repeatedly_execute as a form of "dialog_end". If you have nested/branching dialogs then you could even reliably use dialog_options_get_active as a form of "dialog_repeatedly_execute" to update the actively "running"/visible dialog.

If you're using the built-in methods none of this applies, but it could be some food for thought (and it would save you having to remember to call your custom "StartTracked" method instead of the built-in "Start").

Weird bug though.

Snarky

#1
Quote from: monkey_05_06 on Thu 18/07/2013 20:51:58
Obviously the crash should be looked into, but for what you're doing there may be a better way. Are you using the custom dialog options rendering methods, or just using the built-in rendering? If you're using the custom functions then you can use dialog_options_get_dimensions as a form of "dialog_start" and repeatedly_execute as a form of "dialog_end". If you have nested/branching dialogs then you could even reliably use dialog_options_get_active as a form of "dialog_repeatedly_execute" to update the actively "running"/visible dialog.

If you're using the built-in methods none of this applies, but it could be some food for thought (and it would save you having to remember to call your custom "StartTracked" method instead of the built-in "Start").

It's not for me. I guess it would have been possible to do it that way, though not with the "Run game loops while dialog options are displayed" option on. Recommending switching to custom dialog rendering (which I wasn't sure would even help) seemed like more work than this little extender, though.

monkey0506

Fair enough, but "Run game loops..." only applies to repeatedly_execute_always. repeatedly_execute is never run while the dialog options are being shown or any of the actions that take place throughout its lifetime (until it reaches stop/return). You're probably right that for the situation at hand custom rendering may have been overkill, but I thought I'd point it out in case you weren't aware. ;)

Snarky

Are you sure about that? If "Run game loops..." is set to true, IsGamePaused() returns false while dialog options are displayed, and I've always assumed there's a one-to-one correspondence between IsGamePaused() and repeatedly_execute() not running.

monkey0506

IsGamePaused bears no relevance to the blocking thread. PauseGame only pauses AGS' handling of movement and animations. The scripts are still run normally. You can still call on_key_press, on_mouse_click, event handlers, and even repeatedly_execute while the game is paused.

Conversely, while the user interface is disabled, none of these functions are called. repeatedly_execute_always of course still runs during the blocking thread, so you can effectively do this:

Code: ags
// GlobalScript.asc
bool IsBlocking = false;

function repeatedly_execute_always()
{
  IsBlocking = !IsInterfaceEnabled();
}


IsBlocking would then never return true outside of rep_ex_always or functions explicitly called from there, and it would always be syntactic sugar for !IsInterfaceEnabled, but it's perfectly functional.

As a proof regarding PauseGame, you could use the following:

Code: ags
// GlobalScript.asc

function on_key_press(eKeyCode keycode)
{
  if (keycode == '1') PauseGame();
  else if (keycode == '2') UnPauseGame();
}

function repeatedly_execute()
{
  if (IsGamePaused()) AbortGame("paused");
}


Dialog options being displayed doesn't pause the game (even if "Run game loops..." is set to false):

Code: ags
// GlobalScript.asc

function on_key_press(eKeyCode keycode)
{
  if (keycode == 'D') dDialog0.Start();
}

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  info.X = 0;
  info.Y = 0;
  info.Width = 200;
  info.Height = 200;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  info.Surface.Clear(0);
  info.Surface.DrawingColor = 13;
  info.Surface.DrawString(1, 1, eFontNormal, "lol");
}

function dialog_options_get_active(DialogOptionsRenderingInfo *info)
{
  if (IsGamePaused()) AbortGame("paused");
  info.ActiveOptionID = 0;
}


So, I'd say I have a fairly reasonable idea of what I'm doing... ;)

Oh, also:

Quote from: Pumaman on Sat 12/09/2009 12:07:31
Quoteso, is there any reason why you can't have RepExec loops running with 'run game loops while dialog options are displayed'?

Well, this is standard AGS behaviour that RepExec doesn't run while the game is blocked (which it is while dialog options are displayed); just like while a blocking Walk or blocking Animate are in progress.

monkey0506

I knew we were getting off topic, but that's what you're there for, eh Snarky? :P Also, I hope I didn't come across condescending with all the code snippets and the quote, I was just showing that AGS does indeed behave as I was describing. :)

Snarky

Yeah, I say let the discussion drift as it will, the moderators can always sort it later. (Though it's tough when a post addresses multiple topics; there's no way to split or make duplicate copies of an individual post.)

And I absolutely believe you're right. I've just always been under the impression that IsGamePaused() referred to Wait() and other blocking scripts (so if I understand you correctly, that's IsInterfaceEnabled(), or is that yet another thing?). This probably explains a lot.

SMF spam blocked by CleanTalk