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