View Issue Details

IDProjectCategoryView StatusLast Update
0006164The Dark ModGUIpublic20.02.2024 18:17
Reporterstgatilov Assigned Tostgatilov  
PrioritynormalSeverityfeatureReproducibilityN/A
Status feedbackResolutionopen 
Product VersionTDM 2.11 
Target VersionTDM 2.13 
Summary0006164: New features in GUI engine
DescriptionPerhaps add the following to GUI engine:

1) runScript command --- code is already here, just fix it.
2) namedEvent command: triggers named event with given name (exists on other idTech4 games).
3) Add "vec4" keyword as synonym for "definevec4", deduplicate code for "float" and "definefloat".

Discussed here:
  https://forums.thedarkmod.com/index.php?/topic/21642-feedback-on-wiki-gui-scripting-language-series
Additional Informationhttps://forums.thedarkmod.com/index.php?/topic/22239-gui-features-runscript-and-namedevent/
TagsNo tags attached.

Activities

Geep

Geep

15.11.2022 20:10

reporter   ~0015433

For completeness, should probably also allow the form (reportedly widely used by id Software at one time):
set "cmd" runscript <function_name>;

(I'm not sure about where double quotes are needed here)
stgatilov

stgatilov

04.10.2023 19:49

administrator   ~0016099

Here is an example of how runScript command works in Doom 3 / TDM (it should work in 2.11 too).

First, define a global function.
For instance, I added to tdm_player.script:
   void testfunc() {
       sys.println("It works!\n");
   }

Then add somewhere in GUI script the call.
For instance, I added it in readable.guicode in onAction handler:
  runScript "testfunc";

When I click Attack when reading a readable, this script function is triggered and I see the message in console.

-----------------------------------------------
Here is how it works internally.

runScript is a separate type of command, which accepts one string argument ARG --- which function to call.
Whenever GUI script executes this command, it pushes "runScript ARG" command into idWindow::cmd (see Script_RunScript).
Then at some moment someone pulls these commands from all windows.
In my particular case, it happens in idPlayer::Weapon_GUI --- see the call to idEntity::HandleGuiCommands there.

At this moment it sees runScript command and tries to find script function with ARG name.
The name may contain "::", but as long as the function is found, it is called with no arguments.
So you cannot invoke object methods like this --- only freestanding functions.
I'm not sure game scripts support something like C++ static methods... but if they do, you should be able to call them as well.
stgatilov

stgatilov

04.10.2023 21:11

administrator   ~0016100

I think the real problem is that HandleGuiCommands is only executed in one code location, and only if player clicks "Attack" on this very frame.
It turns out I was just lucky to write test code exactly in the only place where it works =)

It is obvious that the system of passing commands from GUI was not intended as something that just does whatever is said immediately.
It was instead designed as something that caller may act on if he wants.
It was not intended that all commands are queued up until someone pulls them.
Instead, they are stored immediately, and freely cleared between actions.

So whenever someone calls idUserInterface::HandleEvent, it executes some GUI scripts inside, and might return a sequence of commands to the caller.
That's what happens when player clicks Attack while interacting with GUI, but it is context-sensitive: some other action on the GUI might have no handling of the commands, or even different handling.
Of course, if you call runScript in onTime handler, it probably won't do anything, because no one is looking at the resulting commands from them.

The issue I see right now is that script can call GUI event via Event_CallGui.
It internally calls idUserInterface::HandleNamedEvent, which does not return the commands (they are just gone).
I think I can extend this so that returned commands are bubbled up to Event_CallGui, which schedules script calls in the future.

However, anything else is context-sensitive --- that's by design.
stgatilov

stgatilov

05.10.2023 19:46

administrator   ~0016105

r10460 Cleaned up commands chaining on runScript GUI command + reduced error for unknown script function to warning.
r10461 Merged definefloat and float, added vec4 keyword.

Regarding "vec4", I check that it works with attached hacky patch =)
"float"s is already used e.g. for lightgem crouch display.
vec4_in_gui_hacky_background (897 bytes)   
--- C:/Users/GATILO~1/AppData/Local/Temp/mainmenu_background.gui-revBASE.svn003.tmp.gui	�� ���  8 15:00:31 2021
+++ G:/TheDarkMod/darkmod/guis/mainmenu_background.gui	�� ���  5 21:09:17 2023
@@ -74,9 +74,21 @@ windowDef MainMenuBackgroundSwirly
 	background  "guis/assets/mainmenu/swirl"
 
 	BACKGROUND_DEFAULT_BEHAVIOR(MainMenuBackgroundSwirly)
