sourcemod
sourcemod copied to clipboard
Natives is not bounds correctly when OnPluginStart triggers after server launch
Help us help you
- [X] I have checked that my issue doesn't exist yet.
- [X] I have tried my absolute best to reduce the problem-space and have provided the absolute smallest test-case possible.
- [X] I can always reproduce the issue with the provided description below.
Environment
- Operating System version: Linux/Windows
- Game/AppID (with version if applicable): 232330, 232250, 740
- Current SourceMod version: 1.10.0
- Current SourceMod snapshot: 6502
- Current Metamod: Source snapshot: 1.11.0-dev+1144
- [X] I have updated SourceMod to the latest version and it still happens.
- [X] I have updated SourceMod to the latest snapshot and it still happens.
- [X] I have updated SourceMM to the latest snapshot and it still happens.
Description
It looks like issue is in SM, but I'm not sure.
When the first plugin (SMBug_with_natives.sp) has some forward and native, and the forward is called in OnPluginStart() after complete server launch, natives are "not bounded" yet. For example, the second plugin (SMBug_without_natives.sp) calls native from the first plugin. After server launch, everything works as expected:
But when we try to reload the plugin or unload and load it manually, we receive the "Native is not bound" error:

Problematic Code (or Steps to Reproduce)
SMBug_with_natives.sp (first plugin)
#include <sourcemod>
#include <functions>
#include <handles>
Handle g_hForward;
public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
CreateNative("MyNative", _MyNative);
g_hForward = CreateGlobalForward("MyForward", ET_Ignore);
RegPluginLibrary("my_library");
return APLRes_Success;
}
public void OnPluginStart()
{
// perform something initialization
Call_StartForward(g_hForward);
Call_Finish();
}
public int _MyNative(Handle hPlugin, int iParamCount)
{
// do some hard work
return 1;
}
SMBug_without_natives.sp (second plugin)
#include <sourcemod>
#include <functions>
#include <handles>
native int MyNative();
public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
MarkNativeAsOptional("MyNative");
return APLRes_Success;
}
public void OnLibraryAdded(const char[] szName)
{
LogMessage("OnLibraryAdded(): %s", szName);
}
public void MyForward()
{
LogMessage("MyForward()");
LogMessage("MyForward(): calling a native... result %x", MyNative());
}
You should wait until OnAllPluginsLoaded to access other plugins or fire forwards to ensure any changes have propagated which were caused by your plugin loading. So try moving the code in OnPluginStart in SMBug_with_natives.sp to OnAllPluginsLoaded. That should fix your issue.
In my case, i has forward named as XXXX_OnConfigLoaded. Config reads after plugin starting and by server command.
You suggest move config reading (include database connecting and many another initialization stuff) into OnAllPluginsLoaded?
I tested. It solves the issue, but this don't answers, why native is not bounded when OnPluginStart() fires, if we perform binding operations before this forward calls. Exactly for natives availability in another stages.
There is an underlying issue here which is that because you're using an inline native declaration rather than a correctly formatted include file with dependency information, SM has no idea what the relationship between the plugins is which is leaving things in an inconsistent state after you unload/reload the native providing plugin.
Normally SM will sequence load operations in such a way that all depended-upon plugins are loaded before the plugins that depend upon them, which is what makes natives available in OnPluginStart as long as they're registered in AskPluginLoad. That all said, there was another report a few weeks back of reloading a plugin providing natives not re-binding them automatically in dependant plugins.
I'd be interested if you still get the problem when using a correct SharedPlugin declaration alongside the native declaration.
I received this issue with SharedPlugin declaration in another project.
I perform support for plugin what written by another SP scripter. Sometimes users reports issue with plugin reloading. Today i received this report:
sm_rcon sm plugins reload materialadmin.smx
L 04/16/2021 - 16:17:02: [basecommands.smx] "Console<0><Console><Console>" console command (cmdline "sm plugins reload materialadmin.smx")
L 04/16/2021 - 16:17:02: [vip/VIP_Core.smx] OnLibraryAdded: materialadmin
L 04/16/2021 - 16:17:02: [SM] Exception reported: Native is not bound
L 04/16/2021 - 16:17:02: [SM] Blaming: ma_adminmenu.smx
L 04/16/2021 - 16:17:02: [SM] Call stack trace:
L 04/16/2021 - 16:17:02: [SM] [0] MAGetConfigSetting
L 04/16/2021 - 16:17:02: [SM] [1] Line 90, C:\Users\Slava\Downloads\sourcemod-1.10.0-git6460-windows\addons\sourcemod\scripting\ma_adminmenu.sp::MAOnConfigSetting
L 04/16/2021 - 16:17:02: [SM] [3] Call_Finish
L 04/16/2021 - 16:17:02: [SM] [4] Line 486, materialadmin/native.sp::FireOnConfigSetting
L 04/16/2021 - 16:17:02: [SM] [5] Line 1349, materialadmin/function.sp::VerifyServerID
L 04/16/2021 - 16:17:02: [SM] [6] Line 88, materialadmin/config.sp::ReadConfig
L 04/16/2021 - 16:17:02: [SM] [7] Line 283, C:\Users\Slava\Downloads\sourcemod-1.10.0-git6460-windows\addons\sourcemod\scripting\materialadmin.sp::OnPluginStart
[SM] Plugin Material Admin reloaded successfully.
This can be caused because plugin with required native compiled with undefined REQUIRE_PLUGIN?
https://github.com/SB-MaterialAdmin/NewServer/blob/1b7f0aa34df7a87bd976543d9abaa39279eadbe4/addons/sourcemod/scripting/ma_adminmenu.sp#L38-L41
https://github.com/SB-MaterialAdmin/NewServer/blob/1b7f0aa34df7a87bd976543d9abaa39279eadbe4/addons/sourcemod/scripting/include/materialadmin.inc#L6-L15
Ok, i tested now.
Looks like issue related with SharedPlugin.
Currently, i has this code:
// plugin 1 (with native declaration)
#include <sourcemod>
#include <functions>
#include <handles>
Handle g_hForward;
public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
CreateNative("MyNative", _MyNative);
g_hForward = CreateGlobalForward("MyForward", ET_Ignore);
RegPluginLibrary("my_library");
return APLRes_Success;
}
public void OnPluginStart()
{
// perform something initialization
Call_StartForward(g_hForward);
Call_Finish();
}
public int _MyNative(Handle hPlugin, int iParamCount)
{
// do some hard work
return 1;
}
// plugin 2 (calls native from plugin 1)
#include <sourcemod>
#include <functions>
#include <handles>
native int MyNative();
public SharedPlugin __pl_my_library = {
name = "my_library",
file = "SMBug_with_natives.smx",
required = 0
};
public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
MarkNativeAsOptional("MyNative");
return APLRes_Success;
}
public void OnLibraryAdded(const char[] szName)
{
LogMessage("OnLibraryAdded(): %s", szName);
}
public void MyForward()
{
LogMessage("MyForward()");
LogMessage("MyForward(): calling a native... result %x", MyNative());
}
When i compile plugin with required = 1, reload plugin 1 with native performs correctly, without any errors, BUT forward in plugin 2 doesn't fired. When i use required = 0, forward fires, but fails with "Native is not bound" error.

With required = 1 plugin 1 is fully loaded before plugin 2, so plugin 2's use of the forward hasn't been registered yet by the time it is fired.
It looks like there is probably a bug with the required = 0 case, given the order that plugin 1 is doing things it doesn't seem like plugin 2's use of the forward should be registered before it's natives have been bound - optional or not. PluginSys is probably just doing something in the wrong order in the late-load case.