core6

Introduce your project and write about your work.

Moderator: PPS-Leaders

Post Reply
User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

core6

Post by x3n » Sat Aug 24, 2013 9:14 pm

In march I created a new branch called 'core6' to work on some general things in the core framework. In august I finished my work and decided to merge the branch back to trunk. My work was interrupted by a 4 months break caused by some time-consuming events at work and at home.

For those of you that are interested, I'll try to give an overview of the changes in core6. The changes are grouped in 3 main topics.
Fabian 'x3n' Landau, Orxonox developer

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: core6

Post by x3n » Sat Aug 24, 2013 9:15 pm

1. Base-classes (formerly OrxonoxClass)

The core-framework does a lot of helpful things; among them are Identifiers, Objectlists, Configvalues, and Smart-Pointers. Until now, all of those features were based on the common base-class OrxonoxClass. Every class (and every interface) had to inherit from OrxonoxClass in order to use the features of the core-framework. The advantage of OrxonoxClass was that we had all in one place, but at the same time this was also a disadvantage because it was impossible to use only a part of the framework's features.

Following the principle of separation of concerns I decided to split OrxonoxClass into multiple classes. This resulted in the following base-classes:
  • Identifiable: The base of all classes which can be identified by an Identifier
  • Listable (inherits from Identifiable): The base of all classes whose objects are stored in Objectlists
  • Configurable (inherits from Listable): The base of all classes which may have configvalues
  • Destroyable: The base of all classes which can be used with SmartPtr and WeakPtr (thus having a destroy() function)
The inheritance among those base-classes is the result of the dependencies among the corresponding features: Configvalues require Objectlists and Objectlists require Identifiers.

There are two more classes:
  • OrxonoxClass: The base of all classes in Orxonox' gameplay
  • OrxonoxInterface: The base of all interfaces in Orxonox' gameplay
OrxonoxClass and OrxonoxInterface have no members at all, but they inherit from all 4 base-classes listed above; consequently OrxonoxClass has the same abilities like before and OrxonoxInterface does exactly the same. Their only use is to tell if a class is conceptually a class or an interface. Technically it makes no difference if a class inherits from OrxonoxClass or from OrxonoxInterface, but it allows developers to express their intentions by choosing the appropriate base-class.

The following class hierarchy shows the inheritance of the Pong gametype. The important point to note is that BaseObject (conceptually a class) inherits from OrxonoxClass, while Tickable (conceptually an interface) inherits from OrxonoxInterface. Both OrxonoxClass and -Interface inherit from Identifiable, Listable, Configurable, and Destroyable to combine all of the framework's features.
classorxonox_1_1_pong.png
classorxonox_1_1_pong.png (4.59 KiB) Viewed 2639 times
Fabian 'x3n' Landau, Orxonox developer

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: core6

Post by x3n » Sat Aug 24, 2013 9:15 pm

2. RegisterClass (formerly CreateFactory)

Until now there was a rule for each class inheriting (directly or indirectly) from OrxonoxClass: Write RegisterObject(Classname) in the constructor and CreateFactory(Classname) somewhere outside of the constructor. There were also some special cases: Classes which inherit directly from OrxonoxClass had to call RegisterRootObject(Classname) instead, and CreateFactory() did not work with abstract classes.

With core6, the rules have changed. They apply for every class inheriting (directly or indirectly) from Identifiable:
  1. Every class needs to call RegisterObject(Classname) in its constructor
  2. Every class needs to call RegisterClass(Classname) somewhere outside of the constructor
  3. Abstract classes need to call RegisterAbstractClass(Classname).inheritsFrom(Class(BaseClass))[.inheritsFrom(Class(BaseClass2))[...]]
RegisterClass() is essentially just a rename of the CreateFactory() macro. I renamed it to be more consistent with RegisterClass() and to express the real meaning of the macro. RegisterAbstractClass() is new and allows to correctly define the inheritance of abstract classes. Until now, this was done automatically but not always correctly. RegisterRootClass() is not necessary anymore, the only real root class is Identifiable which is already known to the framework.