+
 }
+windowDef MyTimer
+{
+	vec4  MYCOLOR 1, 1, 0.5 + 0.5 * sinTable[time * 0.001], 0.5
+	notime 0
 
+	onTime 10
+	{
+		set "MainMenuBackgroundSwirly::backcolor" "$MYCOLOR";
+		resetTime 0
+	}
+}
 
+
 // Background Figures
 windowDef MainMenuBackgroundFigures
 {
@@ -324,7 +336,7 @@ windowDef FailureBackgroundOuterdirt
 windowDef MainMenuBackgroundOverlay
 {
 	rect    0, 0, 640, 480
-	matcolor    1 ,1 ,1 ,0.6
+    matcolor 1, 1, 1, 0.6
 	background  "guis/assets/mainmenu/background"
 
 	BACKGROUND_DEFAULT_BEHAVIOR(MainMenuBackgroundOverlay)
stgatilov

stgatilov

05.10.2023 19:52

administrator   ~0016106

There are several things to decide here.

1) Regarding "namedEvent" in GUI: how does it work in games where it exists?
Does it trigger the event with this name on current window only, or on all windows in the UI?
Does it trigger event immediately (unlikely), or does it schedule execution until the script handler is over?
Maybe it works via the same window cmd system as runScript command?

2) Regarding runScript.
What use cases do we want for this feature?
Looking at specific examples, we can decide how to adjust the current architecture...
Geep

Geep

07.10.2023 16:35

reporter   ~0016108

It's been a year since I've thought about gui scripting. Let me start with runScript, and how I should change my wiki entry to more correctly express its *current* capabilities (as of 2.11). I understand the call can only be used effectively within an onAction handler. Some questions:

Can the global function called be in any .script file, or only in the map_name.script file (invoked with or without "map_name::" prefix)?

Can that function have a loop (perhaps containing a wait), or must it be executed and completed in 1 frame?

HMart said that another way it could be used is as the name of a placeholder spawnarg (like gui::gui_parm6) on the attached entity, that has the function name, e.g.:

runScript "gui::gui_parm6";

True?
Geep

Geep

07.10.2023 16:38

reporter   ~0016109

Also, thanks for "vec4" keyword. I will change wiki to say it's forthcoming in 2.12
stgatilov

stgatilov

08.10.2023 07:35

administrator   ~0016110

Yes, if you have a GUI, you can put it into "onAction" handler of some window/button so that it gets executed on LMB click.
The global function can be anywhere, files don't matter at all for script I believe.
The script function is executed in a new script-thread, so there is no problem if it would wait/take time.

As for putting function name into gui parameter, I think it should work due to how GUI scripting works in general.
Geep

Geep

08.10.2023 19:26

reporter   ~0016111

OK. Other questions are -
- does runScript have to be the last statement in an onAction event block?
- if not, can two calls be in separate arms of an if...else... (only one of which will execute)?
- or can there be arbitrary number of runScript calls within a given event block (each given its own script-thread)?

As for use cases for *extensions* of runScript, what immediately comes to mind is to allow it to be in onTime and indeed every "on..." handler, so it can be used for debugging, by calling functions that in turn print to console.
stgatilov

stgatilov

08.10.2023 19:49

administrator   ~0016112

There can be any number of runScript, in if-s or not, last or not.
It is executed like any other command.

However, the command does not immediately call the script when executed.
It only puts into into a buffer.
When GUI script is over, all the script threads are created in "delayed" fashion (i.e. it will start at this or next frame --- not sure about details).
This is of course true as long as someone pulls the information from the buffer...
Geep

Geep

09.10.2023 22:25

reporter   ~0016113

FYI, HMart in the past provided some code to extend namedEvents:

https://forums.thedarkmod.com/index.php?/topic/20100-idtech-4-gui-scripting/#comment-439778
Geep

Geep

10.10.2023 02:20

reporter   ~0016114

Wiki page "GUI Scripting: Commands" discussion of runScript is now updated to reflect info here. Check it out.
stgatilov

stgatilov

10.10.2023 06:31

administrator   ~0016115

