Building on proposals #1224 and #1906, courtesy of @Shadowblitz16...
No active project. Have used UE4 for projects in the past. Supported an alternative structure that I miss, namely Blueprints. The ease of use of Blueprints in Unreal and the myriad of people who enjoy them are the "existing practical use cases" of demonstrating the usefulness of the proposed feature, albeit not a Godot context.
In Godot Engine, script-classes make scripts almost a first-party type system. Global names. Static typing. After #22, they become more widespread. After #18, we get data structure / serialization support.
But, while scenes are a declarative extension of classes defined by scripts, it is quite easy to create a script that becomes dependent on its scene in order to function properly. And yet, in those cases, people still have the ability to make the script without the scene. And if you just load the scene, then you don't have enough type information to treat it like a class (cause it isn't a Script). Furthermore scripts and scenes have potentially divergent or even unrelated inheritance hierarchies (wat). Conceptually, that's just plain weird when you want them to be consist (I will grant, there are use cases for the flexibility, so it is needed).
We don't have any utilities to make things easier though. Controlling runtime instantiation of scripts to guarantee they are only ever made inside the proper scene is unreasonably difficult at the Script/Object/ScriptServer level and far too invasive. Querying for PackedScene inheritance hierarchies against a Node, a Script, or another PackedScene is all too complicated (I've written hundreds of lines of code just trying to make sense of it in a ClassType script to abstract everything). Abstracting resource loading so you don't have to worry about whether your loading a Script or a PackedScene is also frequent and frustrating.
TLDR: It isn't good that we tell people scenes help you make classes when they aren't actually classes and we don't help scripts and scenes work together as one, just to ensure we have the flexibility of keeping them separate. We need an optional alternative that provides an opinionated tool for automating the complexity of keeping them in sync where its most needed.
Take Blueprints as an example. The "scenes" are classes in their own right which fulfill all requirements of being a Script. The scene has Script-ed type information, a "built-in" script at the root, and a guarantee that the script will never be instantiated outside of that scene. And yet, derived "scenes" can extend the same "built-in" script safely. Instantiating this type of "script" actually instantiates the scene internally.
I would dub this new type of resource a ScriptScene.
Pros:
Cons:
.cs file to work.Script/PackedScene format again. So, you're locked into that fused inheritance chain once you're in it. On the bright side, you can still change base Script or PackedScene classes separately with no negative consequences, so it shouldn't be that big of a deal in practice imo.ScriptScene would likely be a resource that extends Script, but which owns a PackedScene and a Script and that delegates most of its responsibilities to the internal Script, yet has the ability to load and save itself like a scene with a built-in root script (that way the Godot Editor just sees it as a scene where you can click on the built-in script at the root). The reason it would need to extend Script would be for the sake of other languages being able to load the file and perceive it like they would a script (either out-of-the-box or by casting or something); by extension this would enable static typing and the like.
Honestly, the biggest complexity I see in supporting something like this is figuring out how you would get script logic to "load" the file as if it were a Script (where calling new() just calls instance() on the scene under-the-hood), but make only the Editor "load" the same file as if it were a PackedScene. And I don't think the TOOLS_ENABLED stuff would cut it here cause different parts of the Editor might also need to be able to recognize it as a Script.
I leave that for discussion below.
Edit: note that, even though it's technically a new kind of Script, it's actually more like it's a new scene file format, as far as the scene editing system is concerned, but where it's perceived as the root built-in script in all other contexts. It's not exactly like it's a new scripting language per se.
I could easily envision people creating entire projects with nothing but ScriptScenes in place of managing both Scripts and PackedScenes for their project, so long as they only ever planned on using GDScript, VisualScript, etc. for their project. So yes, if the feature existed, it very well could be used a lot.
And no, there is no existing simple solution in scripting to do this, as evidenced by my rejection of such solutions here.
Now, if some select changes were made to the engine, there is a different viable option that makes it easier to implement a similar idea in script code (https://github.com/godotengine/godot-proposals/issues/1906#issuecomment-735451623), but I ultimately believe a different, more thorough approach will yield stronger benefits since this version naturally has support for more languages without custom language code and better satisfies the requirements of the problem without requiring boilerplate code for every class that is declared.
Technically, you could probably get away with something similar in script code using a mix of PluginScript, some sophisticated resource format loader/saver stuff (maybe with some changes to core?), but PluginScript doesn't have script class support (and #22 actually makes no mention of adding it - not sure how that would be done). And what's more, PluginScript is badly documented with many just not knowing how exactly it works (NativeScript is already complex enough without adding PluginScript on top of that). An add-on is just plagued with all sorts of issues that become far easier to identify, address, and resolve in engine code.
Not to mention, making it a built-in feature would just be a lot more useful to a much wider collection of users, especially considering the percentage of users that exclusively use GDScript and VisualScript for their projects (something like, what, 60+%?). And even to people who also use C# and/or GDNative C++, they can always mix and match what kinds of scene files they use for different parts of their project, so again, still useful to a massive audience of Godot users, especially beginners.
I like this idea but I have issues with it not supporting C# scripts as that's what I am going to once C# support is complete.
Is there a way to support multiple script types?
@Shadowblitz16 With this proposal, it entirely depends on the script information being something that is an embedded resource of some kind (a "built-in" script).
The only way you could potentially work with all scripting languages would be if you took @dalexeev's suggestion and implemented a separate solution for each scripting language to be able to bind a given Script resource to a particular PackedScene.
The only problem I see with that approach, aside from the annoyance of needing so many different language changes, is that you'd also have to add logic in various places to prevent users from being able to create an instance of a scene that splits the inheritance chain.
But, who knows, maybe that approach would be simpler and more flexible in the long run, and my initial worries about it are for nothing. For example, if you added a scene file path to the script class info that can be registered (actually, wouldn't want to require that a scene-bound script is a script class), then you'd effectively have most everything you needed to get started, aside from the instantiation logic and the scene-design checks that the Editor would need to perform.
I guess, actually, in retrospect, I'm thinking that dale's suggestion might be a better way to go provided that we make sure to add tooling that reinforces the constraints it defines for the script - because PackedScene can't do the job itself, and scripts won't be aware of the scene context either, so the Editor has to do all of the heavy-lifting.
I'll leave this open for a little while, just in case others want to see it and give feedback on it, but chances are, we'll end up going down the Dale rabbit hole on this one simply because it doesn't have the "built-in" script limitation. Was really hoping for a one-size-fits-all kind of solution using the resource system, but if a language-specific solution can handle it better in practice, then the work's gotta be done. 🤦 🚶 🏗️ 🏛️ 💯
The current system is ok but this idea to associate script with the whole scene should bring simplicity in many ways.
So why not go further and removing the existing scripting system by this proposal. "ScriptScene" should simply be "Script".
It is generally hard to convince people to drop some flexibility in favor of simplicity, but I will try anyway.
IMO the scene is a natural scope for scripts.
@DriNeo Firstly, you should clarify whether you are saying that every Script should be paired with a PackedScene resource on a mandatory basis, or whether you think the above proposed ScriptScene concept should be the only scripting option available.
If the latter, I would be completely against it, precisely because it forces "built-in" script usage, which not all languages support, and for which you are unable to use third-party text editors that come with far more features than Godot's provided ScriptEditor.
If the former, it's actually even more unreasonable from an architectural view because Script is something that is placed on the Object class, not the Node class. As such, there are many, many types for which mandating a PackedScene is irrelevant. The base Script type shouldn't need to know anything about Node/PackedScene. If we do add info to scripts about an associated scene, as per @dalexeev, then it should be an optional feature that only specific implementations of Script have to be concerned with.
Even if you have an optional scene-binding feature, you still accomplish most of the same benefits/pros that you suggest, but you also keep the flexibility at the same time (except for your last two simplification points).
I agree that scenes are a natural scope for Node-extending scripts, but I also think there is a place for being able to quickly add a bit of custom functionality to a Node type without the burden of having to create an entirely new scene just to do it.
@willnationsdev I totally ignored the current Godot classes in my post. It is a concept inspired by Shadowblitz posts and yours : a scene is not only a collection of nodes, a script property is added, like the current node has one. Whatever the script is a GDScript bytecode or a GDnative binary. This idea assumes a flexibility cost, like you said at the end.
Not sure how to implement that and how to expose the scene properties in the UI, as the scene is a different concept here (maybe in the script dock ?). I found simplicity beautiful and I can sacrifices a lot to avoid choice paralysis and learning time. But I also understand the flexibility loss can be unacceptable for some users. I hope I helped people to explore this topic by throwing this idea.
@DriNeo Yeah, I'm just glad we've got people discussing the issue(s) in the first place. XD