|
|
#22 (permalink) |
|
Crumbly, but Good
|
===================== Entry 9 =====================
Well a lot has happened since I updated this journal a couple months ago. I have stolen even more stuff from unreal (read: ideas, not code), and now I have a lot of code which is in the process of generating itself, instead of me doing it, though I'm doing in a different way than unreal (no separate definition files; everything goes in the header) For example, take a look at an interesting sample class; in this case, a module. Code:
class Belt : public Caelus::WorldModule {
REGISTER_SINGLETON_CLASS(Belt, Caelus::WorldModule);
list<Ship*> Ships;
list<Explosion*> Explosions;
list<Missile*> Missiles;
list<Projectile*> Projectiles;
list<Station*> Stations;
list<Character*> Pilots;
list<Nebula*> Nebulae;
list<Waypoint*> Waypoints;
BeltSun* SunBelt;
BeltSky* SkyBelt;
noedit Module* ActiveLevels;
noedit Module* InactiveLevels;
noedit transient SceneGraph* Graph;
noedit transient int FreeIndex;
noedit transient Asteroid* Asteroids[DENSITY_MAX];
transient Sector* Sectors[SECTOR_ALLOCATION];
Belt(Module* Parent);
~Belt();
void Draw(Caelus::Camera* Eye);
void Step(float Delta);
void Setup();
bool Write(FILE* File, Caelus::SerializationDataset& Dataset) const;
bool Read(FILE* File, Caelus::SerializationDataset& Dataset);
void PostRead();
};
Essentially, these keywords are tie ins to the game's auxiliary code-generating system, that automatically generates code on the fly for each class that's hooked into it. Take a look at the file generated for this class, by the perl script that runs at compile-time: Code:
byte Belt::InitializeClassAttributes()
{
if (Properties)
return 0;
ClassProperties* ParentProperties = Super::GetClassProperties();
Properties = &Base::RuntimeDatabase->Classes["Belt"];
if (ParentProperties)
Properties->Inherit(ParentProperties);
Properties->Variables["Ships"] = BaseProperty("Ships", TYPE_DATASTRUCTURE, offsetof(Belt, Ships), BaseProperty::FLAG_NONE);
Properties->Variables["Explosions"] = BaseProperty("Explosions", TYPE_DATASTRUCTURE, offsetof(Belt, Explosions), BaseProperty::FLAG_NONE);
Properties->Variables["Missiles"] = BaseProperty("Missiles", TYPE_DATASTRUCTURE, offsetof(Belt, Missiles), BaseProperty::FLAG_NONE);
Properties->Variables["Projectiles"] = BaseProperty("Projectiles", TYPE_DATASTRUCTURE, offsetof(Belt, Projectiles), BaseProperty::FLAG_NONE);
Properties->Variables["Stations"] = BaseProperty("Stations", TYPE_DATASTRUCTURE, offsetof(Belt, Stations), BaseProperty::FLAG_NONE);
Properties->Variables["Pilots"] = BaseProperty("Pilots", TYPE_DATASTRUCTURE, offsetof(Belt, Pilots), BaseProperty::FLAG_NONE);
Properties->Variables["Nebulae"] = BaseProperty("Nebulae", TYPE_DATASTRUCTURE, offsetof(Belt, Nebulae), BaseProperty::FLAG_NONE);
Properties->Variables["Waypoints"] = BaseProperty("Waypoints", TYPE_DATASTRUCTURE, offsetof(Belt, Waypoints), BaseProperty::FLAG_NONE);
Properties->Variables["SunBelt"] = BaseProperty("SunBelt", TYPE_BASE, offsetof(Belt, SunBelt), BaseProperty::FLAG_NONE);
Properties->Variables["SkyBelt"] = BaseProperty("SkyBelt", TYPE_BASE, offsetof(Belt, SkyBelt), BaseProperty::FLAG_NONE);
Properties->Variables["ActiveLevels"] = BaseProperty("ActiveLevels", TYPE_BASE, offsetof(Belt, ActiveLevels), BaseProperty::FLAG_NONE | BaseProperty::FLAG_NOEDIT);
Properties->Variables["InactiveLevels"] = BaseProperty("InactiveLevels", TYPE_BASE, offsetof(Belt, InactiveLevels), BaseProperty::FLAG_NONE | BaseProperty::FLAG_NOEDIT);
Properties->Variables["Graph"] = BaseProperty("Graph", TYPE_BASE, offsetof(Belt, Graph), BaseProperty::FLAG_NONE | BaseProperty::FLAG_NOEDIT | BaseProperty::FLAG_TRANSIENT);
Properties->Variables["FreeIndex"] = BaseProperty("FreeIndex", TYPE_INT, offsetof(Belt, FreeIndex), BaseProperty::FLAG_NONE | BaseProperty::FLAG_NOEDIT | BaseProperty::FLAG_TRANSIENT);
InitializeClassMacro();
return 0;
}
IMPLEMENT_SINGLETON_CLASS(Belt);
In the end, this means big time savings for any future developments, as everything is saved back in automatically to the class when it comes time for serialization. Also, it gives us a way to create an editor system in game, by specifying which variables we want to let the user edit using the game's editor (using noedit); allowing us to keep variables that we want protected away from the user's grasp, while letting the vast majority of other variables be tweaked with various widgets that are appropriate to the type of variable (also generated by the system ,so we know). Because there's only one instance of the information per-class (and not per instance), the actual RAM used to maintain the system is very minimal, even with a lot of classes and the vast majority of operations are usually one-off, with no time-constraint (saving, loading, editing), so performance isn't key; even then, things are still pretty good; and it's very very easy to hook things into the system, all they need to do is inherit from the class Base, or inherit from something that does inherit from Base, and use the macro REGISTER_CLASS, or one of its variants. That's it; super-simple, and throws in a whole ton of functionality at minimal cost. Unfortunately the system grossly breaks when used with C++'s virtual inheritance (because the compiler has to juggle around class memory layouts), so you have to be careful about when you want to do multiple inheritance, but if you structure things properly, and make a few trade-offs, things stay simple and managed. And of course, when you need speed and absolutely bare-bones minimal size (no vtable and the uint that the base class requires), you don't need to hook into the system at all; you can just use regular old C/C++ code that's not hooked in for areas of necessary high-performance. Well, that's all for now, just thought I'd drop in an update.
__________________
|
|
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|