How to deal with weapon action function in scripting

Discuss anything ZDoom-related that doesn't fall into one of the other categories.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49184
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

How to deal with weapon action function in scripting

Post by Graf Zahl »

I think it's better to bring this topic out in the open, because I just fail to get the right idea to solve this.

As many may know there is a major problem with DECORATE and action functions that get called from weapons. Due to the way a few functions were implemented - most notably the user variable stuff, these essentially end up with a 'self' pointer whose class does not match the calling object.

In any language, 'self' is supposed to be of the same class as the defining object, but when being called from weapon states this is not the case, so we end up with a huge problem once we allow to actually script action functions. As an example, lets assume you have a new weapon

Code: Select all

actor MyCoolWeapon : Weapon
{
   int mycoolvariable;
}
With scripting you could do something like

Code: Select all

states
{
Fire:
   A_MyCoolWeaponAttack("MyCoolProjectile");
}
and later in the same class define

Code: Select all

action void A_MyCoolWeaponAttack(class<Actor> projectile)
{
   // do something interesting with the given projectile name.
}
All this looks pretty straightforward and simple. Now where the problem comes in:

Internally that function above gets defined as

Code: Select all

void A_MyCoolWeaponAttack(MyCoolWeapon self, Actor caller, StateInfo stateinfo, class<Actor> projectile)
And it HAS to be defined like that, if it was used from inside the weapon's spawn state, so that it is possible to access the class fields (e.g. mycoolvariable)
But when called from a weapon state this will fail, because essentially it will get called like

Code: Select all

   A_MyCoolWeaponAttack(player, self, stateinfo, "MyCoolProjectile");
which creates a type mismatch between 'player' and 'MyCoolWeapon'. This is essentially the cause for the access errors with A_SetUserVar.

My first idea was to use the second parameter, formerly 'stateowner' as self and rename the actual 'self' to 'caller'. But this causes other problems that, for example, calling A_Die from a weapon state, would try to kill the weapon, not the player.

The actual problem for this entire mess is actually, that there is not enough information to decide what a state is being used for until it is being called.
There is absolutely no way to tell at compile time to know if a state is being called from the weapon item itself or from the HUD sprite representing it, so it is impossible to make decisions based on the actual use case. With Dehacked in play this will get even nastier because it can change around state info at will and completely mess things up.

I believe this can be solved, but first I need to get an idea of how much added burden would be acceptable for the users here.
My personal view is to have a special qualifier for weapon-allowed action functions so that 'self' is of type Actor, but to make that work, the 'States' block needs to be broken up into one for regular states and one for inventory-releated states like weapons and CustomInventory because otherwise there is no way to decide where a state may be used.



Now, as long as functions are all native, this can be controlled, but with scripting this is either something the modder has to be aware of, or some clear rules have to be established that make it possible to recognise the different use type of states, and at the same time maintain DECORATE compatibility. And this is what I think needs discussion.
User avatar
Player701
 
 
Posts: 1685
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: How to deal with weapon action function in scripting

Post by Player701 »

I don't have a lot of experience with modern DECORATE features, but I always watch the bugs and feature suggestions forums and I'm mostly aware of the current DECORATE capabilities. From the point of view of a "casual" modder (well, the one who makes simple stuff and mostly for personal use), your proposal looks good to me in terms of usability. IMHO, splitting the "States" block will make the code easier to read and understand. However, experienced modders may not agree with me.

What about non-functional user variables in weapons, though? If I remember correctly, that bug was closed with the resolution "Can't fix". Will the new scripting features allow user variables in weapons to function correctly at last?
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: How to deal with weapon action function in scripting

Post by Graf Zahl »

The thing about user variables in weapons is not that hard. That it cannot be done in DECORATE is more a limitation of the parser than the engine.

If a function is called from a weapon, it will receive two pointers: self and invoker. So all that needs to be done is to call

invoker.GetUserVar("blah") to fetch it from the weapon, while
GetUserVar("blah") will translate to self.GetUserVar("blah") which will fetch it from the player.
User avatar
Nash
 
 
Posts: 17465
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: How to deal with weapon action function in scripting

Post by Nash »

