/** * vim: set ts=4 : * ============================================================================= * SourceMod TopMenus Extension * Copyright (C) 2004-2008 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 . * * 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 . * * Version: $Id$ */ #include "extension.h" #include "TopMenuManager.h" #include "TopMenu.h" HandleType_t hTopMenuType; class TopMenuHandle : public IHandleTypeDispatch { public: void OnHandleDestroy(HandleType_t type, void *object) { ITopMenu *pTopMenu = (ITopMenu *)object; g_TopMenus.DestroyTopMenu(pTopMenu); } bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) { *pSize = ((TopMenu *)object)->CalcMemUsage(); return true; } } s_TopMenuHandle; void Initialize_Natives() { hTopMenuType = handlesys->CreateType("ITopMenu", &s_TopMenuHandle, 0, NULL, NULL, myself->GetIdentity(), NULL); } void Shutdown_Natives() { handlesys->RemoveType(hTopMenuType, myself->GetIdentity()); } enum TopMenuAction { TopMenuAction_DisplayOption = 0, TopMenuAction_DisplayTitle = 1, TopMenuAction_SelectOption = 2, TopMenuAction_DrawOption = 3, TopMenuAction_RemoveObject = 4, }; class TopMenuCallbacks : public ITopMenuObjectCallbacks { public: TopMenuCallbacks(IPluginFunction *pFunction) : m_pFunction(pFunction) { } unsigned int OnTopMenuDrawOption(ITopMenu *menu, int client, unsigned int object_id) { char buffer[2] = {ITEMDRAW_DEFAULT, 0x0}; m_pFunction->PushCell(m_hMenuHandle); m_pFunction->PushCell(TopMenuAction_DrawOption); m_pFunction->PushCell(object_id); m_pFunction->PushCell(client); m_pFunction->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); m_pFunction->PushCell(sizeof(buffer)); m_pFunction->Execute(NULL); return (unsigned int)buffer[0]; } void OnTopMenuDisplayOption(ITopMenu *menu, int client, unsigned int object_id, char buffer[], size_t maxlength) { m_pFunction->PushCell(m_hMenuHandle); m_pFunction->PushCell(TopMenuAction_DisplayOption); m_pFunction->PushCell(object_id); m_pFunction->PushCell(client); m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK); m_pFunction->PushCell(maxlength); m_pFunction->Execute(NULL); } void OnTopMenuDisplayTitle(ITopMenu *menu, int client, unsigned int object_id, char buffer[], size_t maxlength) { m_pFunction->PushCell(m_hMenuHandle); m_pFunction->PushCell(TopMenuAction_DisplayTitle); m_pFunction->PushCell(object_id); m_pFunction->PushCell(client); m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK); m_pFunction->PushCell(maxlength); m_pFunction->Execute(NULL); } void OnTopMenuSelectOption(ITopMenu *menu, int client, unsigned int object_id) { unsigned int old_reply = playerhelpers->SetReplyTo(SM_REPLY_CHAT); m_pFunction->PushCell(m_hMenuHandle); m_pFunction->PushCell(TopMenuAction_SelectOption); m_pFunction->PushCell(object_id); m_pFunction->PushCell(client); m_pFunction->PushString(""); m_pFunction->PushCell(0); m_pFunction->Execute(NULL); playerhelpers->SetReplyTo(old_reply); } void OnTopMenuObjectRemoved(ITopMenu *menu, unsigned int object_id) { m_pFunction->PushCell(m_hMenuHandle); m_pFunction->PushCell(TopMenuAction_RemoveObject); m_pFunction->PushCell(object_id); m_pFunction->PushCell(0); m_pFunction->PushString(""); m_pFunction->PushCell(0); m_pFunction->Execute(NULL); delete this; } Handle_t m_hMenuHandle; IPluginFunction *m_pFunction; }; static cell_t CreateTopMenu(IPluginContext *pContext, const cell_t *params) { IPluginFunction *func = pContext->GetFunctionById(params[1]); if (func == NULL) { return pContext ->ThrowNativeError("Invalid function specified"); } TopMenuCallbacks *cb = new TopMenuCallbacks(func); ITopMenu *pMenu = g_TopMenus.CreateTopMenu(cb); if (!pMenu) { delete cb; return BAD_HANDLE; } Handle_t hndl = handlesys->CreateHandle(hTopMenuType, pMenu, pContext->GetIdentity(), myself->GetIdentity(), NULL); if (hndl == 0) { g_TopMenus.DestroyTopMenu(pMenu); return BAD_HANDLE; } cb->m_hMenuHandle = hndl; return hndl; } static cell_t LoadTopMenuConfig(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } char *file, *err_buf; pContext->LocalToString(params[2], &file); pContext->LocalToString(params[3], &err_buf); char path[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); return pMenu->LoadConfiguration(path, err_buf, params[4]) ? 1 : 0; } static cell_t AddToTopMenu(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } IPluginFunction *func = pContext->GetFunctionById(params[4]); if (func == NULL) { return pContext ->ThrowNativeError("Invalid function specified"); } TopMenuCallbacks *cb = new TopMenuCallbacks(func); char *name, *cmdname, *info_string = NULL; pContext->LocalToString(params[2], &name); pContext->LocalToString(params[6], &cmdname); if (params[0] >= 8) { pContext->LocalToString(params[8], &info_string); } TopMenuObjectType obj_type = (TopMenuObjectType)params[3]; unsigned int object_id; if ((object_id = pMenu->AddToMenu2(name, obj_type, cb, pContext->GetIdentity(), cmdname, params[7], params[5], info_string)) == 0) { delete cb; return 0; } cb->m_hMenuHandle = params[1]; return object_id; } static cell_t RemoveFromTopMenu(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } pMenu->RemoveFromMenu(params[2]); return 1; } static cell_t FindTopMenuCategory(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } char *name; pContext->LocalToString(params[2], &name); return pMenu->FindCategory(name); } static cell_t DisplayTopMenu(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } int client = params[2]; IGamePlayer *player = playerhelpers->GetGamePlayer(client); if (!player) { return pContext->ThrowNativeError("Invalid client index %d", client); } else if (!player->IsInGame()) { return pContext->ThrowNativeError("Client %d is not in game", client); } return pMenu->DisplayMenu(client, 0, (TopMenuPosition)params[3]); } static cell_t DisplayTopMenuCategory(IPluginContext *pContext, const cell_t *params) { HandleError err; TopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } int client = params[3]; IGamePlayer *player = playerhelpers->GetGamePlayer(client); if (!player) { return pContext->ThrowNativeError("Invalid client index %d", client); } else if (!player->IsInGame()) { return pContext->ThrowNativeError("Client %d is not in game", client); } return pMenu->DisplayMenuAtCategory(client, params[2]); } static cell_t GetTopMenuInfoString(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } const char *str; if ((str = pMenu->GetObjectInfoString(params[2])) == NULL) { return pContext->ThrowNativeError("Invalid menu object %d", params[2]); } char *buffer; pContext->LocalToString(params[3], &buffer); return strncopy(buffer, str, params[4]); } static cell_t GetTopMenuName(IPluginContext *pContext, const cell_t *params) { HandleError err; ITopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } const char *str; if ((str = pMenu->GetObjectName(params[2])) == NULL) { return pContext->ThrowNativeError("Invalid menu object %d", params[2]); } char *buffer; pContext->LocalToString(params[3], &buffer); return strncopy(buffer, str, params[4]); } static cell_t SetTopMenuTitleCaching(IPluginContext *pContext, const cell_t *params) { HandleError err; TopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } bool cache_titles = params[2]==1?true:false; pMenu->SetTitleCaching(cache_titles); return 0; } static cell_t TopMenu_AddItem(IPluginContext *pContext, const cell_t *params) { cell_t new_params[] = { 8, params[1], // this params[2], // name TopMenuObject_Item, // type params[3], // handler params[4], // parent params[5], // cmdname params[6], // flags params[7], // info_string }; return AddToTopMenu(pContext, new_params); } static cell_t TopMenu_AddCategory(IPluginContext *pContext, const cell_t *params) { cell_t new_params[] = { 8, params[1], // this params[2], // name TopMenuObject_Category, // type params[3], // handler 0, // parent params[4], // cmdname params[5], // flags params[6], // info_string }; return AddToTopMenu(pContext, new_params); } static cell_t TopMenu_FromHandle(IPluginContext *pContext, const cell_t *params) { HandleError err; TopMenu *pMenu; HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) != HandleError_None) { return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); } return params[1]; } sp_nativeinfo_t g_TopMenuNatives[] = { {"AddToTopMenu", AddToTopMenu}, {"CreateTopMenu", CreateTopMenu}, {"DisplayTopMenu", DisplayTopMenu}, {"DisplayTopMenuCategory", DisplayTopMenuCategory}, {"LoadTopMenuConfig", LoadTopMenuConfig}, {"RemoveFromTopMenu", RemoveFromTopMenu}, {"FindTopMenuCategory", FindTopMenuCategory}, {"GetTopMenuInfoString", GetTopMenuInfoString}, {"GetTopMenuObjName", GetTopMenuName}, {"SetTopMenuTitleCaching", SetTopMenuTitleCaching}, // Transitional variants. {"TopMenu.TopMenu", CreateTopMenu}, {"TopMenu.AddItem", TopMenu_AddItem}, {"TopMenu.AddCategory", TopMenu_AddCategory}, {"TopMenu.Display", DisplayTopMenu}, {"TopMenu.DisplayCategory", DisplayTopMenuCategory}, {"TopMenu.LoadConfig", LoadTopMenuConfig}, {"TopMenu.Remove", RemoveFromTopMenu}, {"TopMenu.FindCategory", FindTopMenuCategory}, {"TopMenu.GetInfoString", GetTopMenuInfoString}, {"TopMenu.GetObjName", GetTopMenuName}, {"TopMenu.CacheTitles.set", SetTopMenuTitleCaching}, {"TopMenu.FromHandle", TopMenu_FromHandle}, {NULL, NULL}, };