ZScript "Standard Library" - Brainstorming

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript "Standard Library" - Brainstorming

Post by Major Cooke »

Not trying to rain on your parade but:
  1. Consider using a regular zip file instead of .7z so people can open it up with SLADE.
  2. I don't really see what purpose this may serve, honestly.
Maybe I'm just blind to what it could be for, but one could easily replace it with something like this:

Code: Select all

if (!master) return Destroy();
double mpitch = master.pitch;
double mang = master.angle;
Vector3 StickerPos = master.Vec3Angle(cos(mpitch) * 20, mang, -sin(mpitch) * 20);
SetOrigin(StickerPos);
And if you just want the roughest degree to be a whole number, turn mpitch and mang into ints.
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript "Standard Library" - Brainstorming

Post by Matt »

You're also the guy who told me it wouldn't make any difference making the same calculation 6 times in a row as opposed to storing a variable.

However, I did finally get around to benchmarking it:

Code: Select all

class CrudeSiner:IdleDummy{
	states{
	spawn:
		BAL1 A 1 nodelay{
			for(int i=0;i<10000000;i++){
				speed=(HDLib.CrudeSine(self,24));
			}
			A_LogInt(speed*1000);
		}wait;
	}
}
class FineSiner:IdleDummy{
	states{
	spawn:
		BAL1 A 1 nodelay{
			for(int i=0;i<10000000;i++){
				speed=(sin(24));
			}
			A_LogInt(speed*1000);
		}wait;
	}
}
and while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.
User avatar
Major Cooke
Posts: 8193
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

Re: ZScript "Standard Library" - Brainstorming

Post by Major Cooke »

I was in a rush, didn't read it properly, that's all. I thought it was an organization thing you were asking, not what you had originally asked.

Anyway, yes. I figured the sine table would've been problematic, and that's why I suggested the other thing.
Gez
 
 
Posts: 17924
Joined: Fri Jul 06, 2007 3:22 pm

Re: ZScript "Standard Library" - Brainstorming

Post by Gez »

Vaecrius wrote:while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.
Yeah, the overhead from calling a VM function is so great that the gain from using a precomputed table is irrelevant.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript "Standard Library" - Brainstorming

Post by ZZYZX »

What happens if you use an array without a function, like sintab[int(angle)%360]? Does it give any performance boost?
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript "Standard Library" - Brainstorming

Post by Matt »

How do you do that, though? Please don't tell me we need to do sintab[0]=0 all the way through 360...
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript "Standard Library" - Brainstorming

Post by ZZYZX »

Fill it somehow. For example, on BeginPlay of a persistent thinker. for (int i = 0; i < 360; i++) sintab = sin(i);
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript "Standard Library" - Brainstorming

Post by Matt »

> asks how to process a large group of numbers on a computer
> use the computer

:oops:

Anyway:

Code: Select all

/*
vid_fps 1;summon cs;
vid_fps 1;summon fs;
*/

class cs:Actor{
	double sintab[360];
	states{
	spawn:
		BAL1 A 10 nodelay{
			for(int i=0;i<360;i++){
				sintab[i]=sin(i);
			}
		}
		BAL1 A 1{
			for(int i=0;i<10000000;i++){
				speed=sintab[24];
			}
			A_LogInt(speed*1000);
		}wait;
	}
}
class fs:Actor{
	states{
	spawn:
		BAL1 A 10;
		BAL1 A 1{
			for(int i=0;i<10000000;i++){
				speed=sin(24);
			}
			A_LogInt(speed*1000);
		}wait;
	}
}
cs:~1550 ms/frame

fs: ~1440 ms/frame

So the native sine calculation is still faster.
User avatar
Nash
 
 
Posts: 17456
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript "Standard Library" - Brainstorming

Post by Nash »

Vaecrius wrote:How do you do that, though? Please don't tell me we need to do sintab[0]=0 all the way through 360...
Make a Console.Printf that writes code for you, and use Logfile before you execute it.

This was what I did to pre-generate array assignments for ~379,000 x 3 variables. It generated a 112 MB ZScript source file. >8D Of course, as I found out, the program actually froze at startup as it tried to compile...

So to answer the question, no, pre-generating your arrays probably won't help either.
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript "Standard Library" - Brainstorming

Post by Matt »

Could your situation have been helped if you somehow broke it up so you only did like a few dozen lines per tic or something?
User avatar
Nash
 
 
Posts: 17456
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript "Standard Library" - Brainstorming

Post by Nash »

Hmm actually my situation is a little different. There were 379k things placed in the map. The map editor would crash if I attempted to add more.

So I had the idea that, instead of pre-placing the things and then at World Load, do a 379-thousand-step for loop to fill in the array (like what you did above)... what if I pre-generate the coordinates and classes into an array list. So I can delete all the things in the map, and the trees would have been "placed" via array definitions instead.

There's no way I'm going to type 379,000 times tree[0].x, tree[0].y, tree[0].class "blah"... so I used a Console.Printf and +logfile to help write code for me. x3

That wasn't a good idea at all, because the program won't even start.

The for loop on map load was actually faster, MUCH faster!

