diff options
Diffstat (limited to 'src/feature.h')
-rw-r--r-- | src/feature.h | 115 |
1 files changed, 92 insertions, 23 deletions
diff --git a/src/feature.h b/src/feature.h index e1e4688..81370b1 100644 --- a/src/feature.h +++ b/src/feature.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com> + * Copyright © 2025 Michael Smith <mikesmiffy128@gmail.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,18 +21,42 @@ #define _FEATURE_CAT(a, b) _FEATURE_CAT1(a, b) /* - * Declares that this translation unit implements a "feature" - a unit of - * plugin functionality. + * Declares that this translation unit implements a "feature" - a unit of plugin + * functionality. * - * desc specifies a string to be displayed to the user. Omit this to declare an - * internal feature, which won't be advertised, but will be available to other - * features. + * At build time, the code generator automatically creates the glue code + * required to make features load and unload in the correct order, subject to + * compatibility with each supported game and engine version. As such, there is + * no need to manually plug a new feature into SST's initialisation code as long + * as dependency information is properly declared (see the macros below). + * + * desc specifies a string to be displayed to the user in the console printout + * that gets displayed when the plugin finishes loading. Omit this to declare an + * internal feature, which won't be displayed to users but will still be + * available for other features to call into and build functionality on top of. */ #define FEATURE(... /*desc*/) /* - * Indicates that the specified feature is required for this feature to function. - * If that feature fails to initialise, this feature will not be enabled. + * Declares that this feature should only be loaded for games matching the given + * gametype tag (see gametype.h). Console variables and commands created using + * DEF_FEAT_* macros will not be registered if SST is loaded by some other game. + * + * As an optimisation, REQUIRE_GAMEDATA() checks (see below) can also be elided + * in cases where gamedata is always present for this particular game. As such, + * it is wise to still specify gamedata dependencies correctly, so that the + * definitions can be changed in the data files without breaking code. + */ +#define GAMESPECIFIC(tag) + +/* + * Indicates that the specified feature is required for this feature to + * function. If that feature fails to initialise, this feature will not be + * enabled. + * + * By convention, the name of the feature is the name of its implementation + * source file, minus the .c extension. For instance, foo.c would be referred to + * by REQUIRE(foo). */ #define REQUIRE(feature) @@ -40,9 +64,9 @@ * Indicates that the specified feature should be initialised before this one, * but is not a hard requirement. * - * Presence of a feature can be tested for using has_<featurename>. + * Presence of a feature can in turn be tested for using has_<featname>. */ -#define REQUEST(featname) extern bool has_##featname; +#define REQUEST(feature) extern bool has_##feature; /* * Indicates that the specified gamedata entry is required for this feature to @@ -52,40 +76,85 @@ * effect on whether this feature is loaded. It can simply be tested for using * has_<entryname>. */ -#define REQUIRE_GAMEDATA(feature) +#define REQUIRE_GAMEDATA(entry) /* * Indicates that this feature requires a global variable (such as a factory or * globally-exposed engine interface) to be non-null in order to function. If * the variable has a null/zero value prior to feature initialisation, this * feature will not be enabled. + * + * Note that this really only works for variables known to engineapi.c which is + * kind of a bad abstraction, but it's currently just necessary in practice. + * + * Correct usage of this macro will generally be very similar to other usages + * found elsewhere in the codebase already, so use those as a reference. */ #define REQUIRE_GLOBAL(varname) +/* status values for INIT and PREINIT below */ +enum { + FEAT_SKIP = -1, /* feature isn't useful here, pretend it doesn't exist */ + FEAT_OK, /* feature successfully initialised/enabled */ + FEAT_FAIL, /* error in starting up feature */ + FEAT_INCOMPAT, /* feature is incompatible with this game/engine version */ + _FEAT_INTERNAL_STATUSES // internal detail, do not use +}; + /* - * Defines the special feature init function which is unique to this translation - * unit. This should return true to indicate success, or false to indicate - * failure. Features which start to load will cause dependent features not to be - * started. + * Defines the special feature initialisation function which is unique to this + * translation unit. All features are required to specify this function. + * + * The defined function must return FEAT_OK on success, FEAT_FAIL on failure due + * to some transient error, FEAT_INCOMPAT to indicate incompatibility with the + * current game/engine version, or FEAT_SKIP to indicate that the feature is + * useless or unnecessary. + * + * If a value other than FEAT_OK is returned, END (see below) will not be called + * later and other features that depend on this feature will be disabled. If + * this feature provides other functions as API, they can be assumed not to get + * called unless initialisation is successful. + * + * For features with a description (see FEATURE() above), all return values with + * the exception of FEAT_SKIP will cause a corresponding status message to be + * displayed in the listing after the plugin finishes loading, while FEAT_SKIP + * will simply hide the feature from the listing. Features with no description + * will not be displayed anyway. * - * Features are required to specify this function. + * Features which either fail to initialise or elect to skip loading will cause + * dependent features not to be enabled. */ -#define INIT bool _FEATURE_CAT(_feature_init_, MODULE_NAME)(void) // { code... } +#define INIT int _FEATURE_CAT(_feat_init_, MODULE_NAME)(void) // { code... } /* * Defines the special, optional feature shutdown function which is unique to * this translation unit. This does not return a value, and may be either * specified once, or left out if no cleanup is required for this feature. */ -#define END void _FEATURE_CAT(_feature_end_, MODULE_NAME)(void) // { code... } +#define END void _FEATURE_CAT(_feat_end_, MODULE_NAME)(void) // { code... } /* - * Defines a conditional check to run prior to checking other requirements for - * this feature. This can be used to match a certain game type or conditionally - * register console variables, and should return true or false to indicate - * whether the feature should continue to initialise. + * Defines a special feature pre-init function which performs early feature + * initialisation, the moment the plugin is loaded. If the plugin is autoloaded + * via VDF, this will be called long before the deferred initialisation that + * usually happens after the client and VGUI have spun up. Since most of the + * rest of SST is also deferred, care must be taken not to call anything else + * that is not yet initialised. + * + * When in doubt, do not use this; it exists only to serve a couple of fringe + * cases. + * + * Like INIT above, the function created by this macro is expected to return one + * of FEAT_OK, FEAT_FAIL, FEAT_INCOMPAT, or FEAT_SKIP. If a value other than + * FEAT_OK is returned, the INIT block won't be run afterwards. + * + * Features that use this macro are currently disallowed from using REQUIRE() + * and REQUEST(), as well as GAMESPECIFIC(), because it's not clear how the + * semantics of doing so should work. It is still possible to use + * REQUIRE_GAMEDATA and REQUIRE_GLOBAL, however these only apply to the INIT + * block, *NOT* the PREINIT. */ -#define PREINIT bool _FEATURE_CAT(_feature_preinit_, MODULE_NAME)(void) // {...} +#define PREINIT int _FEATURE_CAT(_feat_preinit_, MODULE_NAME)(void) // {...} #endif |