I have no problems with having to separate the regular Actor States with specially-designated weapon/inventory/etc States. Reminds me of namespaces and I think that just makes code more organized IMO, and therefore the pointers would have a clearer context when used.
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: How to deal with weapon action function in scripting

Post by Graf Zahl »

I had some time to think about it when I realized something:

In the entire DECORATE code there's precisely 4 action functions that actually work on the item itself and all 4 are internal and should be declared private to Inventory anyway.
Furthermore, there is very little use in creating new functions for inventory items that need to access the added data provided by inventory items.

This means that this can be resolved with far less impact on how mods are made and maybe even backwards compatible with DECORATE.

There's two subclasses of Inventory that can run states in another actor's context: Weapon and CustomInventory. Let's derive both from a special Inventory subclass, let's call it StateProvider, (because it provides states to be run by another actor) and add a special condition for this class that it limits the self pointer of its action functions to class Actor.
That way anything declared in those classes will automatically throw errors if elements of the defining class are accessed and all functions are safe by default for being run outside of them.
The nice thing is, this would fully propagate to DECORATE, even existing mods, and immediately report an error if some action function improperly tries to access the item's user variables, instead of only causing problems when the bad code runs.

And if there's really someone who absolutely needs a function that accesses the item's non-class-Actor member variables directly in its spawn state, well, I think it's acceptable if they have to add an explicit cast for this particular situation.
User avatar
Leonard2
Posts: 313
Joined: Tue Aug 14, 2012 6:10 pm

Re: How to deal with weapon action function in scripting

Post by Leonard2 »

Doesn't this mean that the user variable access problem will still remain unfixed?
I would really like to be able to use those defined with my inventory class.

How long have we waited for this again only to not get this kind of crucial stuff fixed?
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: How to deal with weapon action function in scripting

Post by Graf Zahl »

It can't be fixed like that - that part is utterly impossible. If the 'self' pointer is the player you cannot access the weapon's user variables (or anything else) through that pointer - for the simple reason that it doesnt point to the weapon.
The 'invoker' pointer points to the weapon so you have to access the weapon's user variables through that.

Normally, 'self' really should be the weapon, but that'd cause so many problems that it's not an option, because it'd be incompatible with anonymous DECORATE functions, which get executed in the same context. This is 10 years of baggage that cannot be undone. But be it as it may, you will be able to access the weapon, but you have to use 'invoker.blah' to get its 'blah' variable.
User avatar
Nash
 
 
Posts: 17465
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: How to deal with weapon action function in scripting

Post by Nash »

That's really good enough IMO - having access to the weapon's variables via invoker is better than not having any access at all. :O
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: How to deal with weapon action function in scripting

Post by Graf Zahl »

I just added the handling for this class in the zscript branch. It really seems the best way to deal with this because it's mostly transparent to the modder, unlike every other idea I had.
User avatar
Nash
 
 
Posts: 17465
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: How to deal with weapon action function in scripting

Post by Nash »

2 questions:

1) How soon will this be functional and ready for modders to test?

2) What kind of modifications will this system allow? Are we still going to get that low-level Thinker access that was promised by Doomscript, or is this just "DECORATE but better"?

This reason I ask; not because of pressure or impatience, but just as a time estimation. If it's going to be a loooooong time from now, I could put in some work to prototype whatever I need with cringe-worthy ACS, and THEN port my stuff over.

If it's not far off, I will not waste my time typing any more ACS because enough is enough. :D

And it's good to know what will modders be able to do or not do, what is possible and what is clearly way beyond what this system can offer.
User avatar
Player701
 
 
Posts: 1685
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: How to deal with weapon action function in scripting

Post by Player701 »

I'm sorry if this is not the right place to ask this. If so, please split this post into a separate thread.

I have a few questions regarding weapons, user variables, and the upcoming scripting features. They are all given in the context when the new features are available, of course.
  1. What happens with the values of a weapon's user variables when it is picked up or dropped by the player?
  2. What happens with the values of a weapon's user variables when it is picked up by the player when they already have a weapon of this type in their inventory?
  3. I want to get the player's current ammo capacity for the weapon's AmmoType / AmmoType2 in the weapon's code. Is it possible?
