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 »

Is there any way to transfer strings from ACS to ZScript? (Is there any chance to get such a way in near future?)
I have an ethereal object that rules some logic in my level, but I need to sometimes be able to override it's logic with some preset specified by a string, from an ACS script on a map.

Also, how to use the LevelLocals structure? (is it usable at all?)

Also, dereferencing a null pointer that was declared in function scope results in application crash, as opposed to simple level closing with error message if this is done to a class field.
Test case:

Code: Select all

LevelLocals ll;
A_Log(ll.Music);
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript Discussion

Post by Graf Zahl »

ZZYZX wrote:Is there any way to transfer strings from ACS to ZScript? (Is there any chance to get such a way in near future?)
No, but long term there should be an option to call script functions from ACS and then this should be doable. Right now I have no good idea how to do the interface, though.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

One idea that I had is a function like CallActorMethod(<tid>, <method name>, <print expression>). That would instead of normal printing, generate floats/ints/strings for ZScript.
Not sure if it's possible to make it in this order, as other usages normally put print expression before everything else and separate with ;.
Not sure if it's technically possible either.
But it's probably the best syntax ACS is able to do.
Also probably a variant for calling a static method with providing a class name instead of TID.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript Discussion

Post by Graf Zahl »

Stuff for later. There's still a lot of work to be done on scripting.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript Discussion

Post by Graf Zahl »

ZZYZX wrote: Also, how to use the LevelLocals structure? (is it usable at all?)
You cannot declare local instances of it. This is only there to access the global 'level' variable's members.
User avatar
Major Cooke
Posts: 8196
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Oooh, so it's just 'level.Music'. Okay!
User avatar
Ed the Bat
Posts: 3060
Joined: Thu May 03, 2012 1:18 pm
Graphics Processor: nVidia with Vulkan support
Location: Maryland, US

Re: ZScript Discussion

Post by Ed the Bat »

I've come to find that ThinkerIterator's Next() function becomes incredibly expensive to call if there are a large number of actors in the map, even if they're not the ones. For example,

Code: Select all

	ThinkerIterator it=ThinkerIterator.Create("Clip");
	while((mo=Inventory(it.Next(true)))!=null)
		{...}
This will absolutely destroy performance if there are many actors in play, even if said actors are not Clips. In the instance I ran into this, the actors were snowflakes spawned by the hundreds in a map. Would there be anything that could have been changed in the snowflakes so that Next() will ignore them?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript Discussion

Post by Graf Zahl »

Unfortunately not. A thinker iterator has no good options but to iterate over all thinkers in a map because they are all stored in a list, regardless of type. Of course, those not of type "Clip" will be skipped internally but you are absolutely right that this can become a performance killer if used too frequently on actor-heavy maps.

To give you some help, what's the use case here?
User avatar
Ed the Bat
Posts: 3060
Joined: Thu May 03, 2012 1:18 pm
Graphics Processor: nVidia with Vulkan support
Location: Maryland, US

Re: ZScript Discussion

Post by Ed the Bat »

I have an actor who calls a function every tic (which I know full well is a costly thing to do, so I take responsibility) to see if the actor type I want to scan for (Clip, in the example above, but there are others I'm looking for in practice) exists anywhere on the playing field. If it does, I perform some operations on it, such as spawning another actor in its place if certain conditions exist -- like a more powerful but possibly less graceful version of the 'replaces' keyword.

This seems to work just fine for the most part, but I was playing a large map that features these actors:

Code: Select all

Actor SnowSpawner 27889
{
	+NoBlockMap
	+NoGravity
	+NoSector
	+NoInteraction
	+NoClip
	+CLIENTSIDEONLY
	+SPAWNCEILING
	Radius 1
	Height 1
	States
	{
	Spawn:
		TNT1 A 0
		TNT1 A 0 A_JumpIf(Args[2] > 0,"Circle")
		TNT1 A 0 A_CheckSight("Unsighted")
		TNT1 A 8 A_SpawnItemEx("SnowParticle",Random(-Args[0],-Args[0]),Random(-Args[0],-Args[0]),0,Random(0,1),Random(0,1),Random(-1,-3),0,128,Args[1])
		Loop
	Circle:
		TNT1 A 0 A_CheckSight("Unsighted")
		TNT1 A 8 A_SpawnItemEx("SnowParticle",Random(-Args[0],-Args[0]),0,0,Random(0,1),Random(0,1),Random(-1,-3),Random(0,360),128,Args[1])
		Loop
	Unsighted:
		TNT1 A 1
		Goto Spawn
	}
}

Actor SnowParticle
{
	+MISSILE
	+NoBlockMap
	Radius 1
	Height 1
	Projectile
	RenderStyle Translucent
	Alpha 0
	Scale .7
	States
	{
	Spawn:
		SNOP AAAAAAA 2 A_FadeIn
		SNOP A 3
		Wait
	Death:
		SNOP AAAAAA 1 A_FadeOut(0.2)
		stop
	}
}
...and in many areas, hundreds (if not thousands) of SnowParticles exist together. Even if I were to comment out the body of my while loop, leaving just while((mo=Inventory(it.Next(true)))!=null){}, that alone will bring my machine to a crawl. Heck, even without my ThinkerIterator (playing this map by itself), it can cause a touch of slowdown in some spots from the sheer number of actors.
User avatar
Major Cooke
Posts: 8196
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Couple things I can think of to help with this scenario. Not exactly related to the iterator but...

1. You can optimize the SnowParticle a little bit by having THRUACTORS on them. Or, upon entering the death state, set NOINTERACTION on it and make it A_Stop. Also set the last spawn frame tic duration to -1.

2. Use a BlockThingsIterator for the items. Items don't possess +NOBLOCKMAP and thus are susceptible to this type of iterator (A_RadiusGive, anyone? ;)).

I haven't gotten around to adding the documentation for it yet so you'll have to browse zscript's base.txt file in the wadsrc folder.
Last edited by Major Cooke on Wed Dec 28, 2016 12:18 pm, edited 1 time in total.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript Discussion

Post by Graf Zahl »

Yes, that's a textbook example of something that's not going to work well. Normally I'd say to let your actors count themselves, but with no good means to find out that an item is about to disappear from the map it's not easy. I think the best approach would be to reserve some tids, create replacement items for everything you need to count and allocate a tid for each. You then can let each item set its tid in PostBeginPlay and use an ActorIterator to count them, which is a lot less performance hungry.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

Snow, any kind of snow, is supposed to only be around current camera location. If it's active on the whole map all the time, this is something bad to do in general. Even if it only does sight checks.
Speaking of which, is 'camera' exposed to ZScript? [is it planned to have camera exposed to ZScript? This feature is needed for custom skybox parallaxing and distance/sight-based optimizations]
Last edited by ZZYZX on Wed Dec 28, 2016 12:26 pm, edited 3 times in total.
User avatar
Major Cooke
Posts: 8196
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript Discussion

Post by Major Cooke »

Graf, what about with the BlockThingsIterator? Items are susceptible to it.
User avatar
Ed the Bat
Posts: 3060
Joined: Thu May 03, 2012 1:18 pm
Graphics Processor: nVidia with Vulkan support
Location: Maryland, US

Re: ZScript Discussion

Post by Ed the Bat »

Alright, I'll keep tweaking my setup to see if I can find something I'm happy with. I just figured I'd ask if there was some easy, obvious solution I was overlooking. Thanks for all the info.
ZZYZX wrote:Snow, any kind of snow, is supposed to only be around current camera location. If it's active on the whole map all the time, this is something bad to do in general. Even if it only does sight checks.
It's only active when a player can see it, not all the time. But as I mentioned, it's a very large map. I suppose it could have included a distance check as well as a line-of-sight. I won't defend how the mapper did the map, either, but it is what it is.
Major Cooke wrote:Graf, what about with the BlockThingsIterator? Items are susceptible to it.
Cooke, could you help guide me in setting one up to try it? From what I can tell, BlockThingsIterator.Create will only accept a pointer, not a class name.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript Discussion

Post by ZZYZX »

native static BlockThingsIterator Create(Actor origin, double checkradius = -1, bool ignorerestricted = false);
native static BlockThingsIterator CreateFromPos(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted);

So it allows to either iterate all actors around some other actor (by giving it an origin), or iterate around coordinates by using the pos version.
ZDoom generally uses BlockThingsIterator for collision detection, RadiusGive and things like that.
Last edited by ZZYZX on Wed Dec 28, 2016 12:37 pm, edited 1 time in total.

Return to “Scripting”