aboutsummaryrefslogtreecommitdiff
path: root/src/feature.h
blob: 7bab860522ef84a7a085e2d8acaef176e9a28a32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * 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
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef INC_FEATURE_H
#define INC_FEATURE_H

#define _FEATURE_CAT1(a, b) a##b
#define _FEATURE_CAT(a, b) _FEATURE_CAT1(a, b)

/*
 * Declares that this translation unit implements a "feature" - a unit of plugin
 * functionality.
 *
 * 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*/)

/*
 * 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)

/*
 * Indicates that the specified feature should be initialised before this one,
 * but is not a hard requirement.
 *
 * Presence of a feature can in turn be tested for using has_<featname>.
 */
#define REQUEST(feature) extern bool has_##feature;

/*
 * Indicates that the specified gamedata entry is required for this feature to
 * function. If that entry is missing, this feature will not be enabled.
 *
 * Note that optional gamedata doesn't need to be specified here as it has no
 * effect on whether this feature is loaded. It can simply be tested for using
 * has_<entryname>.
 */
#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 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 which either fail to initialise or elect to skip loading will cause
 * dependent features not to be enabled.
 */
#define INIT int _FEATURE_CAT(_feat_init_, MODULE_NAME)() // { 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(_feat_end_, MODULE_NAME)() // { code... }

/*
 * 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 int _FEATURE_CAT(_feat_preinit_, MODULE_NAME)() // {...}

#endif

// vi: sw=4 ts=4 noet tw=80 cc=80