#ifndef REGISTRY_H #define REGISTRY_H #include "oo.qh" #define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this) #define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this) /** * Register a new entity with a global constructor. * Must be followed by a semicolon or a function body with a `this` parameter. * Wrapper macros may perform actions after user initialization like so: * #define REGISTER_FOO(id) \ * REGISTER(RegisterFoos, FOO, FOOS, FOOS_COUNT, id, m_id, NEW(Foo)); \ * REGISTER_INIT_POST(FOO, id) { \ * print("Registering foo #", this.m_id + 1, "\n"); \ * } \ * REGISTER_INIT(FOO, id) * * Don't forget to forward declare `initfunc` and call `REGISTER_REGISTRY`: * void RegisterFoos(); * REGISTER_REGISTRY(RegisterFoos) * * @param initfunc The global constructor to accumulate into * @param ns Short for namespace, prefix for each global (ns##_##id) * @param array The array to add each entity to. Also requires `array##_first` and `array##_last` to be defined * @param counter Global to count number of entries * @param id The identifier of the current entity being registered * @param fld The field to store the current count into * @param inst An expression to create a new instance, invoked for every registration */ #define REGISTER(initfunc, ns, array, counter, id, fld, inst) \ entity ns##_##id; \ REGISTER_INIT(ns, id) { } \ REGISTER_INIT_POST(ns, id) { } \ .entity enemy; /* internal next pointer */ \ void Register_##ns##_##id() { \ entity this = inst; \ ns##_##id = this; \ this.fld = counter; \ array[counter++] = this; \ if (!array##_first) array##_first = this; \ if ( array##_last) array##_last.enemy = this; \ array##_last = this; \ Register_##ns##_##id##_init(this); \ Register_##ns##_##id##_init_post(this); \ } \ ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \ REGISTER_INIT(ns, id) #endif