PDA

View Full Version : Can someone explain "super" and how it works in FGU?



SilentRuin
January 8th, 2022, 22:55
I can never seem to be able to tell when I can just override one function in a .lua file or use the super reference or not.

I would dearly love to understand how to override only the parts I want to override which I can do sometimes and not others.

For example, I can override a <script file... statement in an .xml with no problems at all. I don't need to copy any other part of the xml into my version...

<root>
<windowclass name="TheName" merge="join">>
<script file="somedir/scripts/TheName.lua" />
</windowclass>
</root>

But when I start replacing things in that file (not clone it as that is always a nightmare of risks) I end up with really bizarre things happening.

A clone of the file will always work.

An onInit using super calls and my own code - will work "most times but not all"...

function onInit()
if super and super.onInit then
super.onInit();
end
-- My stuff
end

Even if the onInit works and all previous functions in the original .lua file are left off - they all still work. Sometimes - depends on .lua I'm overriding.

And even when they still work - they won't let me override the individual functions as it seems somehow when I come into this thing triggered externally (via the engine usually - some event or whatever) I can't just replace the function call I'm interested in changing - I have to replace the entire set of functions from the first on* to some unknown level. Not all the way down - and super does work - but its a mystery what I can and can't directly override. For example...

function onSomeButtonPressed()
-- have to clone code - which I don't need as I'm not changing anything but onInit - which works - this button does not
end

function onOtherButtonPressed()
-- have to clone code - which I don't need as I'm not changing anything but onInit - which works - this button does not
end

function onDoingStuff()
-- have to clone code - which I don't need as I'm not changing anything but onInit - now if I've done all this the button works - not I don't need anything in this logic - it just will not work without providing this small subset of the original lua
end

It's even wilder for template script files and how layered down they are.

What I would like is for someone to explain to me the rules for when I can replace functions that I want (and not the whole thing). Because right now it seems random to me on when I can do this (and not clone a function - which I try never to do).

Overriding declared functions (declared with a name for the lua file in extensions.xml) seems to always have super working with no problems - but of course not many things I need are like this - most are unnamed .lua references buried in templates or .xml files.

I'd like to understand how it all works so I don't waste so much trial and error on how to override something with super calls.

Moon Wizard
January 8th, 2022, 23:35
Think of scripts as individual layers that layer over the top of each other. "self" will get the topmost layer; and "super" will get the layer underneath (if any). All scoping is unique to each layer; but will fall through to lower layers if not defined in the current layer.

Scoping does not go "up"; only "down". This means that you can not overwrite functions in lower layers if they are called in lower layers (because the function reference is local to that scope.)

Regards,
JPG

SilentRuin
January 9th, 2022, 00:12
Think of scripts as individual layers that layer over the top of each other. "self" will get the topmost layer; and "super" will get the layer underneath (if any). All scoping is unique to each layer; but will fall through to lower layers if not defined in the current layer.

Scoping does not go "up"; only "down". This means that you can not overwrite functions in lower layers if they are called in lower layers (because the function reference is local to that scope.)

Regards,
JPG

As in my example above, how do I "tell" if I'm overriding what appears to be a top level (.lua script file) that my extension is overriding? I always thought that would allow super calls because mine is overlaying that layer (it's underneath) - yet it never does. Right now I'm overriding CW to make it more as I need it and I keep having to pull in more and more of the charwizard.lua functions - even though I can call super ones within them. It's like if I don't have a certain entry point I can't override the things it calls by themselves - I have to override everything that calls it leading up to it. That is my confusion - how do I tell the layered order looking at the .xml(s) and their scripts (directly defined or in .lua file)? Trying to grok the rules so I know when something won't work except by trial and error (which always has me missing something and I have to drag in more).

Moon Wizard
January 9th, 2022, 07:31
You can't override a lower layer function without replacing all functions that call that function as well. If a call in a lower layer calls a function internally, it will call that scoped version of the function every time.

Remember, each script has it's own scope, and each function is defined within that scope by Lua on load. In reality, even when you layer on top, the lower layer still has the same function defined in it's environment table, and that will be called by any local calls within it's own scope.

{ Scope A (Base) defines function x and function y (which calls function x) }
{ Scope B (Layered) defines function y (replacement) (which calls function x) }
{ Scope C (Layered) attempts to define function x (failed replacement) }

If Scope A version of function y is called, it will use the function x in Scope A.
If Scope B version of function y is called, it will see that no function x is defined in Scope B, and fall through to a lower level to call function x in Scope A.
If Scope C version of function y is called, it falls through to function y in Scope B (which as noted above, calls function x in Scope A)

The function references for Lua environments are set at the time the scripts are loaded, and each file is loaded separately with it's own environment. The Lua indexes fall through to lower levels due to the way that Lua works via the meta indexes on the objects (but it can only go one way due to the way Lua works).

Regards,
JPG

SilentRuin
January 9th, 2022, 14:35
You can't override a lower layer function without replacing all functions that call that function as well. If a call in a lower layer calls a function internally, it will call that scoped version of the function every time.

Remember, each script has it's own scope, and each function is defined within that scope by Lua on load. In reality, even when you layer on top, the lower layer still has the same function defined in it's environment table, and that will be called by any local calls within it's own scope.

