Thanks for the answer, Andreas! I wasn't sure I understand the limitations of asOBJ_NOHANDLE correctly.
Unfortunately it would not make much sense to make it value type - as Transform is just one example of such object (and even it has more members: position / orientation / scale), there are more like Mesh, Rigidbody, Animator - always a single instance per game object. The idea was that C++ has low-level, non-logic C++ "components" for complex stuff (animations, physics), that may or may not be present on the object. Their presence depends on the purpose of the object: if it's a static object with no animations it won't have these available and they would be null, but if it's some monster it would have animator, transform, rigidbody and so on.
I also thought it would be fancy to expose them as props so you can refer to them as obj.animator or obj.transform - but it's a single instance and its lifetime should not really depend on ref count but be explicitly controlled by the owning object (removing component is possible if it's no longer needed - say, game object reaches an animation after which it just stays inanimate and does not require a full animator component - for example upon death). But if I say "remove it" I want it to be removed, not kept alive because some script writer decided to store reference to that component somewhere in a script, which should not really happen. I could probably disconnect it from world & object, so even if the instance exists it no longer affects the object, but it may cause a lot of "dangling" components if people are not careful and store the reference somewhere for whole object's lifetime - it would defeat the purpose of removing the component if no longer in acive use.
If preventing storing reference or nullifying them all once such component is removed is not an option, I think I will go for less direct method of access to the components that should work - instead of exposing whole component type to script side, I will wrap it in functions - instead of obj.transform.position (where transform is Transform@ and position is vec3 member of it) I could have obj.getPosition(), obj.getRotation(), obj.setPosition() and so on. Each such method will be a wrapper:
vec3 getPosition(Object* obj)
{
asIScriptContext *ctx = asGetActiveContext();
Transform* transform = obj->getComponent<Transform>();
if (transform)
{
return transform->getPosition();
}
else
{
ctx->SetException("Calling getPosition() on an object without Transform!");
}
}
This won't "scope" these properties nicely in a way that could be achieved with props - obj.transform.position - but I think I can still wrap some of them at least to obj.position where applicable. And maybe even, instead of throwing script exception where no component is found, add it automatically when it's not found, assuming that calling some method using this component means that the user actually needs it.
It also has a positive side, which is not needing to register types for all these components, just wrapper methods for their public interface. I was hoping that there may be some tricky way to achieve what I wanted initially, but if there is no such way right now it's not deal breaker.