Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better System for a true OOP workflow #1224

Closed
Shadowblitz16 opened this issue Jul 20, 2020 · 21 comments
Closed

Better System for a true OOP workflow #1224

Shadowblitz16 opened this issue Jul 20, 2020 · 21 comments

Comments

@Shadowblitz16
Copy link

Shadowblitz16 commented Jul 20, 2020

Describe the project you are working on:
Spaceship game

Describe the problem or limitation you are having in your project:
I just find it difficult to work with godot's OOP nature when godot's scripts don't truly extend anything just add logic for it

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
Basically the idea is to get rid of scripts attached to nodes and introduce a true OOP script system.
Basically the way it would work is scripts would no longer be attached to nodes but instead the scripts would be the nodes!

for example...

  • you would no longer attach scripts to nodes instead you would extend nodes by inheritance.
  • you would no longer create scripts in the scene view you would instead create them in the file view.
  • you would beable to drag script files that inherit nodes directly onto the scene! or pick them from node browser dialog.
  • nodes and resources would inherit the icon of its parent but you would beable to supply your own!
  • no longer would the node creation browser or resource creation browser list the script beside the node or resource it would actually be considered a new node!

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
ClassSuggestion_ScriptDialog
ClassSuggestion_NodeDialog
ClassSuggestion_ResourceDialog
ClassSuggestion_InspectorDialog
ClassSuggestion_SceneDialog

extends Node
class_name MyNode
export(float) var some_value
extends Resource
class_name MyResource
export(float) var some_value

If this enhancement will not be used often, can it be worked around with a few lines of script?:
This would be used more then you would think especially in C#

Is there a reason why this should be core and not an add-on in the asset library?:
Godot is OOP by design however it feels like it uses some weird one script ecs even though its actually just oop.
why not abstract the layer away?

@Jummit
Copy link

Jummit commented Jul 20, 2020

This is very close to the class_name functionality, which adds the node to the add node dialog. You can also supply your own icon.
https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_basics.html#classes

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Jul 20, 2020

sorry the suggestion wasn't about changing class_name.
it was about abstracting away scripts and treating them like actual new objects.

I have updated my post to reflect that

@Rubonnek
Copy link
Member

@Shadowblitz16 it sounds like you want something like what willnationsdev implemented.

@Shadowblitz16
Copy link
Author

@Rubonnek no this doesn't have to do with multiple scripts at all.
Its has to do with getting rid of the current node script relationship and actually having true oop

@Shadowblitz16
Copy link
Author

I updated one of the pictures to get rid of the add script icon to be more clear

@willnationsdev
Copy link
Contributor

willnationsdev commented Aug 20, 2020

@Shadowblitz16

