alliedmodders / sourcemod

SourceMod - Source Engine Scripting and Administration
http://www.sourcemod.net/
970 stars 423 forks source link

Optional natives coming from an extension stop working when the extension is reloaded #2169

Open bottiger1 opened 3 months ago

bottiger1 commented 3 months ago

If you have optional natives coming from an extension, they stop working when you reload the extension.

If they come from a plugin instead, if you reload the plugin that provides the natives, they continue to work.

I've spent some time trying to see if it's an easy solution but it appears to be quite complex because "fake natives" which I assume are plugin natives, seem to have an entirely different implementation.

KyleSanderson commented 3 months ago

If you have optional natives coming from an extension, they stop working when you reload the extension.

If they come from a plugin instead, if you reload the plugin that provides the natives, they continue to work.

I've spent some time trying to see if it's an easy solution but it appears to be quite complex because "fake natives" which I assume are plugin natives, seem to have an entirely different implementation.

It's unfortunate that you deleted the template, as this has (binding) seen significant work since 1.5, 1.6, 1.7, 1.8, and I think 1.10.

What version of sourcemod are you running?

bottiger1 commented 3 months ago

If you have optional natives coming from an extension, they stop working when you reload the extension. If they come from a plugin instead, if you reload the plugin that provides the natives, they continue to work. I've spent some time trying to see if it's an easy solution but it appears to be quite complex because "fake natives" which I assume are plugin natives, seem to have an entirely different implementation.

It's unfortunate that you deleted the template, as this has (binding) seen significant work since 1.5, 1.6, 1.7, 1.8, and I think 1.10.

What version of sourcemod are you running?

I'm using bleeding edge sourcemod and this has been a problem for as long as I can remember.

https://github.com/alliedmodders/sourcemod/commit/e07c120cab173a0d40cafa840537cd11c7bb6ee9

bottiger1 commented 3 months ago

I wrote some untested pseudocode.

The logic is to go through all the plugins, find any unbound optional natives, and rebind them.

Do you know if this will work?

bool CPluginManager::RequireExtensions(CPlugin *pPlugin)

if(!ext.required)
{
    pPlugin->optionalExtensions.add(ext.name); // std::set
}

////////////////////////////////////

void CExtension::MarkAllLoaded()

if (!bridge->IsMapLoading())
{

    std::set<string> libs = m_libraries

    for (PluginIter iter(g_PluginSys.m_plugins); !iter.done(); iter.next()) {
        CPlugin *pPlugin = (*iter);
        IPluginContext *pContext = pPlugin->GetBaseContext();

        if(pPlugin->optionalExtensions.contains(GetAPI()->GetExtensionName()))
        {
            sharesys->BeginBindingFor(pPlugin); // maybe not needed?

            uint32_t native_count = pContext->GetNativesNum();
            auto rt = pPlugin->GetRuntime();

            // find unbound optional natives
            for (uint32_t i = 0; i < native_count; i++)
            {
                const sp_native_t *native = pContext->GetRuntime()->GetNative(i);
                if (!native)
                    continue;

                if ( (native->flags & SP_NTVFLAG_OPTIONAL) == 0 || native->func != nullptr)
                    continue;

                auto extensionNative = sharesys->FindNative(native->name);
                if(!extensionNative)
                    continue;

                rt->UpdateNativeBinding(i, extensionNative->native->func, native->flags, nullptr);
            }
        }
    }

}