Note that there is a possible answer to the third question which is "put the name of the ammo class manually in your code"; however, it is not entirely correct. Although this approach is already possible with the current feature set, it suffers from the following drawbacks. First, it will not be possible to generalize the function's code and move it to a parent class - I suppose it will be supported in the new feature set. And second, the main purpose is to avoid repetition of values. Putting the same value in the code several times in cases like this will make it difficult to avoid bugs when the said value is changed, for the programmer might simply forget to change it everywhere.
User avatar
randi
Site Admin
Posts: 7749
Joined: Wed Jul 09, 2003 10:30 pm

Re: How to deal with weapon action function in scripting

Post by randi »

  1. Nothing. They stay on the weapon.
  2. Picking up a weapon you already have just gives you it's ammo and ignores the rest. You would need to override its pickup function to do anything more specific.
  3. Not with decorate.
User avatar
Player701
 
 
Posts: 1685
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support

Re: How to deal with weapon action function in scripting

Post by Player701 »

randi wrote:Not with decorate.
And not even with the new scripting features too?
User avatar
Leonard2
Posts: 313
Joined: Tue Aug 14, 2012 6:10 pm

Re: How to deal with weapon action function in scripting

Post by Leonard2 »

Now I think your solution is good, one thing however:
Graf Zahl wrote:But be it as it may, you will be able to access the weapon, but you have to use 'invoker.blah' to get its 'blah' variable.
I get that the arguments can't be swapped internally as the function will be called with the same pointers etc, but can they be switched in the context?
I mean this way we don't have to write invoker.myvar to access variables declared and if something needs to be done on self instead write self.something.
To be more clear I mean only when the zscript is parsed/compiled, it would make so much more sense and be consistent to have direct access to the declared variables and act on the self using the pointer instead.
Otherwise it's like people writting "this->stuff" in a c++ method.

While we're here let's discuss some other stuff:

Can you clarify this:
Graf Zahl wrote:The scripting language won't allow a goto, it also won't allow A_Jump constructs, but real script syntax instead. In this area the main objective will be: no stopgap measures. Period.
That really sounded exciting for me, I thought perhaps you would have come up with a new state syntax/grammar that would solve the problem of virtual goto jumps (even if it needs to have the internal state system to be extended) and allow some crazy stuff such as dynamic tic duration (calculated per-frame of course and maybe even have a way to use a boolean condition that is evaluated each tic to determine if the frame is still on or if it should go to the next one) and maybe even a dynamic sprite/frame selection that would be flexible enough to allow to do things like "####" or "----" on our own but I see none of that in the scripting branch.
All I can see is that it's exactly like the decorate syntax except you put semicolons at the end of frames.
Graf Zahl wrote:but it'll be a bit more like Java where you only have objects and don't need to think about the difference between an actual object and a pointer referencing it.
How does that work?
Quick example, let's say I have 2 classes 'X' and 'Y' in which I have a "mystruct" member.
If mystruct was a pointer, I would have only one actual object and any change made to it would be noticeable by both X and Y.
If it's not a pointer then I would have 2 objects and I would need to make the change to both classes's mystruct member.
That sounds like a terrible limitation.

Another thing is const variables declaration.
Why have this:

Code: Select all

const myconst = 99;
when we have this:

Code: Select all

int myint = 99;
Why the inconsistency? Isn't const supposed to be a qualifier?
It just doesn't make sense to me.
Nash wrote:Are we still going to get that low-level Thinker access that was promised by Doomscript
AFAIK zscript would be capable of it but some internal changes to allow it would be needed.
The actor class could inherit from an abstract thinker class in which some pure virtual functions like "Tick" are declared.
The actor class's tick function would just map to the native/internal AActor::Tick() in zdoom.
That would allow people to make some interesting stuff I'm sure.
Nash wrote:or is this just "DECORATE but better"?
I seriously hope not.
We waited more than ten years and so many stuff was promised to be fixed/made better with zscript.
That would honestly be the BIGGEST let down ever for me.
User avatar
randi
Site Admin
Posts: 7749
Joined: Wed Jul 09, 2003 10:30 pm

Re: How to deal with weapon action function in scripting

Post by randi »

Leonard2 wrote: How does that work?
Quick example, let's say I have 2 classes 'X' and 'Y' in which I have a "mystruct" member.
If mystruct was a pointer
All structs are values, and all classes are references.

Return to “General”