Optional Requirements (SourceMod Scripting)

From AlliedModders Wiki
Revision as of 00:53, 30 July 2007 by Shane (talk | contribs) (Full Example)
Jump to: navigation, search

Normally, if you use natives from an extension or another plugin, your plugin will not load unless those natives exist. However, it is possible to make your dependencies "optional." This article details how.

Disabling Requirements

Extensions

To disable an extension being marked as "required," remove the REQUIRE_EXTENSIONS define. For example:

#include <sourcemod>
#undef REQUIRE_EXTENSIONS
#include <sdktools>

Note that any extensions included after the #undef will also be marked as required. Thus, you may need to move the include down, or do something like:

#include <sourcemod>
#undef REQUIRE_EXTENSIONS
#include <sdktools>
#define REQUIRE_EXTENSIONS

Plugins

To disable an plugin being marked as "required," remove the REQUIRE_PLUGIN define. For example:

#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <ircrelay>

Note that any plugins included after the #undef will also be marked as required. Thus, you may need to move the include down, or do something like:

#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <ircrelay>
#define REQUIRE_PLUGIN

Optional Natives

To mark a native as optional, use MarkNativeAsOptional. It should be called in AskPluginLoad. For example:

public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
{
	MarkNativeAsOptional("SDKCall");
}


Checking Optional Dependencies

If you use a plugin or extension as an optional dependency, you may need to check whether it exists. For example, let's say we're relying on a plugin with the library name of "ircrelay." The way to always know whether ircrelay is loaded (and working) is:

new bool:ircrelay = false;
 
public OnPluginStart()
{
	ircrelay = LibraryExists("ircrelay");
}
 
public OnLibraryRemoved(const String:name[])
{
	if (StrEqual(name, "ircrelay"))
	{
		ircrelay = false;
	}
}
 
public OnLibraryAdded(const String:name[])
{
	if (StrEqual(name, "ircrelay"))
	{
		ircrelay = true;
	}
}


Creating a Dependency

Allowing other plugins to use your plugin as a library requires making an include file with two structures (the second of which is optional). The first structure must look like this:

public SharedPlugin:__pl_myfile = 
{
	name = "myfile",
	file = "myfile.smx",
#if defined REQUIRE_PLUGIN
	required = 1,
#else
	required = 0,
#endif
};

The basic format is:

  • The variable name MUST start with __pl_ and must end with a unique string.
  • The "name" portion is treated as the library name and must be unique.
  • The filename must match the filename of the plugin implementing the library.
  • The requirement portion should remain unchanged in order to maintain standards.

Additionally, you should expose a function which marks all of your natives as optional. You can do this by:

public __pl_myfile_SetNTVOptional()
{
	MarkNativeAsOptional("native1");
	MarkNativeAsOptional("native2");
	MarkNativeAsOptional("native3");
}

This function will be secretly called before the plugin loads (if and only if the requirement is optional), thus allowing seamless optional usage by third party developers. Note that the __pl_ and _SetNTVOptional portions must be present, and that everything in between must match the ending of __pl_ for the SharedPlugin structure.

You also must register the library name with SourceMod -- again this should be the unique string. This is should be done inside the OnPluginStart function.

public OnPluginStart() 
{
	//... code here ...
	RegPluginLibrary("myfile");
}

Full Example

Bounty: bounty.sp
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <ircrelay>
Bounty: bounty.config.sp
new bool:plugin_IrcRelay = LibraryExists("ircrelay");
if ((BountyIRC) && (plugin_IrcRelay))
{
	RegisterIrcCommand("!bounty", "x", Irc_ViewBounty);
	IrcMessage(CHAN_MASTER, "IRC Bounty Running!");
} else {
	if ((BountyIRC) && (!plugin_IrcRelay))
	{
		BountyConsole_Debug("%t", "Bounty IRC Relay failed");
	}
}
IRC Relay: ircrelay.sp
public OnPluginStart() 
{
	//... code here ...
	RegPluginLibrary("ircrelay");
}
IRC Relay: ircrelay.inc
public SharedPlugin:__pl_ircrelay = 
{
	name = "ircrelay",
	file = "ircrelay.smx",
#if defined REQUIRE_PLUGIN
	required = 1,
#else
	required = 0,
#endif
};
 
public __pl_ircrelay_SetNTVOptional()
{
	MarkNativeAsOptional("IrcMessage");
	MarkNativeAsOptional("RegisterIrcCommand");
	MarkNativeAsOptional("IrcGetCmdArgc");
	MarkNativeAsOptional("IrcGetCmdArgv");
}

The name value is what will be checked when you run LibraryExists. This allows the bounty script to fully work, even if the IRC relay plugin is not installed and/or running correctly on your server.