Yes, he provided a particular implementation: global event and immediate&nested execution.
But he never questioned whether this is compatible with e.g. Quake 4 or not.
boissiere

boissiere

10.10.2023 18:47

reporter   ~0016116

I'm quite interested in getting the runScript functionality to work (better).

First off, someone asked for possible use cases. I can give several.
1) In the recent thread https://forums.thedarkmod.com/index.php?/topic/22217-gui-displaying-different-sections-of-xdata-file/ , datiswous asked if it was possible to develop a template for an enhanced type of briefing where people could specify a different background for each page of text (possibly by having different xdata items for each page)
2) It would also make it easier to develop a in-game journal type of readable which is added to when the player does certain actions. A current example of this is done in the first mission (Monastery) of a House of Locked Secrets but the implementation is quite cumbersome because
a) Each xdata item contains the whole contents of the 'previous' xdata item plus the added text.
b) The in-game actions have to be performed in a pre-determined order.
3) Readables could be made more sophisticated e.g. having tabbed pages (e.g. in a paper address book).
4) You could have dynamic entity guis (e.g. destination displays at railway stations which change when the train has left).

However for any of these to work properly, the scripting language will need to have access to the gui based variables ("text" etc). Scripts *can* access these but only if the qui has been created as an overlay. There are a number of script functions that manipulate gui variables but they all take an overlay handle as a parameter. This can be passed in by existing readable scripts because it has created the overlay in the first place - a script function called from a gui script won't have that value and that's assuming the overlay exists in the first place which won't be the case for briefings or entity guis.
Geep

Geep

10.10.2023 18:53

reporter   ~0016117

"But he never questioned whether this is compatible with e.g. Quake 4 or not."
Fair enough.

You asked some additional questions - as "(1)" above - that I can't really answer. I guess I thinking of this as analogous to a LMB press, that tries to find an onAttack handler in a stack of gui's. However, the fact of the match-by-name makes this more precise and also could (conceivably) be raise-one-event to many-event-handler-instances.

I think I was just channeling HMart's namedEvent enthusiasm when I suggested this as a feature. Maybe this needs to be dropped or kicked down the road, pending a compelling use case.
Geep

Geep

11.10.2023 15:01

reporter   ~0016118

"However for any of these to work properly, the scripting language will need to have access to the gui based variables ("text" etc). Scripts *can* access these but only if the qui has been created as an overlay. There are a number of script functions that manipulate gui variables but they all take an overlay handle as a parameter. This can be passed in by existing readable scripts because it has created the overlay in the first place - a script function called from a gui script won't have that value and that's assuming the overlay exists in the first place which won't be the case for briefings or entity guis."

There are other C++ internal pointers, such as "idUserInterface *gui", and maybe, with work, a pointer like that could be exposed and made viable for use when an overlay handle is not available?
Geep

Geep

11.10.2023 15:52

reporter   ~0016119

More elegant: if you have a custom non-overlay GUI, give it's (top-level only?) windowDef an FM-unique name, e.g., not "Desktop". Then there would be new script functions that take that name instead of an overlay handle.
stgatilov

stgatilov

11.10.2023 16:19

administrator   ~0016120

Reading what boissiere wrote, I think none of the issues are solved simply by the "runScript" feature.

In fact, similar cases inside core TDM are solved by having a persistent game thread which polls some GUI variables and modifies other GUI variables if necessary.
That's how readables are implemented at least.
Having GUI code run game scripts in this case is bad idea, because:
  1) Having both GUI and script control some common state will cause terrible logical issues and race conditions.
  2) GUI scripting are very bad in terms of features, and totally broken in terms of order of evaluation.

----------------

As for accessing entity GUI (i.e. the GUI which is attached to an entity via spawnarg in .map file), it is indeed possible to expose these GUIs (and their variables) to game scripts just like overlays.
But this will work only for fully mission-defined GUIs, which are probably quit rare, no?
I mean: TDM is not Sci-Fi with screens and computers...
stgatilov

stgatilov

11.10.2023 16:39

administrator   ~0016121

I have created forum thread:
  https://forums.thedarkmod.com/index.php?/topic/22239-gui-features-runscript-and-namedevent/

Perhaps migrate to there, since I guess these discussion can become quite lengthy =)
Geep

Geep

11.10.2023 17:21

reporter   ~0016122

I see your point about the very bad features and potential for logical/race issues.

"As for accessing entity GUI (i.e. the GUI which is attached to an entity via spawnarg in .map file), it is indeed possible to expose these GUIs (and their variables) to game scripts just like overlays.
But this will work only for fully mission-defined GUIs, which are probably quit rare, no?
I mean: TDM is not Sci-Fi with screens and computers... "

Perhaps this is chicken-and-egg... fully mission-defined GUIs may be rare to date because of lacking functionality. boisserie gave the train-station-schedule example. I think "magic mirror" effects, puzzles, and dynamic location maps could benefit.
Daft Mugi

Daft Mugi

11.10.2023 18:34

developer   ~0016123

re "TDM is not Sci-Fi with screens and computers."
Did TDM lose the computer screen ability that Doom 3 has?

I can see mission authors wanting to mix in sci-fi elements.
In fact, I have a mission in mind that I'd like to create that would use sci-fi computer screens.

I recommend that we keep or restore in-game GUI screens.
datiswous

datiswous

19.12.2023 12:02

reporter   ~0016249

[quote]Did TDM lose the computer screen ability that Doom 3 has?[/quote]
See: https://forums.thedarkmod.com/index.php?/topic/12987-interactive-gui-surface-question/
stgatilov

stgatilov

04.02.2024 09:25

administrator   ~0016478

It is weird to call this issue "fixed", because:
  trivial p.3 was done
  it was learned that p.1 works as intended
  p.2 is not done

I'm pretty sure the namedEvent command (p.2) should still remain in the bugtracker.
nbohr1more

nbohr1more

20.02.2024 18:17

developer   ~0016539

Moving to 2.13 since there are open sub-tasks

Issue History

Date Modified Username Field Change
14.11.2022 21:07 stgatilov New Issue
14.11.2022 21:07 stgatilov Status new => assigned
14.11.2022 21:07 stgatilov Assigned To => stgatilov
14.11.2022 21:16 stgatilov Product Version => TDM 2.11
14.11.2022 21:16 stgatilov Target Version => TDM 2.12
15.11.2022 20:10 Geep Note Added: 0015433
04.10.2023 19:49 stgatilov Note Added: 0016099
04.10.2023 21:11 stgatilov Note Added: 0016100
05.10.2023 19:46 stgatilov Note Added: 0016105
05.10.2023 19:46 stgatilov File Added: vec4_in_gui_hacky_background
05.10.2023 19:52 stgatilov Note Added: 0016106
07.10.2023 16:35 Geep Note Added: 0016108
07.10.2023 16:38 Geep Note Added: 0016109
08.10.2023 07:35 stgatilov Note Added: 0016110
08.10.2023 19:26 Geep Note Added: 0016111
08.10.2023 19:49 stgatilov Note Added: 0016112
09.10.2023 22:25 Geep Note Added: 0016113
10.10.2023 02:20 Geep Note Added: 0016114
10.10.2023 06:31 stgatilov Note Added: 0016115
10.10.2023 18:47 boissiere Note Added: 0016116
10.10.2023 18:53 Geep Note Added: 0016117
11.10.2023 15:01 Geep Note Added: 0016118
11.10.2023 15:52 Geep Note Added: 0016119
11.10.2023 16:19 stgatilov Note Added: 0016120
11.10.2023 16:39 stgatilov Note Added: 0016121
11.10.2023 16:39 stgatilov Additional Information Updated
11.10.2023 17:21 Geep Note Added: 0016122
11.10.2023 18:34 Daft Mugi Note Added: 0016123
05.12.2023 01:48 nbohr1more Status assigned => feedback
19.12.2023 12:02 datiswous Note Added: 0016249
04.02.2024 05:33 nbohr1more Status feedback => resolved
04.02.2024 05:33 nbohr1more Resolution open => fixed
04.02.2024 05:33 nbohr1more Fixed in Version => TDM 2.12
04.02.2024 09:25 stgatilov Note Added: 0016478
04.02.2024 13:30 nbohr1more Status resolved => feedback
04.02.2024 13:30 nbohr1more Resolution fixed => reopened
20.02.2024 18:16 nbohr1more Resolution reopened => open
20.02.2024 18:16 nbohr1more Fixed in Version TDM 2.12 =>
20.02.2024 18:16 nbohr1more Target Version TDM 2.12 => TDM 2.13
20.02.2024 18:17 nbohr1more Note Added: 0016539