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
|
UQM Code DataPlate modules
=====================================================================
Terminology:
------------
cdp Code DataPlate
refers to either a module or the architecture
itself;
module cdp module (ditto ^)
interface a set of functions defined by either the core
engine or a module aimed at performing various
tasks on a specific part of the game
itf interface; short form
host the game itself or core engine; also a top-level
interface for use by modules
interface kind a unique identifier of a particular defined
interface (not of the interface instance);
there can be several interfaces of the same
kind registered, but they all have to cover
different API versions (version ranges may
overlap though)
standard interface interface *defined* by the core engine
all host, sound, video, gfx, threads, time,
input, io (uio), memory, resource interfaces
are standard, including all subdivisions like
'sound mixer' and 'sound decoder';
a module can implement standard behavior of
the game or extend the game by implementing and
registering a corresponding interface
built-in interface interface *provided* by the core engine
e.g. host, sound, video, gfx, etc. lib wrappers
anything except 'host' can theoretically be
implemented as a 'standard' interface rather
than built-in; sound and video interfaces,
for example, would not make sense to rip out
from the core, but parts of 'gfx' might be good
candidates (gfx should probably be more than
1 interface); do not confuse 'sound' interface
with 'sound decoder' and 'sound mixer', mixers
(MixSDL and OpenAL) are also prime candidates
custom interface interface *defined and provided* by a module,
other than a standard interface
a module may decide to provide (expose) some
interfaces so that other modules can utilize
them; a module will register such interface
the same way it would register a standard
interface it implements
vtbl virtual table; a table of interface functions;
pointer to vtbl is semantically equivalent to
an interface pointer
event a bindable point in code of the engine or any
module; event observer recieves event
notifications via event handlers it installs
h_foo handle to 'foo'
plate cdp module
fork interface; something to poke a plate with
spoon event;
"hit the plate with a spoon" == "notify via
event handler"
Typical calling sequence:
-------------------------
1) something calls adlm_LoadModule(the_mod) ('the_mod' is used here
to identify the module and to *logically* group module properties
and operations performed on the module for the sake of this
document); the_mod gets dlopen()ed;
2) adlm_LoadModule() looks up the only exported symbol 'adlminfo'.
This symbol is the adlm_ModuleInfo struct;
3) adlm_LoadModule() verifies that the_mod is compatible with current
engine and API versions and calls
adlm_GetInterface(HOST,the_mod.api_ver) to lookup the host interface
with the correct API version for the module;
4) adlm_LoadModule() either increments module ref-count (if the module
has already been loaded previously) or calls
the_mod.module_init(host_itf)
5) the_mod.module_init() stores off the host_itf pointer and performs
internal initialization;
6) [Optional; but not useful w/o] the_mod.module_init() calls
host_itf->GetInterface(kind) to get access to whatever standard or
custom interfaces it requires (for example, it requests a sound
interface to register an audio decoder);
7) [Optional] the_mod.module_init() calls
host_itf->RegisterItf(kind,...,itf_vtbl,...) to register the custom
or standard (do not confuse with built-in) interfaces it wishes to
expose to the core engine or other modules;
8) [Continuous normal operation] module calls members of the interfaces
it acquired to perform various game-related tasks; core engine
and/or other modules call members of the interfaces that module
exposed (if it did so);
9) something calls adlm_FreeModule(h_the_mod) either when the game
quits or when the module is dynamically unloaded for whatever
reason: possibly when user decides to dump the game-mod and use
something else in its place or nothing at all, but for now there
is no mechanism to ensure safe mid-game unloading of modules --
interfaces are not ref-counted and anything can hold a pointer to
an interface at any given time (creating a safe system to do this
is probably not cost-effective);
10) adlm_FreeModule() decrements module ref-count and, when ref-count
reaches 0, calls the_mod.module_term();
11) the_mod.module_term() calls host_itf->UnregisterItf(h_itf) to
unregister the interfaces it had exposed previously; then it
unregisters any other objects it registered, releases all objects
it acquired through interfaces and destroys any objects it is
responsible for;
12) the_mod.module_term() performs internal cleanup;
|