{ Scope A (Base) defines function x and function y (which calls function x) }
{ Scope B (Layered) defines function y (replacement) (which calls function x) }
{ Scope C (Layered) attempts to define function x (failed replacement) }

If Scope A version of function y is called, it will use the function x in Scope A.
If Scope B version of function y is called, it will see that no function x is defined in Scope B, and fall through to a lower level to call function x in Scope A.
If Scope C version of function y is called, it falls through to function y in Scope B (which as noted above, calls function x in Scope A)

The function references for Lua environments are set at the time the scripts are loaded, and each file is loaded separately with it's own environment. The Lua indexes fall through to lower levels due to the way that Lua works via the meta indexes on the objects (but it can only go one way due to the way Lua works).

Regards,
JPG

This actually makes sense and helps a lot in my understanding.

So I assume the reason I'm having to "define" things I never call or never use its because some global variable definition is being used from some other scope? I ask because I had to replace functions that had nothing to do with my changes, but somehow when it came in through a different mechanism (LVL UP from charsheet logic for charwizard) it would not work without replacing things that accessed an export variable. That is the kind of weirdness that causes trial and error to figure this stuff out.

So can you verify that a local variable declaration at top of lua file, or inside the .xml it belongs too, is also treated as some sort of function call in terms of scope? I admit this is more confusing to me as the charwizard.lua is defined in one .xml yet when another .xml triggers its owner .xml logic (LVL UP) it somehow requires an entire new branch of the functional code to be dragged in. That is the part confusing me.

Moon Wizard
January 9th, 2022, 17:47
Any scripts that are meant to be modified at that level have to be designed to be modified.

In particular, the Character Wizard scripts are not meant to be enhanced and modified; because they are constantly under flux, as we've been migrating developers on this particular project. I highly recommend not modifying the character wizard in any way; as it receives almost weekly updates and any overrides you write will not get those updates.

Regards,
JPG

SilentRuin
January 9th, 2022, 18:16
Any scripts that are meant to be modified at that level have to be designed to be modified.

In particular, the Character Wizard scripts are not meant to be enhanced and modified; because they are constantly under flux, as we've been migrating developers on this particular project. I highly recommend not modifying the character wizard in any way; as it receives almost weekly updates and any overrides you write will not get those updates.

Regards,
JPG

LOL - and don't I know its under flux! Unfortunately I play games and have players and I need it to do what it used to do in order for them to use CW or the LVL UP option which triggers CW - which is handle stuff FGU does not handle well or really even have a concept for handling - i.e. Supplemental modules. For sure I can still just drop the class over the charsheet class - but I like the way CW is starting to work. And yes I tell people who want to take Advantages its RISKY RISKY and why.

Even now I find myself adding a priority to modules load page so that I can check it in code that needs to pick one thing for my users so they don't get confused on which version we are playing with.

I have a detailed explanation here as I've had to explain the "why" things don't work for supplemental module user in CW and why I did this update (which I do not want to do believe me) for as I've said in a discord post...


And its not a limit of CW - its a limit as I say in how there is no way to say "I want this one when there is more than one choice" in all of FGU - not just CW. They attempt to get around it in CW by hardcoding some things of theirs - which in the wider world does not solve supplemental data.
Or just show a list with everything and say "you choose" neither of which helps something where
THERE CAN BE ONLY ONE (insert highlander picture here)
If you want a workaround - copy everything you want to use in your local DB and remove the modules. Presto - guaranteed work as you wish it.

A detailed explanation so I don't have to repeat it as I'm asked so much is here...
https://www.fantasygrounds.com/forums/showthread.php?59490-Equipped-Effects-Extension-(-ext-file)-Fantasy-Grounds-Unity&p=634543&viewfull=1#post634543

SilentRuin
January 10th, 2022, 20:18
This seemed some a good explanation to reference in here regarding super and self... https://www.fantasygrounds.com/forums/showthread.php?66564-Advantages-Extension-(FGU-5E)&p=634898&viewfull=1#post634898

dsaraujo
January 12th, 2022, 22:15
This thread was enlightening for me too. :)

Fezzik Buttercup
March 29th, 2022, 22:41
EDIT: ignore me; I've given up this tract and trying a different method of getting what I'm looking for. There are some subtleties I'm just not getting (probably in the drag calls)

I think this might be a thread that might help me; I'm not really sure what it is that is causing my problem, but I'll try to sum up.

GURPS has a file <script name="ActionMelee" file="scripts/manager_action_melee.lua" /> in it's /root of the base.xml.

I'm trying to use this file as a base but I have to expand on one of the three functions within (onInit, and modRoll I don't use, just onMelee).

In my xml do I need to (and is TheName the same as TheName.lua, or would it be ActionMelee and manager_action_melee.lua for me?). I don't quite get how to override a gamesystem lua.
<root>
<windowclass name="TheName" merge="join">>
<script file="somedir/scripts/TheName.lua" />
</windowclass>
</root>

Currently my version is in <root>... <base>....<script name="ActionMelee" file="scripts/manager_action_melee.lua" /> ... etc; it works, but it messes up some other functions (namely ones on the character sheet where you roll.)