|
dvander@173
|
1 |
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ |
|
dvander@173
|
2 |
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ |
|
dvander@173
|
3 |
|
|
dvander@211
|
4 |
#include <time.h> |
|
dvander@173
|
5 |
#include <IPluginSys.h> |
|
dvander@220
|
6 |
#include <IHandleSys.h> |
|
dvander@174
|
7 |
#include <sh_list.h> |
|
dvander@174
|
8 |
#include <sh_stack.h> |
|
dvander@173
|
9 |
#include "sm_globals.h" |
|
dvander@177
|
10 |
#include "CFunction.h" |
|
dvander@203
|
11 |
#include "PluginInfoDatabase.h" |
|
dvander@211
|
12 |
#include "sm_trie.h" |
|
dvander@220
|
13 |
#include "sourcemod.h" |
|
dvander@173
|
14 |
|
|
dvander@174
|
15 |
using namespace SourceHook; |
|
dvander@174
|
16 |
|
|
dvander@209
|
17 |
/** |
|
dvander@209
|
18 |
* NOTES: |
|
dvander@209
|
19 |
* |
|
dvander@209
|
20 |
* Currently this system needs a lot of work but it's good skeletally. Plugin creation |
|
dvander@209
|
21 |
* is done without actually compiling anything. This is done by Load functions in the |
|
dvander@209
|
22 |
* manager. This will need a rewrite when we add context switching. |
|
dvander@209
|
23 |
* |
|
dvander@209
|
24 |
* The plugin object itself has a few things to note. The most important is that it stores |
|
dvander@209
|
25 |
* a table of function objects. The manager marshals allocation and freeing of these objects. |
|
dvander@209
|
26 |
* The plugin object can be in erroneous states, they are: |
|
dvander@209
|
27 |
* Plugin_Error --> Some error occurred any time during or after compilation. |
|
dvander@209
|
28 |
* This error can be cleared since the plugin itself is valid. |
|
dvander@209
|
29 |
* However, the state itself being set prevents any runtime action. |
|
dvander@209
|
30 |
* Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it. |
|
dvander@209
|
31 |
* |
|
dvander@209
|
32 |
* If a plugin fails to load externally, it is never added to the internal tracker. However, |
|
dvander@209
|
33 |
* plugins that failed to load from the internal loading mechanism are always tracked. This |
|
dvander@209
|
34 |
* allows users to see which automatically loaded plugins failed, and makes the interface a bit |
|
dvander@209
|
35 |
* more flexible. |
|
dvander@211
|
36 |
* |
|
dvander@211
|
37 |
* Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid |
|
dvander@211
|
38 |
* for execution. SourceMod is a two pass system, and even though the second pass is not implemented |
|
dvander@211
|
39 |
* yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When |
|
dvander@211
|
40 |
* implemented, a Created plugin will be switched to Error in the second pass if it not loadable. |
|
dvander@211
|
41 |
* |
|
dvander@211
|
42 |
* The two pass loading mechanism is described below. Modules/natives are not implemented yet. |
|
dvander@211
|
43 |
* PASS ONE: All loadable plugins are found and have the following steps performed: |
|
dvander@211
|
44 |
* 1. Loading and compilation is attempted. |
|
dvander@211
|
45 |
* 2. If successful, all natives from Core are added. |
|
dvander@211
|
46 |
* 3. OnPluginLoad() is called. |
|
dvander@211
|
47 |
* 4. If failed, any user natives are scrapped and the process halts here. |
|
dvander@211
|
48 |
* 5. If successful, the plugin is ready for Pass 2. |
|
dvander@211
|
49 |
* INTERMEDIATE: |
|
dvander@211
|
50 |
* 1. All forced modules are loaded. |
|
dvander@211
|
51 |
* PASS TWO: All loaded plugins are found and have these steps performed: |
|
dvander@211
|
52 |
* 1. Any modules referenced in the plugin that are not already loaded, are loaded. |
|
dvander@211
|
53 |
* 2. If any module fails to load and the plugin requires it, load fails and jump to step 6. |
|
dvander@211
|
54 |
* 3. If any natives are unresolved, check if they are found in the user-natives pool. |
|
dvander@211
|
55 |
* 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter. |
|
dvander@211
|
56 |
* 5. If the filter fails, the plugin is marked as failed. |
|
dvander@211
|
57 |
* 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped. |
|
dvander@211
|
58 |
* Furthermore, any plugin that referenced these natives must now have pass 2 re-ran. |
|
dvander@211
|
59 |
* PASS THREE (not a real pass): |
|
dvander@211
|
60 |
* 7. Once all plugins are deemed to be loaded, OnPluginInit() is called |
|
dvander@209
|
61 |
*/ |
|
dvander@209
|
62 |
|
|
dvander@174
|
63 |
#define SM_CONTEXTVAR_MYSELF 0 |
|
dvander@174
|
64 |
|
|
dvander@173
|
65 |
struct ContextPair |
|
dvander@173
|
66 |
{ |
|
dvander@209
|
67 |
ContextPair() : base(NULL), ctx(NULL), co(NULL) |
|
dvander@173
|
68 |
{ |
|
dvander@173
|
69 |
}; |
|
dvander@173
|
70 |
IPluginContext *base; |
|
dvander@173
|
71 |
sp_context_t *ctx; |
|
dvander@209
|
72 |
ICompilation *co; |
|
dvander@209
|
73 |
IVirtualMachine *vm; |
|
dvander@173
|
74 |
}; |
|
dvander@173
|
75 |
|
|
dvander@173
|
76 |
class CPlugin : public IPlugin |
|
dvander@173
|
77 |
{ |
|
dvander@174
|
78 |
friend class CPluginManager; |
|
dvander@176
|
79 |
friend class CFunction; |
|
dvander@173
|
80 |
public: |
|
dvander@209
|
81 |
CPlugin(const char *file); |
|
dvander@209
|
82 |
~CPlugin(); |
|
dvander@209
|
83 |
public: |
|
dvander@174
|
84 |
virtual PluginType GetType() const; |
|
dvander@173
|
85 |
virtual SourcePawn::IPluginContext *GetBaseContext() const; |
|
dvander@173
|
86 |
virtual sp_context_t *GetContext() const; |
|
dvander@173
|
87 |
virtual const sm_plugininfo_t *GetPublicInfo() const; |
|
dvander@173
|
88 |
virtual const char *GetFilename() const; |
|
dvander@173
|
89 |
virtual bool IsDebugging() const; |
|
dvander@173
|
90 |
virtual PluginStatus GetStatus() const; |
|
dvander@173
|
91 |
virtual bool SetPauseState(bool paused); |
|
dvander@173
|
92 |
virtual unsigned int GetSerial() const; |
|
dvander@173
|
93 |
virtual const sp_plugin_t *GetPluginStructure() const; |
|
dvander@174
|
94 |
virtual IPluginFunction *GetFunctionByName(const char *public_name); |
|
dvander@174
|
95 |
virtual IPluginFunction *GetFunctionById(funcid_t func_id); |
|
dvander@229
|
96 |
virtual IdentityToken_t *GetIdentity(); |
|
dvander@173
|
97 |
public: |
|
dvander@209
|
98 |
/** |
|
dvander@209
|
99 |
* Creates a plugin object with default values. |
|
dvander@209
|
100 |
* If an error buffer is specified, and an error occurs, the error will be copied to the buffer |
|
dvander@209
|
101 |
* and NULL will be returned. |
|
dvander@209
|
102 |
* If an error buffer is not specified, the error will be copied to an internal buffer and |
|
dvander@209
|
103 |
* a valid (but error-stated) CPlugin will be returned. |
|
dvander@209
|
104 |
*/ |
|
dvander@209
|
105 |
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength); |
|
dvander@209
|
106 |
public: |
|
dvander@209
|
107 |
/** |
|
dvander@209
|
108 |
* Starts the initial compilation of a plugin. |
|
dvander@209
|
109 |
* Returns false if another compilation exists or there is a current context set. |
|
dvander@209
|
110 |
*/ |
|
dvander@209
|
111 |
ICompilation *StartMyCompile(IVirtualMachine *vm); |
|
dvander@209
|
112 |
/** |
|
dvander@209
|
113 |
* Finalizes a compilation. If error buffer is NULL, the error is saved locally. |
|
dvander@209
|
114 |
*/ |
|
dvander@209
|
115 |
bool FinishMyCompile(char *error, size_t maxlength); |
|
dvander@209
|
116 |
void CancelMyCompile(); |
|
dvander@229
|
117 |
|
|
dvander@209
|
118 |
/** |
|
dvander@209
|
119 |
* Sets an error state on the plugin |
|
dvander@209
|
120 |
*/ |
|
dvander@209
|
121 |
void SetErrorState(PluginStatus status, const char *error_fmt, ...); |
|
dvander@211
|
122 |
|
|
dvander@211
|
123 |
/** |
|
dvander@229
|
124 |
* Initializes the plugin's identity information |
|
dvander@229
|
125 |
*/ |
|
dvander@229
|
126 |
void InitIdentity(); |
|
dvander@229
|
127 |
|
|
dvander@229
|
128 |
/** |
|
dvander@211
|
129 |
* Calls the OnPluginLoad function, and sets any failed states if necessary. |
|
dvander@211
|
130 |
* NOTE: Valid pre-states are: Plugin_Created |
|
dvander@211
|
131 |
* If validated, plugin state is changed to Plugin_Loaded |
|
dvander@211
|
132 |
* |
|
dvander@211
|
133 |
* If the error buffer is NULL, the error message is cached locally. |
|
dvander@211
|
134 |
*/ |
|
dvander@211
|
135 |
bool Call_AskPluginLoad(char *error, size_t maxlength); |
|
dvander@211
|
136 |
|
|
dvander@211
|
137 |
/** |
|
dvander@211
|
138 |
* Calls the OnPluginInit function. |
|
dvander@211
|
139 |
* NOTE: Valid pre-states are: Plugin_Created |
|
dvander@211
|
140 |
* NOTE: Pre-state will be changed to Plugin_Running |
|
dvander@211
|
141 |
*/ |
|
dvander@211
|
142 |
void Call_OnPluginInit(); |
|
dvander@211
|
143 |
public: |
|
dvander@211
|
144 |
time_t HasUpdatedFile(); |
|
dvander@173
|
145 |
protected: |
|
dvander@173
|
146 |
void UpdateInfo(); |
|
dvander@173
|
147 |
private: |
|
dvander@209
|
148 |
ContextPair m_ctx; |
|
dvander@174
|
149 |
PluginType m_type; |
|
dvander@173
|
150 |
char m_filename[PLATFORM_MAX_PATH+1]; |
|
dvander@173
|
151 |
PluginStatus m_status; |
|
dvander@173
|
152 |
unsigned int m_serial; |
|
dvander@173
|
153 |
sm_plugininfo_t m_info; |
|
dvander@173
|
154 |
sp_plugin_t *m_plugin; |
|
dvander@176
|
155 |
unsigned int m_funcsnum; |
|
dvander@176
|
156 |
CFunction **m_priv_funcs; |
|
dvander@176
|
157 |
CFunction **m_pub_funcs; |
|
dvander@209
|
158 |
char m_errormsg[256]; |
|
dvander@211
|
159 |
time_t m_LastAccess; |
|
dvander@229
|
160 |
IdentityToken_t *m_ident; |
|
dvander@220
|
161 |
Handle_t m_handle; |
|
dvander@203
|
162 |
}; |
|
dvander@203
|
163 |
|
|
dvander@220
|
164 |
class CPluginManager : |
|
dvander@220
|
165 |
public IPluginManager, |
|
dvander@220
|
166 |
public SMGlobalClass, |
|
dvander@220
|
167 |
public IHandleTypeDispatch |
|
dvander@174
|
168 |
{ |
|
dvander@176
|
169 |
friend class CPlugin; |
|
dvander@174
|
170 |
public: |
|
dvander@174
|
171 |
CPluginManager(); |
|
dvander@176
|
172 |
~CPluginManager(); |
|
dvander@174
|
173 |
public: |
|
dvander@203
|
174 |
/* Implements iterator class */ |
|
dvander@174
|
175 |
class CPluginIterator : public IPluginIterator |
|
dvander@174
|
176 |
{ |
|
dvander@174
|
177 |
public: |
|
dvander@213
|
178 |
CPluginIterator(List<CPlugin *> *mylist); |
|
dvander@174
|
179 |
virtual ~CPluginIterator(); |
|
dvander@174
|
180 |
virtual bool MorePlugins(); |
|
dvander@174
|
181 |
virtual IPlugin *GetPlugin(); |
|
dvander@174
|
182 |
virtual void NextPlugin(); |
|
dvander@174
|
183 |
virtual void Release(); |
|
dvander@174
|
184 |
public: |
|
dvander@174
|
185 |
void Reset(); |
|
dvander@174
|
186 |
private: |
|
dvander@213
|
187 |
List<CPlugin *> *mylist; |
|
dvander@213
|
188 |
List<CPlugin *>::iterator current; |
|
dvander@174
|
189 |
}; |
|
dvander@174
|
190 |
friend class CPluginManager::CPluginIterator; |
|
dvander@203
|
191 |
public: //IPluginManager |
|
dvander@174
|
192 |
virtual IPlugin *LoadPlugin(const char *path, |
|
dvander@174
|
193 |
bool debug, |
|
dvander@174
|
194 |
PluginType type, |
|
dvander@174
|
195 |
char error[], |
|
dvander@174
|
196 |
size_t err_max); |
|
dvander@174
|
197 |
virtual bool UnloadPlugin(IPlugin *plugin); |
|
dvander@174
|
198 |
virtual IPlugin *FindPluginByContext(const sp_context_t *ctx); |
|
dvander@174
|
199 |
virtual unsigned int GetPluginCount(); |
|
dvander@174
|
200 |
virtual IPluginIterator *GetPluginIterator(); |
|
dvander@174
|
201 |
virtual void AddPluginsListener(IPluginsListener *listener); |
|
dvander@174
|
202 |
virtual void RemovePluginsListener(IPluginsListener *listener); |
|
dvander@220
|
203 |
public: //SMGlobalClass |
|
dvander@220
|
204 |
virtual void OnSourceModAllInitialized(); |
|
dvander@220
|
205 |
virtual void OnSourceModShutdown(); |
|
dvander@220
|
206 |
public: //IHandleTypeDispatch |
|
dvander@220
|
207 |
virtual void OnHandleDestroy(HandleType_t type, void *object); |
|
dvander@190
|
208 |
public: |
|
dvander@203
|
209 |
/** |
|
dvander@211
|
210 |
* Loads all plugins not yet loaded |
|
dvander@203
|
211 |
*/ |
|
dvander@211
|
212 |
void LoadAll_FirstPass(const char *config, const char *basedir); |
|
dvander@211
|
213 |
|
|
dvander@211
|
214 |
/** |
|
dvander@211
|
215 |
* Runs the second loading pass for all plugins |
|
dvander@211
|
216 |
*/ |
|
dvander@211
|
217 |
void LoadAll_SecondPass(); |
|
dvander@203
|
218 |
|
|
dvander@203
|
219 |
/** |
|
dvander@203
|
220 |
* Tests a plugin file mask against a local folder. |
|
dvander@203
|
221 |
* The alias is searched backwards from localdir - i.e., given this input: |
|
dvander@203
|
222 |
* csdm/ban csdm/ban |
|
dvander@203
|
223 |
* ban csdm/ban |
|
dvander@203
|
224 |
* csdm/ban optional/csdm/ban |
|
dvander@203
|
225 |
* All of these will return true for an alias match. |
|
dvander@203
|
226 |
* Wildcards are allowed in the filename. |
|
dvander@203
|
227 |
*/ |
|
dvander@209
|
228 |
bool TestAliasMatch(const char *alias, const char *localdir); |
|
dvander@211
|
229 |
|
|
dvander@211
|
230 |
/** |
|
dvander@211
|
231 |
* Registers natives in core itself ONLY. |
|
dvander@211
|
232 |
*/ |
|
dvander@211
|
233 |
void RegisterGlobalNatives(sp_nativeinfo_t *info[]); |
|
dvander@211
|
234 |
|
|
dvander@211
|
235 |
/** |
|
dvander@211
|
236 |
* Returns whether anything loaded will be a late load. |
|
dvander@211
|
237 |
*/ |
|
dvander@211
|
238 |
bool IsLateLoadTime(); |
|
dvander@209
|
239 |
private: |
|
dvander@209
|
240 |
/** |
|
dvander@209
|
241 |
* Recursively loads all plugins in the given directory. |
|
dvander@209
|
242 |
*/ |
|
dvander@209
|
243 |
void LoadPluginsFromDir(const char *basedir, const char *localdir); |
|
dvander@209
|
244 |
|
|
dvander@209
|
245 |
/** |
|
dvander@209
|
246 |
* Loads a plugin using automatic information. |
|
dvander@209
|
247 |
* The file must be relative to the plugins folder. |
|
dvander@209
|
248 |
*/ |
|
dvander@209
|
249 |
void LoadAutoPlugin(const char *file); |
|
dvander@209
|
250 |
|
|
dvander@209
|
251 |
/** |
|
dvander@211
|
252 |
* Adds a plugin object. This is wrapped by LoadPlugin functions. |
|
dvander@211
|
253 |
*/ |
|
dvander@211
|
254 |
void AddPlugin(CPlugin *pPlugin); |
|
dvander@211
|
255 |
|
|
dvander@211
|
256 |
/** |
|
dvander@211
|
257 |
* Runs the second loading pass on a plugin. |
|
dvander@209
|
258 |
*/ |
|
dvander@211
|
259 |
void RunSecondPass(CPlugin *pPlugin); |
|
dvander@211
|
260 |
|
|
dvander@211
|
261 |
/** |
|
dvander@211
|
262 |
* Adds any globally registered natives to a plugin |
|
dvander@211
|
263 |
*/ |
|
dvander@211
|
264 |
void AddCoreNativesToPlugin(CPlugin *pPlugin); |
|
dvander@174
|
265 |
protected: |
|
dvander@209
|
266 |
/** |
|
dvander@209
|
267 |
* Caching internal objects |
|
dvander@209
|
268 |
*/ |
|
dvander@174
|
269 |
void ReleaseIterator(CPluginIterator *iter); |
|
dvander@176
|
270 |
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); |
|
dvander@176
|
271 |
void ReleaseFunctionToPool(CFunction *func); |
|
dvander@229
|
272 |
inline IdentityToken_t *GetIdentity() |
|
dvander@229
|
273 |
{ |
|
dvander@229
|
274 |
return m_MyIdent; |
|
dvander@229
|
275 |
} |
|
dvander@174
|
276 |
private: |
|
dvander@174
|
277 |
List<IPluginsListener *> m_listeners; |
|
dvander@213
|
278 |
List<CPlugin *> m_plugins; |
|
dvander@211
|
279 |
List<sp_nativeinfo_t *> m_natives; |
|
dvander@174
|
280 |
CStack<CPluginManager::CPluginIterator *> m_iters; |
|
dvander@176
|
281 |
CStack<CFunction *> m_funcpool; |
|
dvander@203
|
282 |
CPluginInfoDatabase m_PluginInfo; |
|
dvander@211
|
283 |
Trie *m_LoadLookup; |
|
dvander@211
|
284 |
bool m_AllPluginsLoaded; |
|
dvander@229
|
285 |
IdentityToken_t *m_MyIdent; |
|
dvander@174
|
286 |
}; |
|
dvander@174
|
287 |
|
|
dvander@211
|
288 |
extern CPluginManager g_PluginSys; |
|
dvander@174
|
289 |
|
|
dvander@173
|
290 |
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ |