1.1 --- a/core/systems/PluginSys.cpp Wed Dec 13 11:19:46 2006 +0000
1.2 +++ b/core/systems/PluginSys.cpp Fri Dec 15 13:38:04 2006 +0000
1.3 @@ -5,11 +5,7 @@
1.4 #include "sourcemod.h"
1.5 #include "CTextParsers.h"
1.6
1.7 -CPluginManager g_PluginMngr;
1.8 -
1.9 -CPluginManager::CPluginManager()
1.10 -{
1.11 -}
1.12 +CPluginManager g_PluginSys;
1.13
1.14 CPlugin::CPlugin(const char *file)
1.15 {
1.16 @@ -54,7 +50,7 @@
1.17 {
1.18 for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
1.19 {
1.20 - g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]);
1.21 + g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]);
1.22 }
1.23 delete [] m_pub_funcs;
1.24 m_pub_funcs = NULL;
1.25 @@ -64,7 +60,7 @@
1.26 {
1.27 for (unsigned int i=0; i<m_funcsnum; i++)
1.28 {
1.29 - g_PluginMngr.ReleaseFunctionToPool(m_priv_funcs[i]);
1.30 + g_PluginSys.ReleaseFunctionToPool(m_priv_funcs[i]);
1.31 }
1.32 delete [] m_priv_funcs;
1.33 m_priv_funcs = NULL;
1.34 @@ -196,6 +192,8 @@
1.35 m_pub_funcs = NULL;
1.36 }
1.37
1.38 + m_status = Plugin_Created;
1.39 +
1.40 UpdateInfo();
1.41
1.42 return true;
1.43 @@ -226,7 +224,7 @@
1.44 pFunc = m_pub_funcs[func_id];
1.45 if (!pFunc)
1.46 {
1.47 - pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
1.48 + pFunc = g_PluginSys.GetFunctionFromPool(save, this);
1.49 m_pub_funcs[func_id] = pFunc;
1.50 }
1.51 } else {
1.52 @@ -239,7 +237,7 @@
1.53 pFunc = m_priv_funcs[func_id];
1.54 if (!pFunc)
1.55 {
1.56 - pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
1.57 + pFunc = g_PluginSys.GetFunctionFromPool(save, this);
1.58 m_priv_funcs[func_id] = pFunc;
1.59 }
1.60 }
1.61 @@ -264,7 +262,7 @@
1.62 base->GetPublicByIndex(index, &pub);
1.63 if (pub)
1.64 {
1.65 - pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this);
1.66 + pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this);
1.67 m_pub_funcs[index] = pFunc;
1.68 }
1.69 }
1.70 @@ -307,6 +305,77 @@
1.71 m_info.version = m_info.version ? m_info.version : "";
1.72 }
1.73
1.74 +void CPlugin::Call_OnPluginInit()
1.75 +{
1.76 + if (m_status != Plugin_Loaded)
1.77 + {
1.78 + return;
1.79 + }
1.80 +
1.81 + m_status = Plugin_Running;
1.82 +
1.83 + int err;
1.84 + cell_t result;
1.85 + IPluginFunction *pFunction = GetFunctionByName("OnPluginInit");
1.86 + if (!pFunction)
1.87 + {
1.88 + return;
1.89 + }
1.90 +
1.91 + /* :TODO: push our own handle */
1.92 + pFunction->PushCell(0);
1.93 + if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
1.94 + {
1.95 + /* :TODO: log into debugger instead */
1.96 + SetErrorState(Plugin_Error, "Runtime error %d", err);
1.97 + }
1.98 +}
1.99 +
1.100 +bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
1.101 +{
1.102 + if (m_status != Plugin_Created)
1.103 + {
1.104 + return false;
1.105 + }
1.106 +
1.107 + if (!error)
1.108 + {
1.109 + error = m_errormsg;
1.110 + maxlength = sizeof(m_errormsg);
1.111 + }
1.112 +
1.113 + int err;
1.114 + cell_t result;
1.115 + IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad");
1.116 +
1.117 + if (!pFunction)
1.118 + {
1.119 + return true;
1.120 + }
1.121 +
1.122 + pFunction->PushCell(0); //:TODO: handle to ourself
1.123 + pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
1.124 + pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
1.125 + pFunction->PushCell(maxlength);
1.126 + if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
1.127 + {
1.128 + /* :TODO: debugging system */
1.129 + snprintf(error, maxlength, "Plugin load returned run time error %d", err);
1.130 + m_status = Plugin_Error;
1.131 + return false;
1.132 + }
1.133 +
1.134 + if (!result)
1.135 + {
1.136 + m_status = Plugin_Error;
1.137 + return false;
1.138 + }
1.139 +
1.140 + m_status = Plugin_Loaded;
1.141 +
1.142 + return true;
1.143 +}
1.144 +
1.145 const sp_plugin_t *CPlugin::GetPluginStructure() const
1.146 {
1.147 return m_plugin;
1.148 @@ -397,7 +466,7 @@
1.149
1.150 void CPluginManager::CPluginIterator::Release()
1.151 {
1.152 - g_PluginMngr.ReleaseIterator(this);
1.153 + g_PluginSys.ReleaseIterator(this);
1.154 }
1.155
1.156 CPluginManager::CPluginIterator::~CPluginIterator()
1.157 @@ -413,7 +482,20 @@
1.158 * PLUGIN MANAGER *
1.159 ******************/
1.160
1.161 -void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir)
1.162 +CPluginManager::CPluginManager()
1.163 +{
1.164 + m_LoadLookup = sm_trie_create();
1.165 + m_AllPluginsLoaded = false;
1.166 +}
1.167 +
1.168 +CPluginManager::~CPluginManager()
1.169 +{
1.170 + //:TODO: we need a good way to free what we're holding
1.171 + sm_trie_destroy(m_LoadLookup);
1.172 +}
1.173 +
1.174 +
1.175 +void CPluginManager::LoadAll_FirstPass( const char *config, const char *basedir )
1.176 {
1.177 /* First read in the database of plugin settings */
1.178 SMCParseError err;
1.179 @@ -467,29 +549,51 @@
1.180 } else if (dir->IsEntryFile()) {
1.181 const char *name = dir->GetEntryName();
1.182 size_t len = strlen(name);
1.183 - if (len < 4
1.184 - || strcmp(&name[len-4], ".smx") != 0)
1.185 + if (len >= 4
1.186 + && strcmp(&name[len-4], ".smx") == 0)
1.187 {
1.188 - continue;
1.189 + /* If the filename matches, load the plugin */
1.190 + char plugin[PLATFORM_MAX_PATH+1];
1.191 + if (localpath == NULL)
1.192 + {
1.193 + snprintf(plugin, sizeof(plugin), "%s", name);
1.194 + } else {
1.195 + g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
1.196 + }
1.197 + LoadAutoPlugin(plugin);
1.198 }
1.199 - /* If the filename matches, load the plugin */
1.200 - char plugin[PLATFORM_MAX_PATH+1];
1.201 - if (localpath == NULL)
1.202 - {
1.203 - snprintf(plugin, sizeof(plugin), "%s", name);
1.204 - } else {
1.205 - g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
1.206 - }
1.207 - LoadAutoPlugin(plugin);
1.208 }
1.209 dir->NextEntry();
1.210 }
1.211 g_LibSys.CloseDirectory(dir);
1.212 }
1.213
1.214 +//well i have discovered that gabe newell is very fat, so i wrote this comment now
1.215 +//:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin()
1.216 void CPluginManager::LoadAutoPlugin(const char *file)
1.217 {
1.218 - CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
1.219 + /**
1.220 + * Does this plugin already exist?
1.221 + */
1.222 + CPlugin *pPlugin;
1.223 + if (sm_trie_retrieve(m_LoadLookup, file, (void **)&pPlugin))
1.224 + {
1.225 + /* First check the type */
1.226 + PluginType type = pPlugin->GetType();
1.227 + if (type == PluginType_Private
1.228 + || type == PluginType_Global)
1.229 + {
1.230 + return;
1.231 + }
1.232 + /* Check to see if we should try reloading it */
1.233 + if (pPlugin->GetStatus() == Plugin_BadLoad
1.234 + || pPlugin->GetStatus() == Plugin_Error)
1.235 + {
1.236 + UnloadPlugin(pPlugin);
1.237 + }
1.238 + }
1.239 +
1.240 + pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
1.241
1.242 assert(pPlugin != NULL);
1.243
1.244 @@ -539,12 +643,36 @@
1.245 co = NULL;
1.246 }
1.247
1.248 - InitAndAddPlugin(pPlugin);
1.249 + /* We don't care about the return value */
1.250 + if (pPlugin->GetStatus() == Plugin_Created)
1.251 + {
1.252 + AddCoreNativesToPlugin(pPlugin);
1.253 + pPlugin->Call_AskPluginLoad(NULL, 0);
1.254 + }
1.255 +
1.256 + AddPlugin(pPlugin);
1.257 }
1.258
1.259 IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
1.260 {
1.261 - CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max);
1.262 + /* See if this plugin is already loaded... reformat to get sep chars right */
1.263 + char checkpath[PLATFORM_MAX_PATH+1];
1.264 + g_LibSys.PathFormat(checkpath, sizeof(checkpath), "%s", path);
1.265 +
1.266 + /**
1.267 + * In manually loading a plugin, any sort of load error causes a deletion.
1.268 + * This is because it's assumed manually loaded plugins will not be managed.
1.269 + * For managed plugins, we need the UI to report them properly.
1.270 + */
1.271 +
1.272 + CPlugin *pPlugin;
1.273 + if (sm_trie_retrieve(m_LoadLookup, checkpath, (void **)&pPlugin))
1.274 + {
1.275 + snprintf(error, err_max, "Plugin file is alread loaded");
1.276 + return NULL;
1.277 + }
1.278 +
1.279 + pPlugin = CPlugin::CreatePlugin(path, error, err_max);
1.280
1.281 if (!pPlugin)
1.282 {
1.283 @@ -568,14 +696,24 @@
1.284
1.285 pPlugin->m_type = type;
1.286
1.287 - InitAndAddPlugin(pPlugin);
1.288 + AddCoreNativesToPlugin(pPlugin);
1.289 +
1.290 + /* Finally, ask the plugin if it wants to be loaded */
1.291 + if (!pPlugin->Call_AskPluginLoad(error, err_max))
1.292 + {
1.293 + delete pPlugin;
1.294 + return NULL;
1.295 + }
1.296 +
1.297 + AddPlugin(pPlugin);
1.298
1.299 return pPlugin;
1.300 }
1.301
1.302 -void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin)
1.303 +void CPluginManager::AddPlugin(CPlugin *pPlugin)
1.304 {
1.305 m_plugins.push_back(pPlugin);
1.306 + sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
1.307
1.308 List<IPluginsListener *>::iterator iter;
1.309 IPluginsListener *pListener;
1.310 @@ -585,7 +723,43 @@
1.311 pListener->OnPluginCreated(pPlugin);
1.312 }
1.313
1.314 - /* :TODO: a lot more... */
1.315 + /* If the second pass was already completed, we have to run the pass on this plugin */
1.316 + if (m_AllPluginsLoaded && pPlugin->GetStatus() == Plugin_Loaded)
1.317 + {
1.318 + RunSecondPass(pPlugin);
1.319 + }
1.320 +}
1.321 +
1.322 +void CPluginManager::RunSecondPass(CPlugin *pPlugin)
1.323 +{
1.324 + /* Tell this plugin to finish initializing itself */
1.325 + pPlugin->Call_OnPluginInit();
1.326 +
1.327 + /* Finish by telling all listeners */
1.328 + List<IPluginsListener *>::iterator iter;
1.329 + IPluginsListener *pListener;
1.330 + for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
1.331 + {
1.332 + pListener = (*iter);
1.333 + pListener->OnPluginLoaded(pPlugin);
1.334 + }
1.335 +}
1.336 +
1.337 +void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
1.338 +{
1.339 + List<sp_nativeinfo_t *>::iterator iter;
1.340 +
1.341 + for (iter=m_natives.begin(); iter!=m_natives.end(); iter++)
1.342 + {
1.343 + sp_nativeinfo_t *natives = (*iter);
1.344 + IPluginContext *ctx = pPlugin->GetBaseContext();
1.345 + unsigned int i=0;
1.346 + /* Attempt to bind every native! */
1.347 + while (natives[i].func != NULL)
1.348 + {
1.349 + ctx->BindNative(&natives[i++]);
1.350 + }
1.351 + }
1.352 }
1.353
1.354 bool CPluginManager::UnloadPlugin(IPlugin *plugin)
1.355 @@ -601,6 +775,9 @@
1.356 pListener = (*iter);
1.357 pListener->OnPluginDestroyed(pPlugin);
1.358 }
1.359 +
1.360 + m_plugins.remove(plugin);
1.361 + sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
1.362
1.363 delete pPlugin;
1.364
1.365 @@ -877,7 +1054,7 @@
1.366 return true;
1.367 }
1.368
1.369 -CPluginManager::~CPluginManager()
1.370 +bool CPluginManager::IsLateLoadTime()
1.371 {
1.372 - //:TODO: we need a good way to free what we're holding
1.373 + return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap());
1.374 }