1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/logic/ShareSys.cpp Fri Mar 29 11:37:29 2013 -0700
1.3 @@ -0,0 +1,611 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "ShareSys.h"
1.36 +#include "ExtensionSys.h"
1.37 +#include <ILibrarySys.h>
1.38 +#include "common_logic.h"
1.39 +#include "PluginSys.h"
1.40 +#include "HandleSys.h"
1.41 +
1.42 +ShareSystem g_ShareSys;
1.43 +static unsigned int g_mark_serial = 0;
1.44 +
1.45 +ShareSystem::ShareSystem()
1.46 +{
1.47 + m_IdentRoot.ident = 0;
1.48 + m_TypeRoot = 0;
1.49 + m_IfaceType = 0;
1.50 + m_CoreType = 0;
1.51 +}
1.52 +
1.53 +IdentityToken_t *ShareSystem::CreateCoreIdentity()
1.54 +{
1.55 + if (!m_CoreType)
1.56 + {
1.57 + m_CoreType = CreateIdentType("CORE");
1.58 + }
1.59 +
1.60 + return CreateIdentity(m_CoreType, this);
1.61 +}
1.62 +
1.63 +void ShareSystem::Initialize()
1.64 +{
1.65 + TypeAccess sec;
1.66 +
1.67 + handlesys->InitAccessDefaults(&sec, NULL);
1.68 + sec.ident = GetIdentRoot();
1.69 +
1.70 + m_TypeRoot = handlesys->CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
1.71 + m_IfaceType = handlesys->CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
1.72 +
1.73 + /* Initialize our static identity handle */
1.74 + m_IdentRoot.ident = handlesys->CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
1.75 +
1.76 + /* Add the Handle System and others... they are too innocent and pure to do it themselves */
1.77 + AddInterface(NULL, handlesys);
1.78 + AddInterface(NULL, libsys);
1.79 +}
1.80 +
1.81 +void ShareSystem::OnSourceModShutdown()
1.82 +{
1.83 + if (m_CoreType)
1.84 + {
1.85 + handlesys->RemoveType(m_CoreType, GetIdentRoot());
1.86 + }
1.87 +
1.88 + handlesys->RemoveType(m_IfaceType, GetIdentRoot());
1.89 + handlesys->RemoveType(m_TypeRoot, GetIdentRoot());
1.90 +}
1.91 +
1.92 +IdentityType_t ShareSystem::FindIdentType(const char *name)
1.93 +{
1.94 + HandleType_t type;
1.95 +
1.96 + if (handlesys->FindHandleType(name, &type))
1.97 + {
1.98 + if (g_HandleSys.TypeCheck(type, m_TypeRoot))
1.99 + {
1.100 + return type;
1.101 + }
1.102 + }
1.103 +
1.104 + return 0;
1.105 +}
1.106 +
1.107 +IdentityType_t ShareSystem::CreateIdentType(const char *name)
1.108 +{
1.109 + if (!m_TypeRoot)
1.110 + {
1.111 + return 0;
1.112 + }
1.113 +
1.114 + return handlesys->CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
1.115 +}
1.116 +
1.117 +void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
1.118 +{
1.119 + /* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
1.120 +}
1.121 +
1.122 +IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
1.123 +{
1.124 + if (!m_TypeRoot)
1.125 + {
1.126 + return 0;
1.127 + }
1.128 +
1.129 + /* :TODO: Cache? */
1.130 + IdentityToken_t *pToken = new IdentityToken_t;
1.131 +
1.132 + HandleSecurity sec;
1.133 + sec.pOwner = sec.pIdentity = GetIdentRoot();
1.134 +
1.135 + pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
1.136 + pToken->ptr = ptr;
1.137 + pToken->type = type;
1.138 +
1.139 + return pToken;
1.140 +}
1.141 +
1.142 +bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
1.143 +{
1.144 + if (!iface)
1.145 + {
1.146 + return false;
1.147 + }
1.148 +
1.149 + IfaceInfo info;
1.150 +
1.151 + info.owner = myself;
1.152 + info.iface = iface;
1.153 +
1.154 + m_Interfaces.push_back(info);
1.155 +
1.156 + return true;
1.157 +}
1.158 +
1.159 +bool ShareSystem::RequestInterface(const char *iface_name,
1.160 + unsigned int iface_vers,
1.161 + IExtension *myself,
1.162 + SMInterface **pIface)
1.163 +{
1.164 + /* See if the interface exists */
1.165 + List<IfaceInfo>::iterator iter;
1.166 + SMInterface *iface;
1.167 + IExtension *iface_owner;
1.168 + bool found = false;
1.169 + for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
1.170 + {
1.171 + IfaceInfo &info = (*iter);
1.172 + iface = info.iface;
1.173 + if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
1.174 + {
1.175 + if (iface->GetInterfaceVersion() == iface_vers
1.176 + || iface->IsVersionCompatible(iface_vers))
1.177 + {
1.178 + iface_owner = info.owner;
1.179 + found = true;
1.180 + break;
1.181 + }
1.182 + }
1.183 + }
1.184 +
1.185 + if (!found)
1.186 + {
1.187 + return false;
1.188 + }
1.189 +
1.190 + /* Add a dependency node */
1.191 + if (iface_owner)
1.192 + {
1.193 + IfaceInfo info;
1.194 + info.iface = iface;
1.195 + info.owner = iface_owner;
1.196 + g_Extensions.BindDependency(myself, &info);
1.197 + }
1.198 +
1.199 + if (pIface)
1.200 + {
1.201 + *pIface = iface;
1.202 + }
1.203 +
1.204 + return true;
1.205 +}
1.206 +
1.207 +void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
1.208 +{
1.209 + CNativeOwner *pOwner;
1.210 +
1.211 + pOwner = g_Extensions.GetNativeOwner(myself);
1.212 +
1.213 + pOwner->AddNatives(natives);
1.214 +}
1.215 +
1.216 +void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
1.217 +{
1.218 + HandleSecurity sec;
1.219 +
1.220 + sec.pOwner = GetIdentRoot();
1.221 + sec.pIdentity = GetIdentRoot();
1.222 +
1.223 + handlesys->FreeHandle(identity->ident, &sec);
1.224 + delete identity;
1.225 +}
1.226 +
1.227 +void ShareSystem::DestroyIdentType(IdentityType_t type)
1.228 +{
1.229 + handlesys->RemoveType(type, GetIdentRoot());
1.230 +}
1.231 +
1.232 +void ShareSystem::RemoveInterfaces(IExtension *pExtension)
1.233 +{
1.234 + List<IfaceInfo>::iterator iter = m_Interfaces.begin();
1.235 +
1.236 + while (iter != m_Interfaces.end())
1.237 + {
1.238 + if ((*iter).owner == pExtension)
1.239 + {
1.240 + iter = m_Interfaces.erase(iter);
1.241 + }
1.242 + else
1.243 + {
1.244 + iter++;
1.245 + }
1.246 + }
1.247 +}
1.248 +
1.249 +void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
1.250 +{
1.251 + g_Extensions.AddDependency(myself, filename, require, autoload);
1.252 +}
1.253 +
1.254 +void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
1.255 +{
1.256 + g_Extensions.AddLibrary(myself, name);
1.257 +}
1.258 +
1.259 +void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
1.260 +{
1.261 + unsigned int i;
1.262 + NativeEntry *pEntry;
1.263 + CNativeOwner *pOwner;
1.264 +
1.265 + pOwner = g_Extensions.GetNativeOwner(myself);
1.266 +
1.267 + for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
1.268 + {
1.269 + if ((pEntry = FindNative(natives[i].name)) == NULL)
1.270 + {
1.271 + continue;
1.272 + }
1.273 +
1.274 + if (pEntry->owner != &g_CoreNatives)
1.275 + {
1.276 + continue;
1.277 + }
1.278 +
1.279 + if (pEntry->replacement.owner != NULL)
1.280 + {
1.281 + continue;
1.282 + }
1.283 +
1.284 + /* Now it's safe to add the override */
1.285 + pEntry->replacement.func = natives[i].func;
1.286 + pEntry->replacement.owner = pOwner;
1.287 + pOwner->AddReplacedNative(pEntry);
1.288 + }
1.289 +}
1.290 +
1.291 +NativeEntry *ShareSystem::FindNative(const char *name)
1.292 +{
1.293 + NativeEntry **ppEntry;
1.294 +
1.295 + if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
1.296 + {
1.297 + return NULL;
1.298 + }
1.299 +
1.300 + return *ppEntry;
1.301 +}
1.302 +
1.303 +void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
1.304 +{
1.305 + NativeEntry *pEntry;
1.306 + sp_native_t *native;
1.307 + uint32_t i, native_count;
1.308 + IPluginContext *pContext;
1.309 +
1.310 + pContext = pPlugin->GetBaseContext();
1.311 +
1.312 + /* Generate a new serial ID, mark our dependencies with it. */
1.313 + g_mark_serial++;
1.314 + pPlugin->PropagateMarkSerial(g_mark_serial);
1.315 +
1.316 + native_count = pContext->GetNativesNum();
1.317 + for (i = 0; i < native_count; i++)
1.318 + {
1.319 + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
1.320 + {
1.321 + continue;
1.322 + }
1.323 +
1.324 + /* If we're bound, check if there is a replacement available.
1.325 + * If not, this native is totally finalized.
1.326 + */
1.327 + if (native->status == SP_NATIVE_BOUND)
1.328 + {
1.329 + pEntry = (NativeEntry *)native->user;
1.330 + assert(pEntry != NULL);
1.331 + if (pEntry->replacement.owner == NULL
1.332 + || (pEntry->replacement.owner != NULL
1.333 + && pEntry->replacement.func == native->pfn))
1.334 + {
1.335 + continue;
1.336 + }
1.337 + }
1.338 + /* Otherwise, the native must be in our cache. */
1.339 + else if ((pEntry = FindNative(native->name)) == NULL)
1.340 + {
1.341 + continue;
1.342 + }
1.343 +
1.344 + if (bCoreOnly && pEntry->owner != &g_CoreNatives)
1.345 + {
1.346 + continue;
1.347 + }
1.348 +
1.349 + BindNativeToPlugin(pPlugin, native, i, pEntry);
1.350 + }
1.351 +}
1.352 +
1.353 +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
1.354 +{
1.355 + uint32_t i;
1.356 + sp_native_t *native;
1.357 + IPluginContext *pContext;
1.358 +
1.359 + pContext = pPlugin->GetBaseContext();
1.360 +
1.361 + if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
1.362 + {
1.363 + return;
1.364 + }
1.365 + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
1.366 + {
1.367 + return;
1.368 + }
1.369 +
1.370 + if (native->status == SP_NATIVE_BOUND)
1.371 + {
1.372 + return;
1.373 + }
1.374 +
1.375 + BindNativeToPlugin(pPlugin, native, i, pEntry);
1.376 +}
1.377 +
1.378 +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
1.379 + sp_native_t *native,
1.380 + uint32_t index,
1.381 + NativeEntry *pEntry)
1.382 +{
1.383 + /* Mark as bound... we do the rest next. */
1.384 + native->status = SP_NATIVE_BOUND;
1.385 + native->user = pEntry;
1.386 +
1.387 + /* See if a replacement is available. */
1.388 + if (pEntry->replacement.owner != NULL)
1.389 + {
1.390 + /* Perform a replacement bind. */
1.391 + native->pfn = pEntry->replacement.func;
1.392 + pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
1.393 + }
1.394 + else
1.395 + {
1.396 + /* Perform a normal bind. */
1.397 + native->pfn = pEntry->func;
1.398 +
1.399 + /* We don't bother with dependency crap if the owner is Core. */
1.400 + if (pEntry->owner != &g_CoreNatives)
1.401 + {
1.402 + /* The native is optional, this is a special case */
1.403 + if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
1.404 + {
1.405 + /* Only add if there is a valid owner. */
1.406 + if (pEntry->owner != NULL)
1.407 + {
1.408 + pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
1.409 + }
1.410 + else
1.411 + {
1.412 + native->status = SP_NATIVE_UNBOUND;
1.413 + }
1.414 + }
1.415 + /* Otherwise, we're a strong dependent and not a weak one */
1.416 + else
1.417 + {
1.418 + /* See if this has already been marked as a dependent.
1.419 + * If it has, it means this relationship has already occurred,
1.420 + * and there is no reason to do it again.
1.421 + */
1.422 + if (pEntry->owner != pPlugin->ToNativeOwner()
1.423 + && pEntry->owner->GetMarkSerial() != g_mark_serial)
1.424 + {
1.425 + /* This has not been marked as a dependency yet */
1.426 + //pPlugin->AddDependency(pEntry->owner);
1.427 + pEntry->owner->AddDependent(pPlugin);
1.428 + pEntry->owner->SetMarkSerial(g_mark_serial);
1.429 + }
1.430 + }
1.431 + }
1.432 + }
1.433 +}
1.434 +
1.435 +NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
1.436 +{
1.437 + NativeEntry *pEntry;
1.438 +
1.439 + if ((pEntry = FindNative(ntv->name)) == NULL)
1.440 + {
1.441 + pEntry = new NativeEntry;
1.442 +
1.443 + pEntry->owner = pOwner;
1.444 + pEntry->name = ntv->name;
1.445 + pEntry->func = ntv->func;
1.446 + pEntry->replacement.func = NULL;
1.447 + pEntry->replacement.owner = NULL;
1.448 + pEntry->fake = NULL;
1.449 +
1.450 + m_NtvCache.insert(ntv->name, pEntry);
1.451 +
1.452 + return pEntry;
1.453 + }
1.454 +
1.455 + if (pEntry->owner != NULL)
1.456 + {
1.457 + return NULL;
1.458 + }
1.459 +
1.460 + pEntry->owner = pOwner;
1.461 + pEntry->func = ntv->func;
1.462 + pEntry->name = ntv->name;
1.463 +
1.464 + return pEntry;
1.465 +}
1.466 +
1.467 +void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
1.468 +{
1.469 + NativeEntry *pEntry;
1.470 +
1.471 + if ((pEntry = FindNative(name)) == NULL)
1.472 + {
1.473 + return;
1.474 + }
1.475 +
1.476 + if (pEntry->owner != pOwner)
1.477 + {
1.478 + return;
1.479 + }
1.480 +
1.481 + if (pEntry->fake != NULL)
1.482 + {
1.483 + g_pSourcePawn2->DestroyFakeNative(pEntry->func);
1.484 + delete pEntry->fake;
1.485 + pEntry->fake = NULL;
1.486 + }
1.487 +
1.488 + pEntry->func = NULL;
1.489 + pEntry->name = NULL;
1.490 + pEntry->owner = NULL;
1.491 + pEntry->replacement.func = NULL;
1.492 + pEntry->replacement.owner = NULL;
1.493 +}
1.494 +
1.495 +NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
1.496 +{
1.497 + FakeNative *pFake;
1.498 + NativeEntry *pEntry;
1.499 + SPVM_NATIVE_FUNC gate;
1.500 +
1.501 + if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
1.502 + {
1.503 + return NULL;
1.504 + }
1.505 +
1.506 + pFake = new FakeNative;
1.507 +
1.508 + if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
1.509 + {
1.510 + delete pFake;
1.511 + return NULL;
1.512 + }
1.513 +
1.514 + if (pEntry == NULL)
1.515 + {
1.516 + pEntry = new NativeEntry;
1.517 + m_NtvCache.insert(name, pEntry);
1.518 + }
1.519 +
1.520 + pFake->call = pFunc;
1.521 + pFake->ctx = pFunc->GetParentContext();
1.522 + smcore.strncopy(pFake->name, name, sizeof(pFake->name));
1.523 +
1.524 + pEntry->fake = pFake;
1.525 + pEntry->func = gate;
1.526 + pEntry->name = pFake->name;
1.527 + pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
1.528 + pEntry->replacement.func = NULL;
1.529 + pEntry->replacement.owner = NULL;
1.530 +
1.531 + return pEntry;
1.532 +}
1.533 +
1.534 +void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
1.535 + const char *name)
1.536 +{
1.537 + if (m_caps.retrieve(name) != NULL)
1.538 + return;
1.539 +
1.540 + Capability cap;
1.541 + cap.ext = myself;
1.542 + cap.provider = provider;
1.543 +
1.544 + m_caps.insert(name, cap);
1.545 +}
1.546 +
1.547 +void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
1.548 + const char *name)
1.549 +{
1.550 + Capability *pCap = m_caps.retrieve(name);
1.551 + if (pCap == NULL)
1.552 + return;
1.553 +
1.554 + if (pCap->ext != myself || pCap->provider != provider)
1.555 + return;
1.556 +
1.557 + m_caps.remove(name);
1.558 +}
1.559 +
1.560 +FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
1.561 + const char *name)
1.562 +{
1.563 + switch (feature)
1.564 + {
1.565 + case FeatureType_Native:
1.566 + return TestNative(pRuntime, name);
1.567 + case FeatureType_Capability:
1.568 + return TestCap(name);
1.569 + default:
1.570 + break;
1.571 + }
1.572 +
1.573 + return FeatureStatus_Unknown;
1.574 +}
1.575 +
1.576 +FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
1.577 +{
1.578 + uint32_t index;
1.579 +
1.580 + if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
1.581 + {
1.582 + sp_native_t *native;
1.583 + if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
1.584 + {
1.585 + if (native->status == SP_NATIVE_BOUND)
1.586 + return FeatureStatus_Available;
1.587 + else
1.588 + return FeatureStatus_Unknown;
1.589 + }
1.590 + }
1.591 +
1.592 + NativeEntry *entry = FindNative(name);
1.593 + if (entry == NULL)
1.594 + return FeatureStatus_Unknown;
1.595 +
1.596 + if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
1.597 + (entry->replacement.func != NULL || entry->func != NULL))
1.598 + {
1.599 + return FeatureStatus_Available;
1.600 + }
1.601 + else
1.602 + {
1.603 + return FeatureStatus_Unavailable;
1.604 + }
1.605 +}
1.606 +
1.607 +FeatureStatus ShareSystem::TestCap(const char *name)
1.608 +{
1.609 + Capability *cap = m_caps.retrieve(name);
1.610 + if (cap == NULL)
1.611 + return FeatureStatus_Unknown;
1.612 +
1.613 + return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
1.614 +}