These changes allow to determine the class-hierarchy at runtime correctly even in special cases (like multiple inheritance among abstract classes). Having a correct class-hierarchy is important for features like Configvalues or XML-serialization which allow developers to override definitions in sub-classes.

Defining the inheritance of abstract classes manually by using RegisterAbstractClass() may be a little tedious, but on the other hand it's more explicit - and it's the only way to do it correctly.
Fabian 'x3n' Landau, Orxonox developer

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: core6

Post by x3n » Sat Aug 24, 2013 9:15 pm

3. Contexts

core6 introduces a new concept called context. A context contains objectlists. Every object belongs to a context which means that the object is stored in the context's objectlists. A context is passed to an object's constructor and replaces the old concept of the creator:
  • Old constructor: MyClass(BaseObject* creator) : BaseClass(creator) { ... }
  • New constructor: MyClass(Context* context) : BaseClass(context) { ... }
Until now, Objectlists were a part of Identifiers. Because Identifiers are static, Objectlists were also static: there was only one Objectlist for each class. With the introduction of contexts this changes: There may be multiple contexts at the same time, either parallel (if they contain different objects) or hierarchical (if one context contains the other context and all of its objects).

Currently there are 3 classes in Orxonox which represent a context: Namespace, Level, and Scene. Namespace is a concept of the XML-Loader, but Level and Scene are part of the gameplay. This means that every level and every scene has its own object lists. Since scenes are also part of a level, their contexts build a hierarchy. Let me try to explain this:
  • Level 1
    • Scene 1
      • Object 1
      • Object 2
    • Scene 2
      • Object 3
      • Object 4
  • Level 2
    • Scene 3
      • Object 5
      • Object 6
    • Scene 4
      • Object 7
      • Object 8
Objects 1 and 2 are stored in the objectlists of Scene 1 and of Level 1. Objects 3 and 4 are stored in the objectlists of Scene 2 and also of Level 1. Scenes 1 and 2 are also stored in the objectlists of Level 1. Level 2 contains a completely different set of objects.

There is also a root-context. It is part of the framework and it is used whenever an object has no explicit context. It also serves as a root for all other contexts.

Currently contexts don't help a lot. However in future we may change some of our code. Consider the artificial intelligence which uses objectlists to find all enemies. Until now it iterated over the only static objectlist that existed. Now with core6, it iterates over the objectlist of the root-context. However it would be a lot more reasonable to iterate only over the objectlist of the scene because it makes absolutely no sense to attack enemies which reside in a different scene or even in a different level (remember that there is no interaction between scenes at all - different scene-graph, different physics - thus the AI would attack something that doesn't exist).

Thinking even more ahead I can imagine some sort of paging which splits space into multiple sectors (pages). Only objects in active pages are ticked and rendered (and considered by computationally expensive operations like AI and triggers). Until now, this would have been a difficult task. But with core6, each page could represent a context, which would make it trivial to iterate only over objects of active pages.


I hope this helps to understand the changes in core6. Every feedback is appreciated.
Fabian 'x3n' Landau, Orxonox developer

User avatar
beni
Baron Vladimir Harkonnen
Posts: 949
Joined: Tue Oct 03, 2006 9:15 am
Location: Zurich
Contact:

Re: core6

Post by beni » Wed Aug 28, 2013 3:22 pm

Good work. This looks very useful and especially the last part about iterating through context-specific object lists is great. Now we only have to implement it.
"I'm Commander Shepard and this is my favorite forum on the internet."

The Jo
General DuGalle
Posts: 121
Joined: Mon Mar 01, 2010 7:43 pm

Re: core6

Post by The Jo » Thu Sep 05, 2013 9:37 am

I am impressed. Good to see Orxonox improving.
I will update the presentation slides for the students and I will have to get used to the new framework before the students have their first questions.
Fail. Fail again. Fail better.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: core6

Post by x3n » Fri Sep 06, 2013 8:44 pm

Thanks for updating the slides. Let me know if you need some help or a guest speaker for the PPS. :)
Fabian 'x3n' Landau, Orxonox developer

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests