X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Foo.qh;h=3c7237ef408adb7ea2237536a175f4d19476a126;hb=4b58d4bcc6769c7047225a9840cea3515a3c5da1;hp=63b17089e48c0a8d080e30b797f46b689fd4385f;hpb=c6d440124df99b8b1f48fe7666332273535eb413;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/oo.qh b/qcsrc/common/oo.qh index 63b17089e..3c7237ef4 100644 --- a/qcsrc/common/oo.qh +++ b/qcsrc/common/oo.qh @@ -1,71 +1,139 @@ #ifndef OO_H #define OO_H +#include "registry.qh" + #ifdef MENUQC - #define NULL (null_entity) + #define NULL (null_entity) #else - #define NULL (world) + #define NULL (world) #endif .string classname; -.string vtblname; -.entity vtblbase; -entity spawnVtbl(entity this, entity base) -{ - entity vtbl = spawn(); - copyentity(this, vtbl); - vtbl.vtblname = vtbl.classname; - vtbl.classname = "vtbl"; - vtbl.vtblbase = base ? base : vtbl; // Top level objects use vtbl as base - return vtbl; +/** Location entity was spawned from in source */ +.string sourceLocFile; +.int sourceLocLine; +entity _spawn(); +entity __spawn(string _classname, string _sourceFile, int _sourceLine) { + entity this = _spawn(); + this.classname = _classname; + this.sourceLocFile = _sourceFile; + this.sourceLocLine = _sourceLine; + return this; } -entity Object_vtbl; -entity spawnObject(entity this, entity) -{ - this = spawn(); - this.classname = "Object"; - if (!Object_vtbl) Object_vtbl = spawnVtbl(this, NULL); - return this; -} -// Classes have a `spawn##cname(entity, entity)` constructor -// The parameters are used as locals for [[accumulate]] + +#define entityclass(...) OVERLOAD(entityclass, __VA_ARGS__) +#define entityclass_1(name) entityclass_2(name, Object) +#ifndef QCC_SUPPORT_ENTITYCLASS + #define entityclass_2(name, base) typedef entity name + #define class(name) + #define new(class) __spawn(#class, __FILE__, __LINE__) +#else + #define entityclass_2(name, base) entityclass name : base {} + #define class(name) [[class(name)]] + #define new(class) ((class) __spawn(#class, __FILE__, __LINE__)) +#endif + +// Classes have a `spawn##cname(entity)` constructor +// The parameter is used across [[accumulate]] functions // Macro to hide this implementation detail -#define NEW(cname) (spawn##cname(NULL, NULL)) +#define NEW(cname, ...) \ + OVERLOAD(spawn##cname, new(cname), ##__VA_ARGS__) -#define CLASS(cname, base) \ -entity spawn##cname(entity this, entity basevtbl) { \ - this = NEW(base); basevtbl = base##_vtbl; \ -} +#define CONSTRUCT(cname, ...) \ + OVERLOAD(spawn##cname, this, ##__VA_ARGS__) -#define METHOD(cname, name, prototype) \ -prototype cname##_##name; \ -.prototype name; \ -[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \ - this.name = cname##_##name; \ -} +#define CONSTRUCTOR(cname, ...) \ + cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) { return = this; } \ + [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) -#define ATTRIB(cname, name, type, val) \ -.type name; \ -[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \ - this.name = val; \ -} +.string vtblname; +.entity vtblbase; -#define ATTRIBARRAY(cname, name, type, cnt) \ -.type name[cnt]; - -#define ENDCLASS(cname) \ -.bool instanceOf##cname; \ -entity cname##_vtbl; \ -[[accumulate]] [[last]] entity spawn##cname(entity this, entity basevtbl) { \ - this.instanceOf##cname = true; \ - this.classname = #cname; \ - if (!cname##_vtbl) cname##_vtbl = spawnVtbl(this, basevtbl); \ - return this; \ -} +void RegisterClasses() { } +STATIC_INIT(RegisterClasses) { RegisterClasses(); } + +#define VTBL(cname, base) \ + INIT_STATIC(cname); \ + entity cname##_vtbl; \ + void cname##_vtbl_init() { \ + cname e = new(vtbl); \ + spawn##cname##_static(e); \ + e.vtblname = #cname; \ + /* Top level objects refer to themselves */ \ + e.vtblbase = base##_vtbl ? base##_vtbl : e; \ + cname##_vtbl = e; \ + } \ + ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init) + +#define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this) +#define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this) + +#define CLASS(cname, base) \ + entityclass(cname, base); \ + class(cname) .bool instanceOf##cname; \ + VTBL(cname, base) \ + INIT_STATIC(cname) { \ + if (cname##_vtbl) { \ + copyentity(cname##_vtbl, this); \ + return; \ + } \ + spawn##base##_static(this); \ + this.instanceOf##cname = true; \ + } \ + INIT(cname) { \ + /* Only statically initialize the current class, it contains everything it inherits */ \ + if (cname##_vtbl.vtblname == this.classname) { \ + spawn##cname##_static(this); \ + this.classname = #cname; \ + this.vtblname = string_null; \ + this.vtblbase = cname##_vtbl; \ + } \ + spawn##base##_1(this); \ + } + +#define METHOD(cname, name, prototype) \ + class(cname) .prototype name; \ + prototype cname##_##name; \ + INIT_STATIC(cname) { this.name = cname##_##name; } \ + prototype cname##_##name + +#define ATTRIB(cname, name, type, val) \ + class(cname) .type name; \ + INIT(cname) { this.name = val; } + +#define ATTRIBARRAY(cname, name, type, cnt) \ + class(cname) .type name[cnt]; + +#define ENDCLASS(cname) \ + [[last]] INIT(cname) { return this; } #define SUPER(cname) (cname##_vtbl.vtblbase) +#define super (this.vtblbase.vtblbase) + +#define spawn_static(this) +#define spawn_1(this) +#define _vtbl NULL +CLASS(Object, ); + METHOD(Object, describe, string(entity this)) { + string s = _("No description"); + if (cvar("developer")) { + for (int i = 0, n = numentityfields(); i < n; ++i) { + string value = getentityfieldstring(i, this); + if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value); + } + } + return s; + } + METHOD(Object, display, void(entity this, void(string name, string icon) returns)) { + returns(sprintf("entity %i", this), "nopreview_map"); + } +ENDCLASS(Object) +#undef spawn_static +#undef spawn_1 +#undef _vtbl #endif