I actually initially proposed doing something like this way back before even the 3.0 release. I got this huge big PR put together that tried to simulate everything as if they were fully classes, with no things being "attached" to objects. There was a TypeDB instead of a ClassDB, and it synchronized type inheritance between Engine types, scripted types, and even scenes. The editor UI was gonna be updated to kinda merge everything together. I had big plans. But, I did way too much work without consulting anyone about it (the naivete of youth) and was shot down by reduz after he'd had a chance to look at it. The reasons (which were justified, in retrospect):

  1. Invasive changes that radically changed the engine core without being substantiated by an active use case needing to be overcome. If you look at the contributing guidelines, you'll see that you need to have an actual problem with an attempt to implement a feature or work with the editor or something, before a change can be deemed necessary. Your statement, "I just find it difficult to work with godot's OOP nature when godot's scripts don't truly extend anything just add logic for it," essentially amounts to, "I just don't like the way it feels." Now, in terms of usability, there is a point being made here, but the drastic level of changes necessary to pull it off, the added complexity it would introduce, and the relatively miniscule difference it makes in the usability in comparison just don't justify the depth of changes.
  2. Reduz was very clear that he does not want to hide information from users. Hiding the existence of the script layer over the Object API would either force limitations on what we can allow people to do (can't change or update Script details at runtime - presents issues for editor/tools/debugging) or would cause a documentation hazard as we attempt to hide their existence, but people continuously run into bugs resulting from user error because they don't know how the script system works internally. Basically, nothing good comes from hiding useful information from users.

After receiving this feedback, reduz then attempted to cater to my (and many others') concerns by implementing the class_name keyword and "script class" system that you see in GDScript today.


you would no longer attach scripts to nodes instead you would extend nodes by inheritance.

Hides information from users. No-go.

you would no longer create scripts in the scene view you would instead create them in the file view.

I don't really understand this point. Even if you had scripts simulated exclusively as derived Objects, it would still make sense, for usability reasons, to allow people to right click on a Node and "extend Class" or something to launch a new script editor. And you can already create scripts and scenes from the filesystem dock.

you would beable to drag script files that inherit nodes directly onto the scene! or pick them from node browser dialog.

I think we should already be able to do this with script classes, no? Or if you can't drag it into the scene, I'm sure that's a feature you could independently request.

nodes and resources would inherit the icon of its parent but you would beable to supply your own!

This is already supported with the script class system. If you are wishing for this to be present in C#, know that there is already a draft pull request to add script class support to many other languages in various ways. I've run into problems getting C# to work, but it is still planned. See godotengine/godot#40147.

no longer would the node creation browser or resource creation browser list the script beside the node or resource it would actually be considered a new node!

Hides information from users. No-go.


I do have a different proposal I plan to submit to better synchronize the type system, but it won't be nearly as drastic a change as what I once proposed previously, nor what you've proposed here. When it's made, I can link it here.

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Aug 21, 2020

@willnationsdev it well it depends on the implementation.
hiding information and actually having true oop is basically the same thing.
I mean when it comes down to it oop in c++ is basically nested structs
its not bad to hide something if it improves workflow and if what your hiding is irrelevant
hiding in that case is good as it simplifys the workspace

@willnationsdev
Copy link
Contributor

@Shadowblitz16

its not bad to hide something if it improves workflow

The problem is that hiding the existence of scripts actually impedes users, in any context, from maintaining the same set of features that they currently support.

If I wanted to right now, I could create a "game" which was actually an editor for my own use. And I could empower users to manipulate objects in my game by allowing them to manipulate the script, including changing it's content at runtime based on their modding/editing of features or what-have-you. They could also change the script on an object to effectively change its type or instantly extend it while preserving data.

However, if you hide the existence of scripts, and don't expose that functionality to end users at all, then an entire domain of using Godot Engine is cut off outside of the Godot Editor which magically knows of the existence of scripts behind the scenes.

The workflow is effective enough as it is in my opinion since, afaik, everything that someone could want to get out of making more "legit" classes has already been implemented with scripts already existing. Can you name an actual feature that you are missing or a bug that occurs due to scripts' existence being public?

The only "workflow" improvement I can think of is one of you mentally not knowing of the existence of scripts (slightly "cleaner" concept). But, rather than that being a workflow improvement, doing so would actively inhibit a whole range of workflows (not mentally, but concretely).

if what your hiding is irrelevant
hiding in that case is good as it simplifys the workspace

The point is that it isn't irrelevant. Hiding the information only restricts how people can use the engine, and for an inadequate reason to justify it.

@Shadowblitz16
Copy link
Author

then we should be able to attach multiple scripts.

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Sep 18, 2020

@willnationsdev
@Jummit
@Rubonnek
So one of the main reasons that keeps putting me off to godot is the fact I have to manage two different inheritance hierarchies.

  • scenes
  • scripts

the idea of this was to only have 1 inheritance hierarchy so game development would be easier.

@willnationsdev
Copy link
Contributor

then we should be able to attach multiple scripts

I'm not sure how that follows. You've stated that your concern is that Godot's inheritance/type system is too complex. We outlined how hiding scripts' existence isn't an appropriate solution. Given that, how is going the other direction and supporting multiple script inheritance simultaneously something that solves the problem? If anything, it drastically increases the complexity of that same type system.

In fact, they once attempted to implement a scripting language for creating a stack of different languages' scripts, called MultiScript, but it proved far too complex to use or maintain in practice, so they removed it. It never even made it to a stable 3.0 release (godotengine/godot#8718).

So one of the main reasons that keeps putting me off to godot is the fact I have to manage two different inheritance hierarchies.

  • scenes
  • scripts

the idea of this was to only have 1 inheritance hierarchy so game development would be easier.

The original issue was about abstracting away the differences between engine classes and scripts. Now we are expanding it to scenes as well (which makes sense - part of the "type" system to some extent). It is true that scenes have independent inheritance hierarchies, and that dealing with differences between them and engine classes'/scripts' is a big pain.

However, the solution you are alluding to, if I assume correctly, is that we should unify the type system completely and make it so that Godot's API is more similar to that of Unreal's Blueprint system.

  1. You'd add a new type, called e.g. ScriptScene which would be a Script that has a PackedScene bound to it, where the root node of the PackedScene had to have the given Script attached to it.
  2. Any script extending a Node type would automatically load as a ScriptScene rather than a Script.
  3. You'd prevent any ScriptScene from sharing a root node script with another (i.e. enforce a 1-to-1 relationship).
  4. ScriptScenes would be able to have child ScriptScenes just like they'd have child Nodes (these still have differentiated because you can "open" ScriptScenes, but not engine classes).

Now, assuming my assumptions are accurate, and this is what you intended by your proposal, then here are my thoughts:

  1. I personally wouldn't actually be so opposed to such a reinvention of the engine's API. On the front-end side of things, it definitely makes the engine a lot easier to digest, and it seems like it would make it a lot easier to use too. The unification just does away with a whole realm of potential bugs and misunderstandings. It would actually be a really cool change imo, but implementing it would be riddled with extreme logistical challenges. You'd have to enable such features without ruining the currently clean and maintainable codebase.

  2. In order to prevent such changes from inhibiting people's existing use of the engine, you'd need to ensure that all existing supported features are maintained across the transition, even if in a slightly different form.

    1. Runtime-editing of types would be required. So, there'd be no way to "lock in" that a class is a static thing that cannot be changed, as you previously suggested.
    2. To support having multiple scripted nodes within one scene, you'd just have to get people used to the idea that they must now have dedicated scenes for those scripts. This would be more of a prejudicial issue, solved with documentation and good argumentation of the benefits of the paradigm.
    3. To support having multiple "constructors" of the same type by way of having multiple scenes with the same root script, you could implement a mechanism that allows scripts to define multiple constructors for themselves (and therefore allow a single ScriptScene to have multiple definable node hierarchies/configurations within it). As long as the end result is a class of the same type, with the same public interface and inheritance hierarchy.
    4. To support having scripts with no scene, you'd need to have a much more dynamic Editor UI that adapts to a script's type more effectively. That way, people who don't care about the scene for a script can at least feel like they aren't dealing with a scene at all.
  3. There's the difficulty that Scripts are defined in /core, but Node and PackedScene aren't defined until /scene. So, Script's, and the things loading scripts in /core, actually have no awareness of the existence of nodes or scenes in the first place. So, you'd have to find a way to, in /scene, have the high-level game framework override any attempt to load a Script and instead make it load a ScriptScene. That way, /core can continue to exist as a low-level API without any awareness of the game framework, and keep everything secluded in /scene.

  4. There's the difficulty that Scripts are generally independently editable in external text editors, so their files must remain plain-text formats that contain only script information, with no scene data. But you also need scene data to be usable in both text and binary formats. This means, you'd have to generate scene files, and have the editor modify scene files, without impacting the script code. All that together means there's no real way to have both the script and the scene use a combined file format. This, in turn, makes making, sharing, and organizing "classes" a far more complicated and cumbersome task.

    If there were going to be any dealbreaker in the logistical challenges, it would be this one. You'd effectively need to associate a given directory with a class, and enforce only a single script and scene file within that directory, optionally accompanied by other related assets. The problem is, that doing so makes Godot far more opinionated about file structure than it currently is, and the core devs generally shy away from things that demand arbitrary requirements of the file system structure. Currently, the only such requirement is the addons being located at res://addons/*, but even this will fade in the future when they implement the Sub-Project system (New Add-On (sub-project) system #1205).

  5. You'd also have to make major revisions to the Godot Editor so that scripts were more or less hidden and everything, including scenes, were abstracted into ScriptScene class definitions built on engine C++ classes.

Now, even if you could do all of these changes, and you found a way to make it work, the fact of the matter is, I can almost guarantee you that no core developer is going to support it only because the huge amount of development time, research, bug fixing, and documentation updates that such a massively invasive change would require make it prohibitively expensive in terms of labor.

The only way I could see this remotely happening is if some extremely motivated individual decides to implement all of these features on their own, just because they wanted to, in a hard fork of the engine. Then, they showcase this hard fork. They demonstrate the concrete changes they had to make. They illustrate, with a concrete implementation, how much better the usability and accessibility of the engine and API have become. They prove that the idea works, that it is possible to convert the main Godot project to that format, etc. And then they convince folks to merge those changes.

But even then, it's a big gamble for a lot of work without a guaranteed result. I mean, at a bare minimum, you'd have an alternative version of Godot that supports a different style, but then the motivated individual would be the only one maintaining it while everyone else is moving on with the original project.

More than likely, the core devs would instead want to solve the original problem you are having somehow without making such crazy invasive changes. Like creating a dedicated class or global function that facilitates performing the operations you need to handle abstractions for you. Or creating an EditorPlugin that automates editor tasks and manipulates the GUI to make it seem like a ScriptScene system exists rather than what actually exists. And then those would be things that people can just add to the engine to make it work differently if desired. That proposal would be way more likely to be accepted imo.

@Shadowblitz16
Copy link
Author

so your saying even though it might be a good idea to merge the two inheritance hierarchies into one its most likely not going to happen due to the complexity of the task?

@willnationsdev
Copy link
Contributor

willnationsdev commented Sep 18, 2020

@Shadowblitz16 Exactly. I mean, I can see how it would be useful, but the main issue I foresee is that point number 4. The way Unreal handles it, you can't visualize code-based scripts at all. In order to visualize them, you have to extend the class into a "Blueprint" which inherits the C++ script functionality and creates a Blueprint file format that supports visualization. But then you are locked into that file type (a non-plain-text data file rather than just script code).

The equivalent in Godot would be to mark whether a script is a standalone script, which can be edited anywhere, including an external editor like VS Code, or whether it's a ScriptScene which has visualization as a scene, but a non-script file format that's script can only be edited within the Godot Editor's ScriptEditor (which knows how to navigate the scene format to find the script and update it reliably). This wouldn't impact GDScript, VisualScript, or PluginScript that much (or any other module that uses the ScriptEditor), but it would significantly impact things which rely on an external editor.

For C#, the only way to visualize your content in a scene would be to create a derived class which provides visualization, but restricts you to the ScriptEditor (not optimal), so people would be incentivized to either improve the ScriptEditor to accommodate or problematically make all their changes in a base class and just let the derived class in the scene act on the base class's behalf. That is, you'd have faux, empty classes that just inherit another class in order to work around the fact that C# doesn't have good ScriptEditor support.

It's certainly doable, but I believe that restriction would make the core devs think not just twice, but many, many times over about merging such changes that limit how people can use the engine. You effectively make the engine a lot more opinionated and controlling about how you work with it for the sake of improving usability. But, until you can prove that all of that work would actually improve usability, it's all just hypothetical and therefore wouldn't necessarily be worth all the effort to build.

Now, given the things I've outlined above, it might actually be possible to implement all of the above using addons, now that I think about it. Just create an alternative file format for scenes and build all of your scenes using that file format, rather than the .tscn PackedScene file format. It would also be easy enough to convert a Script/PackedScene to/from a ScriptScene I think. At least, on a basic level. Then you could create this system purely as an option that anyone can apply to their engine, rather than it being a core thing that the developers have to maintain. The only problem would be if the Editor is missing certain hooks to let you edit/access parts of the editor you want to modify to improve the user experience of this plugin. In which case, you'd just need to submit a pull request to expose that access and it would be no big deal.

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Nov 23, 2020

@willnationsdev So what about implementing a true type system for nodes and script relations?
Then your not hiding anything and you still have the separate scene a node hierarchy.

Scripts would actually be nodes!
Existing scripts could be translated from C++ to GDNative and it would ensure that the same methods that implement the built in nodes could be used by the user.

Scripts could then be dragged into the scene as nodes because they would be them

@willnationsdev
Copy link
Contributor

willnationsdev commented Nov 24, 2020

So what about implementing a true type system for nodes and script relations?

Scripts would actually be nodes!

Overall, just so far, I'm a little confused by what you mean here.

Existing scripts could be translated from C++ to GDNative and it would ensure that the same methods that implement the built in nodes could be used by the user.

Here you seem to elaborate on the above comments. The idea being to outsource things inside the engine to external assets that can be fully rewritten in GDNative script code and downloaded from official sources.

There are actually plans to do this for the less-often-used nodes in the engine, e.g. VehicleBody. However, a few issues from your idea.

  1. If you port something to GDNative, then you still have to manually specify which parts of that class should be exposed to other scripting languages. That's why GDNative C/C++ have register_* methods that explicitly bind code to the scripting API and allow other scripts, like GDScript and VisualScript, to access those properties/methods/constants/signals. You won't just instantly "ensure that the same methods [they] implement...could be used by the user," as you suggest.
  2. If you port a core type to GDNative, only GDNative classes would be able to directly extend and access those classes. GDScript, VisualScript, and C# would have to resort to the core Object API to even understand what the type is, and would not be able to extend it regardless.

Going back to the "Scripts would actually be nodes!" idea, if you also outsourced the Node and Resource classes so that "all of their methods could be exposed to scripting" in some form or fashion (even if it was only GDNative scripts), then all of the other languages would suddenly be unable to extend the Node or Resource types. Therefore, the core system of Godot wouldn't have any way of communicating. So, at a bare minimum, you'd need Object, Resource, Node, MainLoop, and SceneTree to be in the core rather than in GDNative.

But even if you did manage to port most of the /scene and /modules directories to external assets that are downloaded to individual projects as scripts, you'd then have all kinds of weird usability problems where no one is able to directly extend any of those classes with their preferred scripting language (GDScript, VisualScript, C#). And performance would take a hit too since you're now shoe-horning in Variant binding between method calls where previously there was none.

If you wanted to add inheritable support for every language, you'd have to re-implement the class in each language, and each language's implementation would have different performance constraints (so a GDScript VehicleBody would execute code much more slowly than a C# or C++ VehicleBody, etc.). In the current form, each language all makes use of the fast engine C++ code, so a GDScript VehicleBody is just as fast as a C# VehicleBody. It's only when you add more and more customized runtime logic on top of the VehicleBody class that you start to see larger differences in performance.

Another consideration is the Server classes which are also exposed to the scripting API (RenderingServer, AudioServer, PhysicsServer2D, etc.). If you also want all of their methods exposed so that people can directly implement and override their methods, you'd just be asking for people to wreak havoc with their engine runtimes if they don't know what they're doing. Would need tons of documentation.

Although, I do think there are plans to make it easier for people to provide their own implementations of the physics server in later versions of Godot (like 4.1 or something). And the RenderingDevice/RenderingServer code is already being massively redesigned to allow people to more easily customize the rendering pipeline in Godot 4 thanks to reduz's work.

My point being, the more stuff you move out of the core, the slower Godot becomes and the more difficult you make it for users to freely extend and use the stuff in the engine. So, while there are plans to do this, it is only for a handful of types, and mostly for things which don't require heavy customization to be useful. That, or they are for standalone systems that are to be swapped out in their entirety (like swappable Server implementations).

Scripts could then be dragged into the scene as nodes because they would be them

Isn't this already doable for any script that extends Node? I know it is for scenes, but I would've thought scripts supported it too. If not, then wouldn't be too difficult to implement, I would think. Double-check, and if it isn't, you can open a proposal for it.

@Shadowblitz16
Copy link
Author

@willnationsdev see #1876 I think it may be a better implementation and might be more inlined with godot's design philosophy

@Shadowblitz16
Copy link
Author

@willnationsdev #1906

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Apr 11, 2021

Reopening this.
@willnationsdev I would like to know how hiding the existence of scripts actually impedes users.

Its much easier to just inherit something and create it then attach a script that might be removed.
If anything it improves the workflow.
The only way it would impedes users is if we could add multiple scripts to a node in the first place which we can't.

Godot talks about its design philosophy as being the reason we don't have a multi script/unity3D like ecs workflow,
but when people want to improve the way OOP is handled its downvoted and disregarded by reduz and the main developers

also what even makes it a script vs a new object? a script does exactly that it creates new objects so I don't see your point

@dalexeev
Copy link
Member

As far as I know, GDExtension makes it relatively easy to add your own full-fledged classes, including Nodes. But allowing GDScript classes to actually inherit C++ classes is probably technically impossible.

However, it seems to me that in theory we can change the UI of the editor in such a way that there will be an illusion of full-fledged classes (lack of the Attach Script button, etc.). But this is a lot of work, which is definitely too late to start for 4.0. Maybe for 5.0. And I'm not sure it will bring much benefit. Although, I imagined it, and it seems to me that it will improve the user experience and, in a sense, change the minds of users a little. I can draw some mockups if you like.

@Shadowblitz16
Copy link
Author

@dalexeev can you? I think most of my suggestions are shutdown because I can't properly communicate to other people due to my disabilities.

It's kinda the reason why I get frustrated and close my issues

@Shadowblitz16
Copy link
Author

This may come with gdscript and C# being ported to gd extension

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants