core/systems/ShareSys.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Sep 14 03:01:05 2008 -0500 (2008-09-14)
changeset 2289 44045ead61cd
parent 2226 d10b38524be3
parent 1947 e73a1e51833b
child 2384 a92e5558410e
permissions -rw-r--r--
Eliminated head: da55a80522cf, a remnant of sourcemod-1.1.0 branch
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "ShareSys.h"
    33 #include "HandleSys.h"
    34 #include "ExtensionSys.h"
    35 #include "LibrarySys.h"
    36 #include "PluginSys.h"
    37 #include "sm_stringutil.h"
    38 
    39 ShareSystem g_ShareSys;
    40 static unsigned int g_mark_serial = 0;
    41 
    42 ShareSystem::ShareSystem()
    43 {
    44 	m_IdentRoot.ident = 0;
    45 	m_TypeRoot = 0;
    46 	m_IfaceType = 0;
    47 	m_CoreType = 0;
    48 }
    49 
    50 IdentityToken_t *ShareSystem::CreateCoreIdentity()
    51 {
    52 	if (!m_CoreType)
    53 	{
    54 		m_CoreType = CreateIdentType("CORE");
    55 	}
    56 
    57 	return CreateIdentity(m_CoreType, this);
    58 }
    59 
    60 void ShareSystem::Initialize()
    61 {
    62 	TypeAccess sec;
    63 
    64 	g_HandleSys.InitAccessDefaults(&sec, NULL);
    65 	sec.ident = GetIdentRoot();
    66 
    67 	m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
    68 	m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
    69 
    70 	/* Initialize our static identity handle */
    71 	m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
    72 
    73 	/* Add the Handle System and others... they are too innocent and pure to do it themselves */
    74 	AddInterface(NULL, &g_HandleSys);
    75 	AddInterface(NULL, &g_LibSys);
    76 }
    77 
    78 void ShareSystem::OnSourceModShutdown()
    79 {
    80 	if (m_CoreType)
    81 	{
    82 		g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
    83 	}
    84 
    85 	g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
    86 	g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
    87 }
    88 
    89 IdentityType_t ShareSystem::FindIdentType(const char *name)
    90 {
    91 	HandleType_t type;
    92 
    93 	if (g_HandleSys.FindHandleType(name, &type))
    94 	{
    95 		if (g_HandleSys.TypeCheck(type, m_TypeRoot))
    96 		{
    97 			return type;
    98 		}
    99 	}
   100 
   101 	return 0;
   102 }
   103 
   104 IdentityType_t ShareSystem::CreateIdentType(const char *name)
   105 {
   106 	if (!m_TypeRoot)
   107 	{
   108 		return 0;
   109 	}
   110 
   111 	return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
   112 }
   113 
   114 void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
   115 {
   116 	/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
   117 }
   118 
   119 IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
   120 {
   121 	if (!m_TypeRoot)
   122 	{
   123 		return 0;
   124 	}
   125 
   126 	/* :TODO: Cache? */
   127 	IdentityToken_t *pToken = new IdentityToken_t;
   128 
   129 	HandleSecurity sec;
   130 	sec.pOwner = sec.pIdentity = GetIdentRoot();
   131 
   132 	pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
   133 	pToken->ptr = ptr;
   134 	pToken->type = type;
   135 
   136 	return pToken;
   137 }
   138 
   139 bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
   140 {
   141 	if (!iface)
   142 	{
   143 		return false;
   144 	}
   145 
   146 	IfaceInfo info;
   147 
   148 	info.owner = myself;
   149 	info.iface = iface;
   150 	
   151 	m_Interfaces.push_back(info);
   152 
   153 	return true;
   154 }
   155 
   156 bool ShareSystem::RequestInterface(const char *iface_name, 
   157 								   unsigned int iface_vers, 
   158 								   IExtension *myself, 
   159 								   SMInterface **pIface)
   160 {
   161 	/* See if the interface exists */
   162 	List<IfaceInfo>::iterator iter;
   163 	SMInterface *iface;
   164 	IExtension *iface_owner;
   165 	bool found = false;
   166 	for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
   167 	{
   168 		IfaceInfo &info = (*iter);
   169 		iface = info.iface;
   170 		if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
   171 		{
   172 			if (iface->GetInterfaceVersion() == iface_vers
   173 				|| iface->IsVersionCompatible(iface_vers))
   174 			{
   175 				iface_owner = info.owner;
   176 				found = true;
   177 				break;
   178 			}
   179 		}
   180 	}
   181 
   182 	if (!found)
   183 	{
   184 		return false;
   185 	}
   186 
   187 	/* Add a dependency node */
   188 	if (iface_owner)
   189 	{
   190 		IfaceInfo info;
   191 		info.iface = iface;
   192 		info.owner = iface_owner;
   193 		g_Extensions.BindDependency(myself, &info);
   194 	}
   195 
   196 	if (pIface)
   197 	{
   198 		*pIface = iface;
   199 	}
   200 
   201 	return true;
   202 }
   203 
   204 void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
   205 {
   206 	CNativeOwner *pOwner;
   207 
   208 	pOwner = g_Extensions.GetNativeOwner(myself);
   209 
   210 	pOwner->AddNatives(natives);
   211 }
   212 
   213 void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
   214 {
   215 	HandleSecurity sec;
   216 
   217 	sec.pOwner = GetIdentRoot();
   218 	sec.pIdentity = GetIdentRoot();
   219 
   220 	g_HandleSys.FreeHandle(identity->ident, &sec);
   221 	delete identity;
   222 }
   223 
   224 void ShareSystem::DestroyIdentType(IdentityType_t type)
   225 {
   226 	g_HandleSys.RemoveType(type, GetIdentRoot());
   227 }
   228 
   229 void ShareSystem::RemoveInterfaces(IExtension *pExtension)
   230 {
   231 	List<IfaceInfo>::iterator iter = m_Interfaces.begin();
   232 
   233 	while (iter != m_Interfaces.end())
   234 	{
   235 		if ((*iter).owner == pExtension)
   236 		{
   237 			iter = m_Interfaces.erase(iter);
   238 		}
   239 		else
   240 		{
   241 			iter++;
   242 		}
   243 	}
   244 }
   245 
   246 void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
   247 {
   248 	g_Extensions.AddDependency(myself, filename, require, autoload);
   249 }
   250 
   251 void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
   252 {
   253 	g_Extensions.AddLibrary(myself, name);
   254 }
   255 
   256 void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
   257 {
   258 	unsigned int i;
   259 	NativeEntry *pEntry;
   260 	CNativeOwner *pOwner;
   261 
   262 	pOwner = g_Extensions.GetNativeOwner(myself);
   263 
   264 	for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
   265 	{
   266 		if ((pEntry = FindNative(natives[i].name)) == NULL)
   267 		{
   268 			continue;
   269 		}
   270 
   271 		if (pEntry->owner != g_pCoreNatives)
   272 		{
   273 			continue;
   274 		}
   275 
   276 		if (pEntry->replacement.owner != NULL)
   277 		{
   278 			continue;
   279 		}
   280 
   281 		/* Now it's safe to add the override */
   282 		pEntry->replacement.func = natives[i].func;
   283 		pEntry->replacement.owner = pOwner;
   284 		pOwner->AddReplacedNative(pEntry);
   285 	}
   286 }
   287 
   288 NativeEntry *ShareSystem::FindNative(const char *name)
   289 {
   290 	NativeEntry **ppEntry;
   291 
   292 	if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
   293 	{
   294 		return NULL;
   295 	}
   296 
   297 	return *ppEntry;
   298 }
   299 
   300 void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
   301 {
   302 	NativeEntry *pEntry;
   303 	sp_native_t *native;
   304 	uint32_t i, native_count;
   305 	IPluginContext *pContext;
   306 
   307 	pContext = pPlugin->GetBaseContext();
   308 
   309 	/* Generate a new serial ID, mark our dependencies with it. */
   310 	g_mark_serial++;
   311 	pPlugin->PropogateMarkSerial(g_mark_serial);
   312 
   313 	native_count = pContext->GetNativesNum();
   314 	for (i = 0; i < native_count; i++)
   315 	{
   316 		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
   317 		{
   318 			continue;
   319 		}
   320 
   321 		/* If we're bound, check if there is a replacement available.  
   322 		 * If not, this native is totally finalized.
   323 		 */
   324 		if (native->status == SP_NATIVE_BOUND)
   325 		{
   326 			pEntry = (NativeEntry *)native->user;
   327 			assert(pEntry != NULL);
   328 			if (pEntry->replacement.owner == NULL
   329 				|| (pEntry->replacement.owner != NULL 
   330 				&&  pEntry->replacement.func == native->pfn))
   331 			{
   332 				continue;
   333 			}
   334 		}
   335 		/* Otherwise, the native must be in our cache. */
   336 		else if ((pEntry = FindNative(native->name)) == NULL)
   337 		{
   338 			continue;
   339 		}
   340 
   341 		if (bCoreOnly && pEntry->owner != g_pCoreNatives)
   342 		{
   343 			continue;
   344 		}
   345 
   346 		BindNativeToPlugin(pPlugin, native, i, pEntry);
   347 	}
   348 }
   349 
   350 void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
   351 {
   352 	uint32_t i;
   353 	sp_native_t *native;
   354 	IPluginContext *pContext;
   355 
   356 	pContext = pPlugin->GetBaseContext();
   357 
   358 	if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
   359 	{
   360 		return;
   361 	}
   362 	if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
   363 	{
   364 		return;
   365 	}
   366 
   367 	if (native->status == SP_NATIVE_BOUND)
   368 	{
   369 		return;
   370 	}
   371 
   372 	BindNativeToPlugin(pPlugin, native, i, pEntry);
   373 }
   374 
   375 void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, 
   376 									 sp_native_t *native,
   377 									 uint32_t index,
   378 									 NativeEntry *pEntry)
   379 {
   380 	/* Mark as bound... we do the rest next. */
   381 	native->status = SP_NATIVE_BOUND;
   382 	native->user = pEntry;
   383 
   384 	/* See if a replacement is available. */
   385 	if (pEntry->replacement.owner != NULL)
   386 	{
   387 		/* Perform a replacement bind. */
   388 		native->pfn = pEntry->replacement.func;
   389 		pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
   390 	}
   391 	else
   392 	{
   393 		/* Perform a normal bind. */
   394 		native->pfn = pEntry->func;
   395 
   396 		/* We don't bother with dependency crap if the owner is Core. */
   397 		if (pEntry->owner != g_pCoreNatives)
   398 		{
   399 			/* The native is optional, this is a special case */
   400 			if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
   401 			{
   402 				/* Only add if there is a valid owner. */
   403 				if (pEntry->owner != NULL)
   404 				{
   405 					pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
   406 				}
   407 				else
   408 				{
   409 					native->status = SP_NATIVE_UNBOUND;
   410 				}
   411 			}
   412 			/* Otherwise, we're a strong dependent and not a weak one */
   413 			else
   414 			{
   415 				/* See if this has already been marked as a dependent.
   416 				 * If it has, it means this relationship has already occurred, 
   417 				 * and there is no reason to do it again.
   418 				 */
   419 				if (pEntry->owner != pPlugin 
   420 					&& pEntry->owner->GetMarkSerial() != g_mark_serial)
   421 				{
   422 					/* This has not been marked as a dependency yet */
   423 					//pPlugin->AddDependency(pEntry->owner);
   424 					pEntry->owner->AddDependent(pPlugin);
   425 					pEntry->owner->SetMarkSerial(g_mark_serial);
   426 				}
   427 			}
   428 		}
   429 	}
   430 }
   431 
   432 NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
   433 {
   434 	NativeEntry *pEntry;
   435 
   436 	if ((pEntry = FindNative(ntv->name)) == NULL)
   437 	{
   438 		pEntry = new NativeEntry;
   439 
   440 		pEntry->owner = pOwner;
   441 		pEntry->name = ntv->name;
   442 		pEntry->func = ntv->func;
   443 		pEntry->replacement.func = NULL;
   444 		pEntry->replacement.owner = NULL;
   445 		pEntry->fake = NULL;
   446 
   447 		m_NtvCache.insert(ntv->name, pEntry);
   448 
   449 		return pEntry;
   450 	}
   451 
   452 	if (pEntry->owner != NULL)
   453 	{
   454 		return NULL;
   455 	}
   456 
   457 	pEntry->owner = pOwner;
   458 	pEntry->func = ntv->func;
   459 	pEntry->name = ntv->name;
   460 	pEntry->func = NULL;
   461 
   462 	return pEntry;
   463 }
   464 
   465 void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
   466 {
   467 	NativeEntry *pEntry;
   468 
   469 	if ((pEntry = FindNative(name)) == NULL)
   470 	{
   471 		return;
   472 	}
   473 
   474 	if (pEntry->owner != pOwner)
   475 	{
   476 		return;
   477 	}
   478 
   479 	if (pEntry->fake != NULL)
   480 	{
   481 		g_pSourcePawn2->DestroyFakeNative(pEntry->func);
   482 		delete pEntry->fake;
   483 		pEntry->fake = NULL;
   484 	}
   485 
   486 	pEntry->func = NULL;
   487 	pEntry->name = NULL;
   488 	pEntry->owner = NULL;
   489 	pEntry->replacement.func = NULL;
   490 	pEntry->replacement.owner = NULL;
   491 }
   492 
   493 NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
   494 {
   495 	FakeNative *pFake;
   496 	NativeEntry *pEntry;
   497 	SPVM_NATIVE_FUNC gate;
   498 
   499 	if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
   500 	{
   501 		return NULL;
   502 	}
   503 
   504 	pFake = new FakeNative;
   505 
   506 	if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
   507 	{
   508 		delete pFake;
   509 		return NULL;
   510 	}
   511 
   512 	if (pEntry == NULL)
   513 	{
   514 		pEntry = new NativeEntry;
   515 		m_NtvCache.insert(name, pEntry);
   516 	}
   517 
   518 	pFake->call = pFunc;
   519 	pFake->ctx = pFunc->GetParentContext();
   520 	strncopy(pFake->name, name, sizeof(pFake->name));
   521 	
   522 	pEntry->fake = pFake;
   523 	pEntry->func = gate;
   524 	pEntry->name = pFake->name;
   525 	pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
   526 	pEntry->replacement.func = NULL;
   527 	pEntry->replacement.owner = NULL;
   528 
   529 	return pEntry;
   530 }