Anyway it wasn't a serious project, just wanted to mess around with ZScript and see what works and what doesn't.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript "Standard Library" - Brainstorming

Post by ZZYZX »

Nash wrote:Make a Console.Printf that writes code for you, and use Logfile before you execute it.

This was what I did to pre-generate array assignments for ~379,000 x 3 variables. It generated a 112 MB ZScript source file. >8D Of course, as I found out, the program actually froze at startup as it tried to compile...

So to answer the question, no, pre-generating your arrays probably won't help either.
Or write a Python script already and stop trying to use ZScript as a general purpose language :P
At least not until file(lump) reading/writing is done properly, lol.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49143
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript "Standard Library" - Brainstorming

Post by Graf Zahl »

Vaecrius wrote:and while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.
The native sine function already uses a table, so you'll have a very hard time beating that. I optimized the hell out of it and it's possibly the most precise fast sine function you'll ever get.
And that doesn't even factor in the VM overhead for calling a script function, which alone is a lot more than the sine function requires to do its job.
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript "Standard Library" - Brainstorming

Post by Matt »

Good to know! I did notice in my subsequent attempts to benchmark stuff that sine functions were abnormally fast compared to what I had been expecting relative to everything else.

(Though I suppose given how relevant these calculations are to projectiles, movement, weapon bobbing, etc. etc. etc. I guess I shouldn't have expected anything less!)
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript "Standard Library" - Brainstorming

Post by ZZYZX »

Hello so I made this https://github.com/jewalky/zgui

You can use it like so:

Code: Select all

class Doom3Element : Element
{
	TextureID mMouseCursor;
	
	override void OnCreate()
	{
		mRect = Rect.FromXYWH(0, 0, Screen.GetWidth(), Screen.GetHeight());
		mScale = 2;
	
		mMouseCursor = TexMan.CheckForTexture("graphics/D3Mouse.png", TexMan.Type_Any);
		AddChild(new('Doom3Doom').Init());
	}

	override void Draw()
	{
		Drawer d = GetDrawer();
		vector2 mouse = GetMouseXY();
		d.DrawTexture(mMouseCursor, false, mouse.x, mouse.y);
	}
}

class Doom3Menu : ListMenu
{
	Element e;

	override void Init(Menu parent, ListMenuDescriptor desc)
	{
		Super.Init(parent, desc);
		DontDim = true;
		
		e = new('Doom3Element').Init();
		e.OnCreate();
	}

	override bool OnUIEvent(UiEvent ev)
	{
		if (e) return e.OnProcessUi(ev);
		return false;
	}
	
	override bool OnInputEvent(InputEvent ev)
	{
		if (e) return e.OnProcessInput(ev);
		return false;
	}

	override void Drawer()
	{
		if (e) e.OnDraw();
	}

	override void Ticker()
	{
		if (e) e.OnTick();
	}
}
What it does: it allows you to have a WM-style hierarchy of Elements with automatic scaling, clipping, text align and wrapping.
Each Element can have a position inside the parent Element (mRect field), and scale of child elements (mScale field). The scale also affects perceived width/height of the Element (the client rect).
Topmost Element has mParent=null which means that it's using the real screen coordinates and scale of 1.0.

Functions exposed to the user are these:

Code: Select all

	virtual void OnCreate()
	{
		
	}
	
	virtual bool Process(ElementEvent ev)
	{
		return false;
	}
	
	virtual void Tick()
	{
		//
	}
	
	virtual void Draw()
	{
		//
	}
The preferred way of constructing Elements is calling "new ('Element').Init()", for example. That automatically sets certain fields to the initial values, otherwise you might end up with a wild null pointer error.
Unobviously enough, OnCreate is actually called when you add a child element, on the child. For a root element, you have to call OnCreate manually or it won't get a chance to initialize.

You can draw things by receiving an instance of Drawer class:

Code: Select all

Drawer d = GetDrawer();
And then using it's methods to draw things as opposed to directly using Screen.
Alternatively, you can instantiate a drawer by using

Code: Select all

Drawer d = Drawer.Create(self);
or even

Code: Select all

Drawer d = Drawer.CreateMod('Drawer', self);
The latter option is for custom Drawer classes if you want to do some fancy stuff.

Also, the system doesn't care about your input/rendering backend — you can provide OnProcessUi/OnProcessInput/OnTick by an event handler, and OnDraw by DrawPowerup (I blame Graf for consistently removing any ways to draw anything while playing the game and providing no alternative), or you can do all this in a menu.
The system is able to receive mouse input both from UiEvent and InputEvent — the elements will receive an uniform ElementEvent anyway. This means that it transparently supports both enabled and disabled mouse in menus.
ElementEvent is the same as UiEvent, except there is no information about pressed modifier keys (yet?)
Also, you can receive the current mouse coordinates relative to the current element (including all scaling) by using GetMouseXY() — which returns a vector2, see the example.

What it doesn't have yet is setting arbitrary clipping values in a Drawer. That'll be added eventually.
Added, actually.

The system is kinda new and untested, pls report bugs if anyone is actually going to use this.

Return to “Script Library”