core/systems/PluginSys.cpp
changeset 211 4c77142eaf36
parent 209 fae1894d884c
child 213 2bec1ff85d06
     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  }