WD Studios - O3DEReflect (development)#1016
WD Studios - O3DEReflect (development)#1016JailbreakPapa wants to merge 2 commits intoo3de:developmentfrom
Conversation
|
The code here looks interesting. The description he is a bit sparse, can you add more detail in what exactly this does? I think a lot of people would be very interested in this! |
|
Currently away from my home PC, but I'll remove the Unreal references, and add proper documentation. |
The gem helps get rid of some boilerplate code that comes with setting up components, and helps with exposing them properly to SC, which was a problem at the time when the gem was created. |
|
I'm still reviewing this, but I distinctly remember suggesting we go in this direction at some point maybe 10 years ago. Its much safer to code gen boilerplate than it is to write it each time, and the multi player autocomponents pattern was way easier to write for and less error prone. Its just that by that point, we had already written the vast majority of our components the other way. Back then we were considering something like this as core O3DE feature, and reworking the components we already have to use this kind of system instead. But there's just only so many hours in the day and reworking existing features that themselves are okay and already work is now how we end up being good. So I'm glad to see this get started, and extras is a pretty good place to put it to experiment with it. If its really good and very useful, I would not actually be against promoting it to core, but we'd want to revision it and try it and push it here first. Extending this, I'd love to find a way to hook new components into the code in such a way that we don't have to also register them with the module class each time, perhaps we can solve that with code gen too, somehow. (Out of scope for this change) I like having XML or JSON or some other structured document be the source of truth, since it also opens up other avenues, such as being able to generate the editor property grid, or to even make a editor for the xml itself, and so on. So good work with this! (Still reviewing). My interest will also be around how we can deal with say, editor components, or the controller model of editor/game components (where the property fields are stored in a config class, and a controller is shared with editor so that the component can do stuff like render preview particles or enable atom render lights and stuff, in the editor, without duplicating code). |
nick-l-o3de
left a comment
There was a problem hiding this comment.
Your module and your system component don't seem to do anything. it isn't necessary to have a system component or module if you have no c++ code of your own. You can just eliminate those targets from your cmake script. Gems do not need to have c++ modules if they are build or asset tools.
Another issue, calling the header parsing version "V2" makes it sound like its the superior, evolutionary approach, and that we should deprecate "V1" (xml, etc). However, I don't see this as the actual intent.
Perhaps we need to consider some other names for the two approaches? just a thought here?
| cmake_dir = os.path.abspath(os.path.join(script_dir, '..', '..', '..', '..', '..', 'cmake')) | ||
| if cmake_dir not in sys.path: | ||
| sys.path.insert(0, cmake_dir) |
There was a problem hiding this comment.
I'm assuming this is an attempt to add the path to the cmake executable to the front of the path? Its not the case that people cloning from git get this path here, I think its only in installers. Its going to be interesting though, because O3DE itself uses cmake from your path, allowing you to install a newer one, and use that, but this will force usage of cmake from the installer. More consistent I guess? Not sure what to suggest here, but interesting.
But like, everyone can check out the extras repo anywhere on their HDD, so maybe the first param to this script should instead be the path to the o3de engine root? (Since you can have different engines installed?) From there, you can locate cmake, as well as the cmake folder, which contains the venv hash finder?
| try: | ||
| from jinja2 import Environment, FileSystemLoader, select_autoescape | ||
| JINJA2_AVAILABLE = True | ||
| except ImportError: | ||
| JINJA2_AVAILABLE = False | ||
| print("Warning: Jinja2 not available. Template rendering will fail.", file=sys.stderr) | ||
| if o3de_site_packages: | ||
| print(f" Tried O3DE site-packages at: {o3de_site_packages}", file=sys.stderr) | ||
|
|
||
| logging.basicConfig(format='[%(levelname)s] %(name)s: %(message)s') | ||
| logger = logging.getLogger('O3DEReflectGen') | ||
| logger.setLevel(logging.INFO) |
There was a problem hiding this comment.
At some point in the future, we are going to be in a situation where the user is having compile errors or other problems related to this script, and we are going to have to try to help them by looking at log output. Would it be useful for that diagnostic to print this stuff out anyway? That is "Using O3DE site-packages at xxxxx" as well as "using cmake from xxxxx" ? or something?
Just trying to be nice to future me, or future you when you get a log back and it tells you nothing...
| matches = glob.glob(pattern) | ||
| if matches: | ||
| return matches[0] | ||
| return None |
There was a problem hiding this comment.
This is also interesting to me, since there's going to be a bunch of Venv in there, one for each version of the engine, and which one you use is supposed to be related to the project you are running this as part of (or a special one for no project, engine only to build installer). This appears to return the first one, rather than the correct one?
There's a cmake script to calculate it, namely, cmake/CalculateEnginePathId.cmake
cmake -P cmake/CalculateEnginePathId.cmake (root folder of engine)will fill stdout with the actual hash of the venv for the given engine.
I guess this is all because you expect this script to be executed directly by the user on the command line, so it doesn't have access to all that?
| logger.setLevel(logging.INFO) | ||
|
|
||
|
|
||
| def create_hash_guid(string: str) -> str: |
There was a problem hiding this comment.
If you pass in the path to the engine, would it not be possible to from AzAutoGen import create_hash_guid ?
| def find_o3de_site_packages(): | ||
| """Find O3DE's Python venv site-packages directory.""" | ||
| home = os.path.expanduser("~") | ||
| patterns = [ | ||
| os.path.join(home, ".o3de", "Python", "venv", "*", "lib", "site-packages"), | ||
| os.path.join(home, ".o3de", "Python", "venv", "*", "Lib", "site-packages"), # Windows | ||
| ] | ||
| for pattern in patterns: | ||
| matches = glob.glob(pattern) | ||
| if matches: | ||
| return matches[0] | ||
| return None |
There was a problem hiding this comment.
Same comment as prior file. Changing this so that you pass in the path to the engine you wanna use as a parameter makes it easier to deal with multiple different engines with different cmakes / az auto gen, in the same extras repo. Extras repo is checked out anywhere on user's HDD.
|
|
||
| set(gem_path ${CMAKE_CURRENT_LIST_DIR}) | ||
| set(gem_json ${gem_path}/gem.json) | ||
| o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) |
There was a problem hiding this comment.
dont need this unless you plan a restricted module.
|
|
||
| o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}") | ||
|
|
||
| ly_add_external_target_path(${CMAKE_CURRENT_LIST_DIR}/3rdParty) |
There was a problem hiding this comment.
can remove this unless you want to include 3rd party libraries in here.
| "origin": "WD Studios Corp.", | ||
| "origin_url": "https://wdstudios.tech", | ||
| "type": "Code", | ||
| "summary": "Unreal-style reflection system for O3DE. Simplifies component, struct, and enum creation", |
There was a problem hiding this comment.
Plz dont mention unreal :)
| Example O3DEReflect Enum - AI State | ||
|
|
||
| This demonstrates how to define an enum using O3DEReflect XML. | ||
| Like Unreal's UENUM, this creates a scriptable, editor-visible enumeration. |
There was a problem hiding this comment.
I don't htink we should mention another engine here.
| if(NOT DEFINED LY_PYTHON_CMD) | ||
| # Fallback to Python_EXECUTABLE if LY_PYTHON_CMD is not set | ||
| set(O3DE_REFLECT_PYTHON_CMD "${Python_EXECUTABLE}") | ||
| else() | ||
| set(O3DE_REFLECT_PYTHON_CMD ${LY_PYTHON_CMD}) | ||
| endif() |
There was a problem hiding this comment.
Is this something that actually happens? These cmake files are always supposed to be executed in the context of an O3DE build, and LY_PYTHON_CMD is set as part of bringup of the Platform Abstraction Layer (PAL) in O3DE, before any gem cmakes are evaluated.
This happens https://github.com/o3de/o3de/blob/3347f66b4d2fa3a7ee7e50c2e84c676829a8ccca/CMakeLists.txt#L58C1-L58C25 here, very very early on.
Perhaps instead we should error here? Or print a warning?
What does this PR do?
Adds O3DEReflect, a gem for component creation
How was this PR tested?
Tested on 1/4/2026 o3de-development (6f3adb49c14c5209bcc727014f3c8c5f92afee96) & O3DE Release 25.10.1