armory3d / armory

3D Engine with Blender Integration
https://armory3d.org/engine
zlib License
3.08k stars 319 forks source link

Make VISUAL NODES API same as HAXE API --> Static methods on nodes so that nodes API can be used in HAXE #3000

Open kone9 opened 9 months ago

kone9 commented 9 months ago

The idea of this is to self-document the HAXE API with the nodes API, this way it is simpler to use the Armory functionalities within Haxe.

Captura_de_pantalla_2024-02-13_103613 Captura de pantalla 2024-02-14 083151

It is 100% possible to do this with all nodes

works correctly on linux and windows.

https://github.com/armory3d/armory/assets/12847027/46dae46a-6d49-46b3-8c52-820f2faefed0

You have to tell me if you want or don't want to implement it... if you want I can contribute with this.

discussion on discord https://discord.com/channels/486771218599510021/1206956471364100168

kone9 commented 9 months ago

The idea is to implement it in the entire node API no matter how basic it is.

Example with the print node.

Captura_de_pantalla_2024-02-13_194322 Captura_de_pantalla_2024-02-13_194333

kone9 commented 9 months ago

API modified to be the same as the visual nodes, thus self-documenting the functionalities and reducing the learning curve.

https://github.com/armory3d/armory/assets/12847027/4a31675a-7986-4a88-a89b-c78f72a58289

Captura de pantalla 2024-02-14 093748

kone9 commented 9 months ago

API in the same blender editor where we can see how to implement it in the tooltips. Example image edited in Gimp. Captura de pantalla 2024-02-14 100710

MoritzBrueckner commented 9 months ago

