Godot: MultiScript and "overlapping" method names

Created on 26 Apr 2017  Â·  19Comments  Â·  Source: godotengine/godot

Godot version: 3 master

Issue description:
MultiScript has some inconsistent way in which it works with "overlapping" methods.

Some methods like _init and _process are called on every script, while others like _ready, _enter_tree and name_your_function are called only on the first script where it is defined.

This makes not possible to do common things like initialize variables on secondary scripts when the node enters the tree, also not possible to make a single function call affecting all the scripts, reducing the usability of MultiScript.

I would prefer to have everything called on every script, if I do $Node.foo(), have ScriptA.foo() and ScriptB.foo() executed.


And what if foo() returns a value? I have no idea...

I wonder if will be needed some kind of keyword before func to control the way multi-methods are called (call all, just the first, override, and things like that).

Or maybe a multi version of call, a multi_call that returns an array of results (but the problem with enter tree and ready persist).

Steps to reproduce:

  • Make two scripts with _init, _ready, enter_tree, _process and another function
  • Check the method calls, notice on which scripts are called each.
archived bug discussion core

Most helpful comment

The "class fusion" nature of multiscript is the problem, another thing would be if is implemented as a kind of interface or polymorphism but making the extra scripts pure Object (no ready, no process, just regular variables and methods).

All 19 comments

The problem is that it's impossible to have multiple scripts on one object. So what I'm doing is create a dummy object for every script that just call()s the real object.

_init gets called when the script instance gets created, so that happens on every script (because I attach them to an object).

call() stops after the first script that implements that method, notification and call_multilevel call it on every script. So that's where this behavior is coming from.

I agree, it should be more consistent, but the return value problem is a real problem

IMO calling the same function name on all scripts is a no go. By itself this problem makes me wonder if it's worth it at all to reintroduce MultiScript.

I think it should not be allowed to define the same function name in sibling scripts. The parser should raise an error if it happens. Callbacks like _init, _ready or _draw are specific to the node, and not to its script, so it shouldn't be necessary to call them in each script. If all sibling scripts have a _draw call, what's the draw order?

All in all this is raising quite some complexity. How does member var scoping works in MultiScript? Do all scripts share a same scope as if it were one file, or are they handled as separate classes?

now I understand why @reduz doesn't want it.
how does unity handle this?
as I remember, it's something like get_node(path).get_component(script_name).func_name().
(don't want to search it...)

edit: I think I misunderstood what OP said about anyway...

@akien-mga if I want to update all the variables on a node, I will need to call update functions on all the scripts, if I don't know which scripts are there, I won't know which functions update each script (a script can access another script variable but defeats MultiScript purpose, I think).

The scope seems to be shared but (now) the first script sets the variable and methods (tested with export too), but is strange, some may expect the last script overrides the first :upside_down_face:

@volzhs in Unity scripts are completely separated objects that must be called explicitely (gameObject.GetComponent<Foo>().SayHello()), but they share the same GameObject through a gameObject property (note: nothing inherits GameObject, everything is done through components). Special functions such as Update, FixedUpdate or OnGUI are called by the engine on all scripts defining the method. No inheritance, no multicall wizardry. Their execution/call order doesn't matter, unless specified in project settings. Sometimes (for image effects) their order in the component list is used, for the OnRenderImage I think but I'm not sure.

The "class fusion" nature of multiscript is the problem, another thing would be if is implemented as a kind of interface or polymorphism but making the extra scripts pure Object (no ready, no process, just regular variables and methods).

Can't multi scripts be implemented as traits like in php and bind to parent script via for example "Inherits" keyword? This will solidify override order and double calls for _ready and other functions may be resolved this way. But this may need more complex script handling as well.

I think this whole feature is unnecessary. If you start using Godot, coming from Unity, you may want something like components, but as soon as you understand the engine's design you'll realize, there is no need for this.
But if we really want to implement this, I think we should go with Unity like components, while keeping the current script system. So, for example, each object could have a list of scripts (besides the original single script), maybe as @eon-s said attached to other objects or some special helper class.
But that's almost the same as adding additional nodes with scripts to your original node.

There is one use case where I think a feature like this would make sense. When you write an EditorPlugin that adds custom node types, the instanced nodes all share the original script, and you can't just add a new script like you would do with the built-in node types. Of course there are many ways around this, but at least this is a case where I would like to have the ability to add a second script.

It was just a test. Some users want to try it out regardless, but I'm okay with removing it again

I also think it might better to remove it, as users might try to use it
instead of just using children nodes...

On Apr 29, 2017 2:03 PM, "Thomas Herzog" notifications@github.com wrote:

It was just a test. Some users want to try it out regardless, but I'm okay
with removing it again

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/8546#issuecomment-298164811,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AF-Z22IxcXaHGIqGk2u_Iks_81pydCHgks5r0ycBgaJpZM4NI0Tw
.

instead of just using children nodes...

Which is more performant though, children nodes or multi script? Even if the node is just a dummy Spatial or Position, I guess it takes memory, doesn't it?

@Zireael07 you can use Node, which is the dummyest node you can create in Godot ;) it will always take a bit of memory though

Although the multi script might really be faster, I don't have any numbers, and in my opinion it just doesn't worth the extra hassle, and primes that comes with it.

I would like to ask a question because I am curious. What is the difference between the multiscript feature and the current ability to load script files in your node script ? I apologize if the answer is obvious.

@DriNeo If you load a script file in your script then a second script can't easily all methods on that. If you use a multiscript then you're merging multiple scripts.

So you can have one script that handles signals for physics (in an Area or a PhysicsBody) while other scripts do something completely different

Thanks.

Closing with the removal of the multiscript module.

What if the new inline inspector (https://twitter.com/reduzio/status/997078709847834624) allowed nodes in the same way as resources? If all NodePath variables were also shown inline.
I.e. add children nodes with scripts and allow them to be shown in the inspector, and not just in the scene tree. They are then usable with $component1, $component2, etc, while the appearance is similar to Unity's.

Was this page helpful?
0 / 5 - 0 ratings