X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Flib%2Foo.qh;h=f57bf8e909c4e7d1a594a0e36f2415b715483fda;hp=2f871ccf17a3a6d73191dda69ea7d50f5fdfc7bc;hb=1b0decb9afb829407eae763b3053a122e2ae3de6;hpb=292502018a08f0a0f82358e5644f62fee3c7eed0 diff --git a/qcsrc/lib/oo.qh b/qcsrc/lib/oo.qh index 2f871ccf1..f57bf8e90 100644 --- a/qcsrc/lib/oo.qh +++ b/qcsrc/lib/oo.qh @@ -1,19 +1,12 @@ -#ifndef OO_H -#define OO_H +#pragma once #include "misc.qh" #include "nil.qh" #include "static.qh" -#ifdef MENUQC - #define NULL (null_entity) -#else - #define NULL (world) -#endif - .vector origin; .bool pure_data; -/** deprecated, use new_pure or NEW(class) */ +/** @deprecated use new_pure or NEW(class) */ #define make_pure(e) \ MACRO_BEGIN \ { \ @@ -28,47 +21,74 @@ .string classname; /** Location entity was spawned from in source */ -.string sourceLocFile; -.int sourceLocLine; +.string sourceLoc; entity _spawn(); -entity __spawn(string _classname, string _sourceFile, int _sourceLine, bool pure) + +#ifndef SPAWN_PURE +#define SPAWN_PURE 0 +#endif + +// pure entities: need no .origin +#if SPAWN_PURE +entity spawn_pure() = #600; +#else +#define spawn_pure() _spawn() +#endif + +entity __spawn(string _classname, string _sourceLoc, bool pure) { - entity this = _spawn(); + entity this = pure ? spawn_pure() : _spawn(); this.classname = _classname; - this.sourceLocFile = _sourceFile; - this.sourceLocLine = _sourceLine; + this.sourceLoc = _sourceLoc; if (pure) { make_pure(this); #ifdef CSQC - setorigin(this, '0 0 10000'); + setorigin(this, (world.mins + world.maxs) * 0.5); #endif + #ifdef SVQC + setorigin(this, (world.mins + world.maxs) * 0.5); + #endif } return this; } -#define entityclass(...) EVAL(OVERLOAD(entityclass, __VA_ARGS__)) +#define entityclass(...) EVAL_entityclass(OVERLOAD_(entityclass, __VA_ARGS__)) +#define EVAL_entityclass(...) __VA_ARGS__ #define entityclass_1(name) entityclass_2(name, Object) #ifndef QCC_SUPPORT_ENTITYCLASS - #define entityclass_2(name, base) typedef entity name + #define entityclass_2(name, base) USING(name, entity) #define class(name) - #define _new(class, pure) __spawn( #class, __FILE__, __LINE__, pure) + #define _new(class, pure) __spawn( #class, __FILE__ ":" STR(__LINE__), pure) #else #define entityclass_2(name, base) entityclass name : base {} #define class(name) [[class(name)]] - #define _new(class, pure) ((class) __spawn( #class, __FILE__, __LINE__, pure)) + #define _new(class, pure) ((class) __spawn( #class, __FILE__ ":" STR(__LINE__), pure)) #endif /** entities you care about seeing (.origin works) */ #define new(class) _new(class, false) /** purely logical entities (.origin doesn't work) */ #define new_pure(class) _new(class, true) -#define spawn() __spawn("entity", __FILE__, __LINE__, false) +#define spawn() __spawn("entity", __FILE__ ":" STR(__LINE__), false) + +[[accumulate]] void ONREMOVE(entity this) {} + +#ifndef SVQC + #define delete_fn builtin_remove +#endif + +#define delete(this) MACRO_BEGIN { \ + entity _this = (this); \ + void(entity) _dtor = _this.dtor; \ + ONREMOVE(this); \ + if (_dtor) _dtor(_this); else delete_fn(_this); \ + /* this = NULL; */ \ +} MACRO_END entity _clearentity_ent; STATIC_INIT(clearentity) { _clearentity_ent = new_pure(clearentity); - make_pure(_clearentity_ent); } void clearentity(entity e) { @@ -86,25 +106,38 @@ void clearentity(entity e) // Classes have a `spawn##cname(entity)` constructor // The parameter is used across [[accumulate]] functions +.bool transmute; + // Macros to hide this implementation detail: -#ifdef GMQCC +#ifdef __STDC__ #define NEW(cname, ...) \ - OVERLOAD(spawn##cname, new_pure(cname),##__VA_ARGS__) + OVERLOAD_(spawn##cname, new_pure(cname) P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) + + #define _TRANSMUTE(cname, this, ...) \ + OVERLOAD_(spawn##cname, this P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) #define CONSTRUCT(cname, ...) \ - OVERLOAD(spawn##cname, this,##__VA_ARGS__) + OVERLOAD_(spawn##cname, this P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) #else - #define NEW_(cname, ...) \ - OVERLOAD_(spawn##cname, __VA_ARGS__) #define NEW(cname, ...) \ - NEW_(cname, new_pure(cname),##__VA_ARGS__)(new_pure(cname),##__VA_ARGS__) + OVERLOAD(spawn##cname, new_pure(cname),##__VA_ARGS__) + + #define _TRANSMUTE(cname, this, ...) \ + OVERLOAD(spawn##cname, this,##__VA_ARGS__) - #define CONSTRUCT_(cname, ...) \ - OVERLOAD_(spawn##cname, __VA_ARGS__) #define CONSTRUCT(cname, ...) \ - CONSTRUCT_(cname, this,##__VA_ARGS__)(this,##__VA_ARGS__) + OVERLOAD(spawn##cname, this,##__VA_ARGS__) #endif +#define TRANSMUTE(cname, this, ...) MACRO_BEGIN \ + entity _e = (this); \ + if (_e.vtblbase != cname##_vtbl) { \ + _e.transmute = true; \ + _e.classname = #cname; \ + _TRANSMUTE(cname, _e, __VA_ARGS__); \ + } \ + MACRO_END + #define CONSTRUCTOR(cname, ...) \ cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \ { \ @@ -122,7 +155,7 @@ STATIC_INIT(RegisterClasses) } #define VTBL(cname, base) \ - INIT_STATIC(cname); \ + _INIT_STATIC(cname); \ entity cname##_vtbl; \ void cname##_vtbl_init() \ { \ @@ -135,29 +168,40 @@ STATIC_INIT(RegisterClasses) } \ ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init) -#define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this) +#define _INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this) #define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this) +#if NDEBUG + #define DEBUG_STUFF(cname) +#else + #define DEBUG_STUFF(cname) \ + bool is_##cname(entity e) { return e.instanceOf##cname; } \ + void isnt_##cname(entity e) { eprint(e); } +#endif + + #define CLASS(cname, base) \ entityclass(cname, base); \ - class(cname).bool instanceOf##cname; \ + class(cname).bool instanceOf##cname; \ + DEBUG_STUFF(cname) \ VTBL(cname, base) \ - INIT_STATIC(cname) \ - { \ - if (cname##_vtbl) \ - { \ + _INIT_STATIC(cname) \ + { \ + if (cname##_vtbl && !this.transmute)\ + { \ copyentity(cname##_vtbl, this); \ return; \ } \ spawn##base##_static(this); \ this.instanceOf##cname = true; \ } \ - INIT(cname) \ - { \ + INIT(cname) \ + { \ /* Only statically initialize the current class, it contains everything it inherits */ \ if (cname##_vtbl.vtblname == this.classname) \ - { \ + { \ spawn##cname##_static(this); \ + this.transmute = false; \ this.classname = #cname; \ this.vtblname = string_null; \ this.vtblbase = cname##_vtbl; \ @@ -174,20 +218,45 @@ STATIC_INIT(RegisterClasses) #define METHOD(cname, name, prototype) \ STATIC_METHOD(cname, name, prototype); \ class(cname) .prototype name; \ - INIT_STATIC(cname) \ + _INIT_STATIC(cname) \ { \ this.name = METHOD_REFERENCE(cname, name); \ } \ STATIC_METHOD(cname, name, prototype) -#define ATTRIB(cname, name, type, val) \ - class(cname).type name; \ +#define DESTRUCTOR(cname) \ + STATIC_METHOD(cname, dtorimpl, void(cname this)); \ + METHOD(cname, dtor, void(cname this)) \ + { \ + METHOD_REFERENCE(cname, dtorimpl)(this); \ + this.instanceOf##cname = false; \ + entity super = SUPER(cname); \ + if (super != cname##_vtbl) super.dtor(this); \ + } \ + STATIC_METHOD(cname, dtorimpl, void(cname this)) + +#define ATTRIB(...) EVAL_ATTRIB(OVERLOAD_(ATTRIB, __VA_ARGS__)) +#define EVAL_ATTRIB(...) __VA_ARGS__ +#define ATTRIB_3(cname, name, type) INIT(cname) {} class(cname) .type name +#define ATTRIB_4(cname, name, type, val) \ + ATTRIB_3(cname, name, type); \ INIT(cname) \ { \ noref bool strzone; /* Error on strzone() calls. */ \ this.name = val; \ + } \ + ATTRIB_3(cname, name, type) + +#define STATIC_ATTRIB(cname, name, type, val) \ + type cname##_##name; \ + _INIT_STATIC(cname) \ + { \ + noref bool strzone; /* Error on strzone() calls. */ \ + cname##_##name = val; \ } +// cleanup potentially zoned strings from base classes + #define ATTRIB_STRZONE(cname, name, type, val) \ class(cname).type name; \ INIT(cname) \ @@ -197,8 +266,17 @@ STATIC_INIT(RegisterClasses) this.name = strzone(val); \ } +#define STATIC_ATTRIB_STRZONE(cname, name, type, val) \ + type cname##_##name; \ + _INIT_STATIC(cname) \ + { \ + if (cname##_##name) \ + strunzone(cname##_##name); \ + cname##_##name = val; \ + } + #define ATTRIBARRAY(cname, name, type, cnt) \ - class(cname).type name[cnt]; + class(cname) .type name[cnt] #define ENDCLASS(cname) \ INIT(cname) \ @@ -212,8 +290,11 @@ STATIC_INIT(RegisterClasses) #define spawn_1(this) #define _vtbl NULL CLASS(Object, ); - METHOD(Object, describe, string(entity this)) + DESTRUCTOR(Object) { builtin_remove(this); } + #define remove(this) delete(this) + METHOD(Object, describe, string(Object this)) { + TC(Object, this); string s = _("No description"); if (cvar("developer")) { @@ -225,13 +306,12 @@ CLASS(Object, ); } return s; } - METHOD(Object, display, void(entity this, void(string name, string icon) returns)) + METHOD(Object, display, void(Object this, void(string name, string icon) returns)) { + TC(Object, this); returns(sprintf("entity %i", this), "nopreview_map"); } ENDCLASS(Object) #undef spawn_static #undef spawn_1 #undef _vtbl - -#endif