Skip to content

WD Studios - O3DEReflect (development)#1016

Open
JailbreakPapa wants to merge 2 commits intoo3de:developmentfrom
WatchDogStudios:wdc-approved-1
Open

WD Studios - O3DEReflect (development)#1016
JailbreakPapa wants to merge 2 commits intoo3de:developmentfrom
WatchDogStudios:wdc-approved-1

Conversation

@JailbreakPapa
Copy link
Copy Markdown

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

@byrcolin
Copy link
Copy Markdown
Contributor

byrcolin commented Jan 6, 2026

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!

Comment thread Gems/O3DEReflect/Code/Examples/BeforeAfterComparison.h Outdated
Comment thread Gems/O3DEReflect/Code/Examples/V2/PlayerMovementComponent.h Outdated
Comment thread Gems/O3DEReflect/Code/Examples/V2/PlayerMovementComponent.h Outdated
Comment thread Gems/O3DEReflect/Code/Include/O3DEReflect/AutoGen/O3DEReflect.xsd Outdated
@JailbreakPapa
Copy link
Copy Markdown
Author

Currently away from my home PC, but I'll remove the Unreal references, and add proper documentation.

Comment thread Gems/O3DEReflect/Code/Include/O3DEReflect/AutoGen/O3DEReflectGen.py Outdated
@byrcolin byrcolin requested a review from nick-l-o3de January 6, 2026 18:04
@byrcolin byrcolin added sig/content Categorizes an issue or PR as relevant to SIG Content. sig/core Categorizes an issue or PR as relevant to SIG Core labels Jan 6, 2026
@byrcolin byrcolin requested review from a team January 13, 2026 16:51
@JailbreakPapa
Copy link
Copy Markdown
Author

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!

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.

@nick-l-o3de
Copy link
Copy Markdown
Contributor

nick-l-o3de commented Jan 16, 2026

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).

Copy link
Copy Markdown
Contributor

@nick-l-o3de nick-l-o3de left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment on lines +32 to +34
cmake_dir = os.path.abspath(os.path.join(script_dir, '..', '..', '..', '..', '..', 'cmake'))
if cmake_dir not in sys.path:
sys.path.insert(0, cmake_dir)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment on lines +56 to +67
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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you pass in the path to the engine, would it not be possible to from AzAutoGen import create_hash_guid ?

Comment on lines +40 to +51
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can remove this unless you want to include 3rd party libraries in here.

Comment thread Gems/O3DEReflect/gem.json
"origin": "WD Studios Corp.",
"origin_url": "https://wdstudios.tech",
"type": "Code",
"summary": "Unreal-style reflection system for O3DE. Simplifies component, struct, and enum creation",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't htink we should mention another engine here.

Comment on lines +42 to +47
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()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

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

Labels

sig/content Categorizes an issue or PR as relevant to SIG Content. sig/core Categorizes an issue or PR as relevant to SIG Core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants