EDIT: After reading your question again, i'm not so sure this is what you wanted, i'm sorry if that's the case.
This is how i do it, i'm not sure if i should be posting it here or in the snippets/tutorials section but whatever.
I think it is safer and less error prone to create an interface rather than giving out the handle to other plugins.
This code will enable plugins to add new items to another plugins menu.
First we need some way of storing our menu items information, i am going to use a multidimensional array for this.
PHP Code:
enum MenuItem
{
String:DisplayName[32],
String:Info[32],
Handle:PluginHandle
};
int g_menu_item[32][MenuItem]; // Each of the 32 slots available can hold two strings and one handle
In this array, we will be able to store up to 32 different items, we'll come back here later.
Adding the item to the menu is the easy part, but we need some way of sending information back to the plugin that created the item.
First create an include file, myplugin.inc;
PHP Code:
#if defined MYPLUGIN_INC
#endinput
#endif
#define MYPLUGIN_INC
typeset MyPlugin_MenuCallback // This function will be used as a callback to send the info string back to the module
{
function void(int client, const char[] info);
}
And while we're here, let's define our native too.
PHP Code:
/**
* Add an item to the MyPlugin main menu.
*
* @param display What the item will appear as in the menu (obviously).
* @param info Information string, used to know what item was selected if multiple have been created by the same plugin.
*
* @return Slot in the array/menu, may be useful for other purposes (removing, finding the item etc).
*/
native int MyPlugin_AddMenuItem(const char[] display, const char[] info, MyPlugin_MenuCallback callback);
public SharedPlugin __pl_myplugin =
{
name = "myplugin",
file = "myplugin.smx",
#if defined REQUIRED_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRED_PLUGIN
public __pl_myplugin_SetNTVOptional()
{
MarkNativeAsOptional("MyPlugin_AddMenuItem");
}
Now let's go back and update our MenuItem enum;
PHP Code:
enum MenuItem
{
String:DisplayName[32],
String:Info[32],
Handle:PluginHandle,
MyPlugin_MenuCallback:Callback
};
int g_menu_item[32][MenuItem];
int g_menu_item_count; // We use this for iterating through the array later
We haven't created our native function yet so let's do that.
PHP Code:
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("MyPlugin_AddMenuItem", Native_AddMenuItem);
RegPluginLibrary("myplugin");
return APLRes_Success;
}
public int Native_AddMenuItem(Handle plugin, int params)
{
char display[32];
GetNativeString(1, display, sizeof(display));
char info[32];
GetNativeString(2, info, sizeof(info));
int item;
for(int i = 0; i < g_menu_item_count; i++) // Iterate through every available item slot until the condition below are met
{
if(g_menu_item[i][PluginHandle] != null) // Here we just make sure the slot is not occupied
{
Format(g_menu_item[i][DisplayName], 32, display);
Format(g_menu_item[i][Info], 32, info);
g_menu_item[i][PluginHandle] = plugin; // We need to know where to go when the item is selected
g_menu_item[i][Callback] = GetNativeCell(3);
g_menu_item_count++;
item = i;
break; // The item was added to the first empty slot in the array, we're done here
}
}
return item; // Return the item slot, again this can be used later.
}
Let's actually create the menu now.
PHP Code:
void ShowMyMenu(int client)
{
Menu menu = new Menu(MenuHandler);
menu.SetTitle("MyPlugin Amazing Menu");
int err_count;
for(int i = 0; i < g_menu_item_count; i++)
{
if(GetPluginStatus(g_menu_item[i][PluginHandle]) != Plugin_Running) // Make sure the plugin is loaded before proceeding
{
g_menu_item[i][PluginHandle] = null; // Something did not work out, remember we checked the plugin handle for null in our native?
err_count++;
break;
}
char buffer[32];
IntToString(i, buffer, sizeof(buffer)); // Passed to the handler, we need the array slot to be able to do anything
menu.AddItem(buffer, g_menu_item[i][DisplayName]);
}
g_menu_item_count -= err_count;
menu.ExitButton = true;
menu.Display(client, 20);
}
public int MenuHandler(Menu menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[32];
menu.GetItem(param2, info, sizeof(info));
int item = StringToInt(info); // Transform our array slot back into an integer
Call_StartFunction(g_menu_item[item][PluginHandle], view_as<Function>(g_menu_item[item][Callback])); // Pass the plugin handle and the callback we stored for this specific item.
Call_PushCell(param1); // Client who selected the item
Call_PushString(g_menu_item[item][Info]); // Item string used by the module
Call_Finish();
}
else if(action == MenuAction_End)
{
delete menu;
}
}
We still need some way to tell our modules it's okay to start adding items, for this we will use a global forward.
PHP Code:
Handle g_fwd_ready = null;
public void OnPluginStart()
{
g_fwd_ready = CreateGlobalForward("OnMyPluginReady", ET_Ignore);
}
public void OnAllPluginsLoaded() // Called once, if it loaded late it will be called right after OnPluginStart
{
Call_StartForward(g_fwd_ready);
Call_Finish();
}
And in our include file
PHP Code:
forward void OnMyPluginReady();
Now if all is well, we should be able to do this:
PHP Code:
#include <sourcemod>
#include <myplugin>
public void OnPluginStart()
{
OnMyPluginReady(); // Account for late-loading
}
public void OnMyPluginReady()
{
MyPlugin_AddMenuItem("My Item #1", "item1", view_as<MyPlugin_MenuCallback>(MyCallback));
MyPlugin_AddMenuItem("My Item #2", "item2", view_as<MyPlugin_MenuCallback>(MyCallback));
}
public void MyPlugin_MenuCallback MyCallback(int client, const char[] info)
{
PrintToChat(client, "%s", info); // either "item1" or "item2"
}
I hope this will help you! It is quite an extensive post so forgive me for any mistakes, i just woke up so i'm still quite tired.