sourcemod/core/logic/NativeOwner.cpp
Peace-Maker 2c8614c639 Keep optional natives optional after reloading
Bug 6518

Starting from no plugins loaded, after the final step of the following,
basetriggers will be marked as errored because mapchooser is missing:

Load basetriggers
Load mapchooser
Unload mapchooser
Load mapchooser
Unload mapchooser

We lose the SP_NTVFLAG_OPTIONAL when removing a WeakNative. The
__pl_mapchooser_SetNTVOptional() is only called in basetriggers when it
is loaded. It adds the OPTIONAL flag to the mapchooser natives the
basetrigger plugin uses.
When mapchooser is loaded, the native is overwritten and the OPTIONAL
flag consumed (WeakNative registered), but not preserved. Later when
mapchooser is unloaded the WeakNative is removed in
CNativeOwner::UnbindWeakRef, but the OPTIONAL flag isn't added again.
The next time mapchooser is loaded, the natives aren't optional anymore
and will cause a real dependency.

The change in ShareSys isn't needed to fix the error, but is included to
keep the SP_NTVFLAG_OPTIONAL flag consistent.
2016-07-21 01:52:47 +02:00

130 lines
3.6 KiB
C++

/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "NativeOwner.h"
#include "ShareSys.h"
#include "PluginSys.h"
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
{
}
void CNativeOwner::SetMarkSerial(unsigned int serial)
{
m_nMarkSerial = serial;
}
unsigned int CNativeOwner::GetMarkSerial()
{
return m_nMarkSerial;
}
void CNativeOwner::AddDependent(CPlugin *pPlugin)
{
if (m_Dependents.find(pPlugin) == m_Dependents.end())
m_Dependents.push_back(pPlugin);
}
void CNativeOwner::AddWeakRef(const WeakNative & ref)
{
m_WeakRefs.push_back(ref);
}
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
{
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
g_ShareSys.AddNativeToCache(this, native);
m_natives.append(natives);
}
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
{
IPluginContext *pContext;
pContext = ref.pl->GetBaseContext();
pContext->GetRuntime()->UpdateNativeBinding(
ref.idx,
nullptr,
SP_NTVFLAG_OPTIONAL,
nullptr);
}
void CNativeOwner::DropEverything()
{
List<WeakNative>::iterator iter;
/* Unbind and remove all weak references to us */
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
UnbindWeakRef((*iter));
iter = m_WeakRefs.erase(iter);
}
/* Strip all of our natives from the cache */
for (size_t i = 0; i < m_natives.length(); i++) {
const sp_nativeinfo_t *natives = m_natives[i];
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
g_ShareSys.ClearNativeFromCache(this, native->name);
}
m_natives.clear();
for (size_t i = 0; i < m_fakes.length(); i++)
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
m_fakes.clear();
}
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
{
List<WeakNative>::iterator iter;
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
WeakNative & ref = (*iter);
if (ref.pl == pPlugin)
{
iter = m_WeakRefs.erase(iter);
}
else
{
iter++;
}
}
}
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
{
m_Dependents.remove(pPlugin);
DropWeakRefsTo(pPlugin);
}