Hi, while this PR only implements a small change to an individual logic node, let me comment on the intention behind this, which you mentioned here and on Discord: I think that Armory shouldn't follow this approach as this is kind of an inversion of responsibility and semantics. Logic nodes are a visual wrapper around game logic to simplify it, not the other way around. While at the moment Armory doesn't stricly follow this approach (and probably can't completely do this), ideally, a logic node should contain as little "own code" as possible and just act as the wrapper around code that's somewhere else in the Armory/Iron/Kha/Haxe APIs. Logic nodes are not supposed to be heavily used from Haxe, instead that's the job of the actual programming API. Logic nodes act as a visual helper to the API, not the other way around.

I see two more problems with this approach, both resulting from the fact that logic nodes are not the main "API source":

  1. It creates a "detour" over logic nodes to implement some functionality. Instead of looking up the functionality in a semantically structured API (whether the API is well structured is open for discussion of course), with your proposed approach one would need to first search the list of logic nodes for a node that might implement this functionality and then check if the node actually provides a public function for this. Keep in mind that not every Armory user uses logic nodes by default, so a user that only programs in Haxe might not know much about individual logic nodes. Providing functionality via static functions (not static classes, btw) distributed over many nodes only complicates finding the desired functionality.
  2. Armory doesn't provide a logic node for each feature available from the Armory/Kha/Iron/Haxe APIs. This means that either there would be a lot of structural fragmentation of functionality where some functions are located in a proper API and other functions are distributed all over the place in logic node code, OR there would be a lot of redundancy which becomes difficult to manage as over time, the redundant will likely diverge. In case of the Kha and Haxe APIs, there would definitely be redundancy as these APIs are outside of the control of the Armory project.

Also, with the print example from your second post, I completely fail to see how this simplifies things:

  1. trace() would still be available, so we get redundancy that might confuse users as to why there are two ways to print ("is there a difference?")
  2. It's more code to write
  3. You need to look up the name of the print node instead of just using the functionality you literally learn in the first Haxe program you will probably write ("hello world")
  4. In this specific case, the function should be inlined to be guaranteed to not also be slower than trace()

After all I'm not the one who decides whether this gets merged, but I personally am sceptical whether this makes much sense.


As for your last post about documenting the API in the logic node menu: This is sadly not possible with Blender's Python API.

kone9 commented 9 months ago

Hi, while this PR only implements a small change to an individual logic node, let me comment on the intention behind this, which you mentioned here and on Discord: I think that Armory shouldn't follow this approach as this is kind of an inversion of responsibility and semantics. Logic nodes are a visual wrapper around game logic to simplify it, not the other way around. While at the moment Armory doesn't stricly follow this approach (and probably can't completely do this), ideally, a logic node should contain as little "own code" as possible and just act as the wrapper around code that's somewhere else in the Armory/Iron/Kha/Haxe APIs. Logic nodes are not supposed to be heavily used from Haxe, instead that's the job of the actual programming API. Logic nodes act as a visual helper to the API, not the other way around.

I see two more problems with this approach, both resulting from the fact that logic nodes are not the main "API source":

  1. It creates a "detour" over logic nodes to implement some functionality. Instead of looking up the functionality in a semantically structured API (whether the API is well structured is open for discussion of course), with your proposed approach one would need to first search the list of logic nodes for a node that might implement this functionality and then check if the node actually provides a public function for this. Keep in mind that not every Armory user uses logic nodes by default, so a user that only programs in Haxe might not know much about individual logic nodes. Providing functionality via static functions (not static classes, btw) distributed over many nodes only complicates finding the desired functionality.
  2. Armory doesn't provide a logic node for each feature available from the Armory/Kha/Iron/Haxe APIs. This means that either there would be a lot of structural fragmentation of functionality where some functions are located in a proper API and other functions are distributed all over the place in logic node code, OR there would be a lot of redundancy which becomes difficult to manage as over time, the redundant will likely diverge. In case of the Kha and Haxe APIs, there would definitely be redundancy as these APIs are outside of the control of the Armory project.

Also, with the print example from your second post, I completely fail to see how this simplifies things:

  1. trace() would still be available, so we get redundancy that might confuse users as to why there are two ways to print ("is there a difference?")
  2. It's more code to write
  3. You need to look up the name of the print node instead of just using the functionality you literally learn in the first Haxe program you will probably write ("hello world")
  4. In this specific case, the function should be inlined to be guaranteed to not also be slower than trace()

After all I'm not the one who decides whether this gets merged, but I personally am sceptical whether this makes much sense.

As for your last post about documenting the API in the logic node menu: This is sadly not possible with Blender's Python API.

Yes, I made a single example class showing how it works, I am not going to do everything if you tell me that you are not interested in this proposal. Maintaining the code may be more complicated, that's for sure, but you have to look at the positive side. You are going to make it so that many more people can access the HAXE API in a simple way, self-documenting with the editor, THAT IS THE GREAT ADVANTAGE. What I can tell you is that this is how unreal engine works... The important thing is to have the best of both tools. If I want to use the Nodes API in HAXE, I use the Nodes API. If I want to use the HAXE API directly, I use the haxe API. The main idea of this is to self-document the HAXE API with the nodes shortening the learning curve without having to constantly resort to the documentation, which is still confusing and this unfinished. Also make it intuitive and simple to understand. Due to performance issues, it may reduce a little, but I don't think it will be that significant. Redundancy is the least important thing, the important thing is that it is easy to understand, then you can improve the redundancy. Even with the print. Apart from print being a basic example, there are many much more complete functionalities that could be in a node and easily called from HAXE. A tool for developing video games has to make development as easy as possible, the tools have to be prepared to be intuitive and easy to understand, making you waste as little time as possible so that the "artist developer" can concentrate on the mechanics of the game. and fun interactivity.. Being a video game developer is not the same as being a conventional developer.. A video game developer does not care how difficult things are implemented under the hood, he needs the tools very easily, to concentrate in the art and representation of interactive animation correctly.

kone9 commented 9 months ago

I see two more problems with this approach, both resulting from the fact that logic nodes are not the main "API source":

  1. It creates a "detour" over logic nodes to implement some functionality. Instead of looking up the functionality in a semantically structured API (whether the API is well structured is open for discussion of course), with your proposed approach one would need to first search the list of logic nodes for a node that might implement this functionality and then check if the node actually provides a public function for this. Keep in mind that not every Armory user uses logic nodes by default, so a user that only programs in Haxe might not know much about individual logic nodes. Providing functionality via static functions (not static classes, btw) distributed over many nodes only complicates finding the desired functionality.

Beyond this proposal I made, visual nodes have a completely different API than HAXE, that is very bad, it is unintuitive, confusing and wastes a lot of time. If they at least used the same API, that would be something else. My proposal is to not break the engine and to remain compatible with previous versions. Self-document the Haxe API with visual nodes. And although it's not supposed to be right, I say it again, this is how unreal Engine works... a C++ class is a visual node and that class can be implemented in C++... So you can solve the logic in a node and easily pass it to c++ code

kone9 commented 9 months ago
  1. It creates a "detour" over logic nodes to implement some functionality. Instead of looking up the functionality in a semantically structured API (whether the API is well structured is open for discussion of course), with your proposed approach one would need to first search the list of logic nodes for a node that might implement this functionality and then check if the node actually provides a public function for this. Keep in mind that not every Armory user uses logic nodes by default, so a user that only programs in Haxe might not know much about individual logic nodes. Providing functionality via static functions (not static classes, btw) distributed over many nodes only complicates finding the desired functionality.

I mean, it's not about using just nodes, but about looking at them for a second, seeing how it is implemented and that's it... even learning the API intuitively, this is intended for new users of the engine who want to learn the tool with less learning curve.

kone9 commented 9 months ago

After all I'm not the one who decides whether this gets merged, but I personally am sceptical whether this makes much sense.

As for your last post about documenting the API in the logic node menu: This is sadly not possible with Blender's Python API

Regarding the issue of trace, I can tell you that people do not know what it is called trace, they know what it is called print, apart from that the node print has a debug function that the trace does not have. If you want to use trace, that's fine... but my idea is to use the functionalities of the nodes, thus SELF-DOCUMENT THE API... Yes, it is a great functionality that could improve productivity by 100% with this engine. Due to the Blender3D tooptip issue, you can modify any tooltip. https://blenderartists.org/t/adding-tooltip-to-an-operator-button/607993/4

moisesjpelaez commented 6 months ago

I'm skeptical as well and I don't think this should be merged. Logic nodes are just wrappers that already use the current API.

I agree with @MoritzBrueckner points and I'm listing practical situations I've been through:

I personally don't like this approach, but in case I did here are some things to consider:

In the end these are my observations as an user that has spent a few months with the engine, have used Logic Nodes a bit and heavily used Haxe for scripting.