aboutsummaryrefslogtreecommitdiff
path: root/src/feature.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature.h')
-rw-r--r--src/feature.h115
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