Advertisement

Making a case for a base object type

Started by October 27, 2010 11:06 AM
11 comments, last by WitchLord 14 years, 1 month ago
As the title implies, here I will attempt to make a case for objects, both application registered and script defined, to all inherit from a global base type.

I am working currently on a game engine with design concepts similar to that of the Unreal Engine. In Unreal, almost all application logic is controlled through Unreal Script. That is really all that is needed to be known about that to get the jist of what direction I am going with my engine.

One of the challenges I faced early on is one that is covered in a few pages in the manual, where objects need to be passed back down to the compiled application prior to the type actually being known. I tried using the any type and the variable parameter, but to me, they all felt hackish and more like workarounds than actual solutions.

I was able to rectify this situation by registering an interface with no functions. Just a simple little interface that I was able to use to pass objects back down to the compiled application. Basically, anything that inherited from 'object' was usable anywhere, just as in Java and C#. This was not only useful for passing classes back down to the application, but it was also useful for creating generic containers within the script such as linked lists, queues, and stacks. However, that is about where the usefulness ends, because when it comes to application registered classes, they don't inherit the object type, so storage using this method is impossible without introducing some other specialized wrapper object. This to me seems unnecessary.

I understand that AngelScript is meant to be customizable and configurable, but many, many design challenges we are faced with when using it could easily be rectified by introducing a base type, even if it is optional. So what I can see is something at the engine level that registers the name of the base type that objects could inherit from, something like

void asIScriptEngine::RegisterBaseType(char*);


Other potential benefits could include greater simplification of the interpreter, because with a base type, [potential_landmine]templates could be rendered unnecessary.[/potential_landmine]

I guess I should also ask, are there plans in place to include such a feature in upcoming versions?
While this is a feature I would like to support, it is not that easy since AngelScript is statically typed. There is just no common base for script classes and application registered classes, so it's not possible to say they have it.

If I can come up with a reasonable solution to this I will definitely add this feature.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
How about just making it so that application classes can be registered as supporting an interface? If I'm understanding him right, I think that would satisfy _orm_'s requirements.
That would actually work perfectly! Something like

int r;r=engine->RegisterObjectInterfaceSupport("RegisteredClass","object");


But then what is stopping you from creating a base interface for script defined classes?

Another option could be to go the C route and allow for void handles that behave like void pointers.
It might be possible if the application class implements the asIScriptObject interface (or rather a simplified version of it). This is the path I've been thinking about exploring for a near future.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Such a route might be infinitely less obtrusive to existing code as well if there were some canned implementations to inherit from.
Advertisement
Is an intrusive solution really necessary? Let's for the moment consider only supporting registering interfaces for reference types; from what I know about AS, it doesn't seem like supporting value types would make much sense. So let's say you register a class Foo supporting an interface IBar. Then the script engine could automatically create a proxy class filled with forwarding functions:
class FooProxy : IBar {  Foo@ inner;  int foo() {    return inner.foo();  }  void bar(int i) {    inner.bar(i);  }}

Then Foo could be given an implicit ref cast to IBar that constructs a new FooProxy, stuffs the Foo instance into the FooProxy's inner handle and returns that as an IBar handle.
That's an interesting idea.

The ref_cast from Foo to IBar can be solved as you described.
The ref_cast from IBar to Foo can also be solved with special treatment in AS.

One problem is that if the same Foo handle is cast to IBar in two different locations, the two IBar handles will not be pointing to the same FooProxy object. Unless, the FooProxy is kept in some map as long as the first FooProxy is alive.

An IBar handle can also not be directly compared with a Foo handle to determine if it is the same object. But then again, that cannot be done with two handles for application types with multiple inheritances either, so that is not an additional limitation.

Looks like this solution might work. I'll have to explore this further.


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

I don't know if this would be less or more work than using a map for the proxy types, but it might be possible to special case the proxy type comparison to return a comparison of the inner handle. Then you could have multiple proxies floating around but they would all look like the original.

Alternately, rather than requiring that a class that implements interfaces derive from asIScriptObject, have it register an object behavior where it returns a pointer to a void pointer that the script engine could use to stuff a pointer to a proxy object if one exists. The proxy object could hold a handle to the application object and when it gets created or destroyed, it can write or remove it's address in that location. That would be somewhat intrusive, but a little less than requiring implementing an interface.

Just throwing out ideas.
That is about what I do now with my actor class in my engine. If special behavior for an actor is required, then one has to make a proxy that gets passed down to the compiled actor (where certain callback functions such as OnCollide are utilized, if required). I actually think it could be possible to generate the proxy classes as the engine exists now. I'll see what I come up with. But I'm guessing that is a no on the void handle type?

This topic is closed to new replies.

Advertisement