ZScript Discussion

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

EVENT SYSTEM EXAMPLE (and prototype design doc) FOR GRAF (and everyone else)
Disclaimer: I'm not 100% sure about any of this, any suggestions or requirements on how to improve it are totally welcome.

https://github.com/jewalky/gzdoom/commi ... eisnospoon — source
http://www.mediafire.com/file/3zxaib4r4f6my96/REL.zip — build + example

0. Technically, this implements the OOP Observer pattern in relation to the engine and not exactly hierarchical 'events' as we know them by various GUI or DOM systems.
0.1. The observers are not planned to be able to interact with each other right now.
1. Subset of Render events was implemented, if this is to be accepted we will have to think about other virtuals that should be there (and do some performance tests, for example I'd want to implement something like "RenderActor" so that it's possible to know what actors were actually rendered during last frame (use-case: "a picture of an angel becomes an angel"), but not sure if calling the VM for every drawn actor won't bring it to a crawl; maybe replace virtual methods with abstract, if possible, so that unimplemented methods aren't called excessively).
1.1. Current implementation allows for sub-gametic and sub-renderframe precision in scripts.
1.2. The generic point is: any EventHandler can override any virtual method (and it will be called), but event-specific handlers have additional data.
2. To run the example, use the GZDoom version from the archive and load EventDemo.pk3, then spawn TestActor then spawn any actor. Look into the portal: actor will be RED there, but not red in the actual map!
3. Some things are not done even though planned. For example, MAPINFO-based handler instantiation and addition.
4. Sound doesn't work in my build, make sure that you don't overwrite your normal GZDoom! I don't have FMOD libraries on my PC, and their new website is [censored word] and requires registration, so I'm too lazy to do it.
5. There are no checks for registering one handler twice, I know about that. And will fix if we agree on this. (and if not, it doesn't matter)
6. By the current architecture, if you want your handler to be gone on map unload, you have to do it manually: MapUnloading + Destroy();. This is because in the future, if we use this for UI, we will need to be disconnected from the map.
6.1. Note that this is not yet implemented ;P The event handlers are destroyed by the GC right now it seems.
7. Statusbar suggestion: permanent class StatusBar : UiEventHandler object that gets created by MAPINFO/GameInfo on engine start, doesn't get removed by map unload and checks for gameaction/gamestate in order to decide current state.
(yes I've seen it in the GZDoom commit history that there are preparations in the repo to move sbar out :))
7.1. This raises another problem: serialization of event handlers. We don't want our old statusbar to restore from the savegame, and we don't want our statusbar to be gone if someone loads a savegame that doesn't have it.
(note: read 'statusbar', understand 'anything that has to be global');
What I have in mind right now:
7.2. There should be two kinds of handlers (this is changed dynamically throughout map lifecycle): those defined in MAPINFO, and those created with EventHandler.Create.
7.3. Handlers that are defined in MAPINFO can be only only one per map, trying to EventHandler.Create an instance of a handler that already is loaded using MAPINFO should result in an exception.
7.3.1. Subvariant: I don't see when we might want to have same handler both dynamically and statically, so we can have these "inherit" from StaticEventHandler instead, and somehow make this translate into isStatic boolean in EventHandler structure.
7.4. Handlers that are defined in MAPINFO are implicitly transient: they are not serialized, instead null is written. If one wants to refer to a global handler, they should use EventHandler.Find.
7.5. When the save game is loaded, MAPINFO handlers are recreated based on their settings for the particular map.
7.6. Based on exact place of MAPINFO where handlers were defined (GameInfo or Map section) they will or will not be deleted/recreated on map unload/load.
7.7. Handlers that were temporarily created from the map, on the other side, are serialized along with normal objects and with their references and state fully preserved.

Side note: I needed to provide it an Actor in order to call A_Log.
We desperately need something like Console or System in order to call Printf static method from it.
Last edited by ZZYZX on Sun Jan 22, 2017 1:47 am, edited 27 times in total.
ZzZombo
Posts: 317
Joined: Mon Jul 16, 2012 2:02 am

Re: ZScript Discussion

Post by ZzZombo »

You know that is also dangerous? Replacing a class that is used by other classes w/o their knowledge? Wait...
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

Well that's historical heritage from DECORATE.
I strongly suggest adding a keyword that prevents using 'replaces' with a class, as in causing a compilation error.
User avatar
Gutawer
Posts: 469
Joined: Sat Apr 16, 2016 6:01 am
Preferred Pronouns: She/Her

Re: ZScript Discussion

Post by Gutawer »

ZZYZX wrote:EVENT SYSTEM EXAMPLE FOR GRAF (and everyone else)

https://github.com/jewalky/gzdoom/commi ... eisnospoon — source
http://www.mediafire.com/file/3zxaib4r4f6my96/REL.zip — build + example

1. Subset of Render events was implemented, if this is to be accepted we will have to think about other virtuals that should be there (and for other handler types).
1.1. Current implementation allows for sub-gametic and sub-renderframe precision in scripts.
1.2. The generic point is: any EventHandler can override any virtual method (and it will be called), but event-specific handlers have additional data.
2. To run the example, use the GZDoom version from the archive and load EventDemo.pk3, then spawn TestActor. Look into the portal: actor will be translucent there, but not translucent in the actual map!
3. Some things are not done even though planned. For example, MAPINFO-based handler instantiation and addition.
4. Sound doesn't work in my build, make sure that you don't overwrite your normal GZDoom! I don't have FMOD libraries on my PC, and their new website is [censored word] and requires registration, so I'm too lazy to do it.
5. There are no checks for registering one handler twice, I know about that. And will fix if we agree on this. (and if not, it doesn't matter)

Side note: I needed to provide it an Actor in order to call A_Log.
We desperately need something like Console or System in order to call Printf static method from it.
This seems pretty cool. Would be interesting to see uses such as, for example, an enemy that can be viewed through a camera, but when the player looks at it, it is completely invisible. Sort of like a ghost that the human eye cannot see.
User avatar
Rachael
Posts: 13738
Joined: Tue Jan 13, 2004 1:31 pm
Preferred Pronouns: She/Her

Re: ZScript Discussion

Post by Rachael »

Gutawer wrote:This seems pretty cool. Would be interesting to see uses such as, for example, an enemy that can be viewed through a camera, but when the player looks at it, it is completely invisible. Sort of like a ghost that the human eye cannot see.
That's already possible using [wiki]A_CheckSight[/wiki]. This function does not check for camera texture viewing, as far as I know.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

The point is that you can have the same monster both in camera and real view (consider something like "videocam" weapon with small cameratexture drawn on it, like this), and it will only be visible in the cameratexture :)
User avatar
Rachael
Posts: 13738
Joined: Tue Jan 13, 2004 1:31 pm
Preferred Pronouns: She/Her

Re: ZScript Discussion

Post by Rachael »

Ahhh. Yeah that's a bit different.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

I could use this to paint enemies a different color when in AEoD's demon morph to be precisely like painkiller's...
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

This particular one would be something like renderthingbefore and renderthingafter, because you need to somehow store the old value for enemy color, etc.
Currently you'd have to implement a custom actor class to be 100% sure that everything is preserved properly.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Spawn another class and store its translation in it, which then reapplies it after its done. Yeah, a hack but it'll do as a substitution since GZDoom's lightamp effect is inflexible.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

The whole point of event system is to reduce the need to hack things to the absolute zero. Or at least something near that value. So yea, if it doesn't allow something, it's probably a reason to reconsider the design spec.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Then show me how you would do it, please. I have no idea how that would work.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

Major Cooke wrote:Then show me how you would do it, please. I have no idea how that would work.
Something like Qt's polish/unpolish approach, if anyone here is familiar with that.

Code: Select all

class RenderEventHandler : EventHandler native
{
  Actor CurrentThing; // default null

  virtual native void RenderBeforeThing();
  virtual native void RenderAfterThing();
}
So then you can override RenderBeforeThing and RenderAfterThing, and save current state in first and restore in second (to a handler field).
And refer to the currently processed thing as CurrentThing.
The problem that I have with this currently, is that things are not processed one-by-one, they are stored as a vissprite list (and analogous structure in the GL renderer). So we can have a Before, but not After. Or it can be an "after" that is called once the vissprite is added to the list... going to test.

(also: yet another reason why I'm storing ViewPos and rest of things in the structure as opposed to passing by parameter: during all Render* callbacks that are going to be there, View*, FracTic, and other fields will represent the actual current state!)
Last edited by ZZYZX on Sat Jan 21, 2017 10:08 pm, edited 3 times in total.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Go for it! I'd love to see that in.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

http://i.imgur.com/JJgNka4.png
Too lazy to update the build, but in the ZScript source it's defined like this: http://pastebin.com/Tb5dh0uA
Also, I changed the code so that it doesn't call the stub implementations of the virtual methods.
This should make it a tiny bit faster (I don't experience any speed issues right now anyway, will have to test with something like our favorite FrozenT once static handlers are implemented).
It's a shame that you can't retrieve the current renderstyle though.

Also, another use-case for Render*Thing hooks: you can create a custom actor type and store last tick on which it was rendered with it's subsector.
Then you can turn off/on spawners instead of relying on CheckSight, since CheckSight doesn't account for lots of scenarios, and Render*Thing is guaranteed to execute if you are going to see the actor. Especially useful with SpawnParticle-intensive stuff as these are extremely limited. Or if I wanted to implement something like this in all seriousness for use in actual production map.

EDIT: updated the build for MAPINFO static EventHandler definition.
Currently there are two types: if you put it in Map{}, it will be loaded on map start and removed on unload.
If you put it in GameInfo{}, it will be loaded directly after scripting engine initialization and removed...well, never.
Checked with FrozenT. No performance regressions found :P
Checked with nuts.wad. FPS dropped from 67 to 35, but then again, it's 10000 monsters rendered at once.

Serialization is still not done (not sure if it serializes automatically, but probably not; if it DOES, then I have to actually make it not serialize).
Last edited by ZZYZX on Sun Jan 22, 2017 2:17 am, edited 1 time in total.

Return to “Scripting”