diff --git a/amxmodx/CForward.cpp b/amxmodx/CForward.cpp index e4653c01..aa0c4230 100755 --- a/amxmodx/CForward.cpp +++ b/amxmodx/CForward.cpp @@ -543,7 +543,9 @@ void CForwardMngr::unregisterSPForward(int id) { //make sure the id is valid if (!isIdValid(id) || m_SPForwards.at(id >> 1)->isFree) + { return; + } CSPForward *fwd = m_SPForwards.at(id >> 1); @@ -556,6 +558,38 @@ void CForwardMngr::unregisterSPForward(int id) } } +int CForwardMngr::duplicateSPForward(int id) +{ + if (!isIdValid(id) || m_SPForwards.at(id >> 1)->isFree) + { + return -1; + } + + CSPForward *fwd = m_SPForwards.at(id >> 1); + + return registerSPForward(fwd->m_Func, fwd->m_Amx, fwd->m_NumParams, fwd->m_ParamTypes); +} + +int CForwardMngr::isSameSPForward(int id1, int id2) +{ + if (!isIdValid(id1) || !isIdValid(id2)) + { + return false; + } + + CSPForward *fwd1 = m_SPForwards.at(id1 >> 1); + CSPForward *fwd2 = m_SPForwards.at(id2 >> 1); + + if (fwd1->isFree || fwd2->isFree) + { + return false; + } + + return ((fwd1->m_Amx == fwd2->m_Amx) + && (fwd1->m_Func == fwd2->m_Func) + && (fwd1->m_NumParams == fwd2->m_NumParams)); +} + int registerForwardC(const char *funcName, ForwardExecType et, cell *list, size_t num, int fwd_type) { ForwardParam params[FORWARD_MAX_PARAMS]; diff --git a/amxmodx/CForward.h b/amxmodx/CForward.h index 8f868ae6..be5aa26f 100755 --- a/amxmodx/CForward.h +++ b/amxmodx/CForward.h @@ -217,6 +217,8 @@ public: // Unregister single plugin forward void unregisterSPForward(int id); + int duplicateSPForward(int id); + int isSameSPForward(int id1, int id2); // execute forward cell executeForwards(int id, cell *params); diff --git a/amxmodx/CMenu.cpp b/amxmodx/CMenu.cpp index b2a3bafc..c372fcc1 100755 --- a/amxmodx/CMenu.cpp +++ b/amxmodx/CMenu.cpp @@ -35,14 +35,15 @@ // ***************************************************** // class MenuMngr // ***************************************************** -MenuMngr::MenuCommand::MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, int n) +MenuMngr::MenuCommand::MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, bool new_menu) { plugin = a; keys = k; menuid = mi; - function = f; next = 0; - newmenu = n; + is_new_menu = new_menu; + + function = f; } MenuMngr::~MenuMngr() @@ -62,112 +63,47 @@ int MenuMngr::findMenuId(const char* name, AMX* amx) return 0; } -void MenuMngr::removeMenuId(int id) -{ - MenuIdEle *n = headid; - MenuIdEle *l = NULL; - while (n) - { - if (n->id == id) - { - if (l) - l->next = n->next; - else - headid = n->next; - delete n; - break; - } - l = n; - n = n->next; - } - - MenuCommand *c = headcmd; - MenuCommand *lc = NULL; - MenuCommand *tmp; - while (c) - { - if (c->menuid == id) - { - if (m_watch_iter.a == c) - { - ++m_watch_iter; - } - if (lc) - lc->next = c->next; - else - headcmd = c->next; - tmp = c->next; - delete c; - c = tmp; - } else { - lc = c; - c = c->next; - } - } -} - -void MenuMngr::removeMenuCmds(int newMenu) -{ - MenuCommand *c = headcmd; - MenuCommand *lc = NULL; - MenuCommand *tmp; - while (c) - { - if (c->newmenu == newMenu) - { - if (m_watch_iter.a == c) - { - ++m_watch_iter; - } - if (lc) - lc->next = c->next; - else - headcmd = c->next; - tmp = c->next; - delete c; - c = tmp; - } else { - lc = c; - c = c->next; - } - } -} - int MenuMngr::registerMenuId(const char* n, AMX* a) { int id = findMenuId(n, a); if (id) + { return id; + } headid = new MenuIdEle(n, a, headid); - if (!headid) - return 0; // :TODO: Better error report - return headid->id; } -void MenuMngr::registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, int n) +void MenuMngr::registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, bool from_new_menu) { MenuCommand **temp = &headcmd; - MenuCommand *ptr; - while (*temp) + if (from_new_menu) { - ptr = *temp; - if (n > -1 - && ptr->plugin == a - && ptr->menuid == mi - && ptr->keys == k) + MenuCommand *ptr; + while (*temp) { - if (strcmp(g_forwards.getFuncName(ptr->function), g_forwards.getFuncName(f)) == 0) + ptr = *temp; + if (ptr->is_new_menu + && ptr->plugin == a + && ptr->menuid == mi) { - return; + if (g_forwards.isSameSPForward(ptr->function, f)) + { + return; + } } + temp = &(*temp)->next; + } + } else { + while (*temp) + { + temp = &(*temp)->next; } - temp = &(*temp)->next; } - *temp = new MenuCommand(a, mi, k, f, n); + *temp = new MenuCommand(a, mi, k, f, from_new_menu); } void MenuMngr::clear() diff --git a/amxmodx/CMenu.h b/amxmodx/CMenu.h index f4c8242c..860e55a5 100755 --- a/amxmodx/CMenu.h +++ b/amxmodx/CMenu.h @@ -66,14 +66,17 @@ private: int menuid; int keys; int function; + int is_new_menu; MenuCommand* next; - MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, int n=-1); + MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, bool new_menu=false); public: inline int getFunction() { return function; } inline CPluginMngr::CPlugin* getPlugin() { return plugin; } - inline bool matchCommand(int m, int k) { return ((m == menuid) && (keys & k)); } - int newmenu; + inline bool matchCommand(int m, int k) + { + return ((m == menuid) && (keys & k)); + } } *headcmd; public: @@ -85,9 +88,7 @@ public: int findMenuId(const char* name, AMX* a = 0); int registerMenuId(const char* n, AMX* a); - void removeMenuId(int id); - void removeMenuCmds(int newMenu); - void registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, int n=-1); + void registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, bool from_new_menu=false); void clear(); class iterator @@ -112,4 +113,6 @@ private: MenuMngr::iterator m_watch_iter; }; +extern MenuMngr g_menucmds; + #endif //MENUS_H diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 726a0f0a..cf6bedc1 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -31,6 +31,7 @@ #include #include "amxmodx.h" +#include "CMenu.h" #include "natives.h" #include "debugger.h" #include "binlog.h" diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 4256d258..6d6053cf 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -65,7 +65,6 @@ #include "CLogEvent.h" #include "CForward.h" #include "CCmd.h" -#include "CMenu.h" #include "CEvent.h" #include "CLang.h" #include "fakemeta.h" @@ -183,7 +182,6 @@ extern CList g_auth; extern EventsMngr g_events; extern Grenades g_grenades; extern LogEventsMngr g_logevents; -extern MenuMngr g_menucmds; extern CLangMngr g_langMngr; extern String g_log_dir; extern String g_mod_name; diff --git a/amxmodx/emsg.cpp b/amxmodx/emsg.cpp index 37de1b0f..3f59304d 100755 --- a/amxmodx/emsg.cpp +++ b/amxmodx/emsg.cpp @@ -30,6 +30,7 @@ */ #include "amxmodx.h" +#include "CMenu.h" int gmsgAmmoPickup; int gmsgAmmoX; diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index fc5f5c6b..3502bb37 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -39,6 +39,7 @@ #include "amxmodx.h" #include "fakemeta.h" +#include "CMenu.h" #include "newmenus.h" #include "natives.h" #include "binlog.h" @@ -965,6 +966,7 @@ void C_ClientCommand(edict_t *pEntity) pPlayer->menu = 0; /* First, do new menus */ + int func_was_executed = -1; if (pPlayer->newmenu != -1) { int menu = pPlayer->newmenu; @@ -988,6 +990,11 @@ void C_ClientCommand(edict_t *pEntity) RETURN_META(MRES_SUPERCEDE); } } + /** + * No matter what we marked it as executed, since the callback styles are + * entirely different. After all, this is a backwards compat shim. + */ + func_was_executed = pMenu->func; } } @@ -997,7 +1004,11 @@ void C_ClientCommand(edict_t *pEntity) while (a) { g_menucmds.SetWatchIter(a); - if ((*a).matchCommand(menuid, bit_key) && (*a).getPlugin()->isExecutable((*a).getFunction())) + if ((*a).matchCommand(menuid, bit_key) + && (*a).getPlugin()->isExecutable((*a).getFunction()) + && (func_was_executed == -1 + || !g_forwards.isSameSPForward(func_was_executed, (*a).getFunction())) + ) { ret = executeForwards((*a).getFunction(), static_cast(pPlayer->index), static_cast(pressed_key), 0); diff --git a/amxmodx/newmenus.cpp b/amxmodx/newmenus.cpp index 9fd18f45..ae205b7c 100755 --- a/amxmodx/newmenus.cpp +++ b/amxmodx/newmenus.cpp @@ -29,6 +29,7 @@ */ #include "amxmodx.h" +#include "CMenu.h" #include "newmenus.h" CVector g_NewMenus; @@ -48,28 +49,6 @@ void ClearMenus() } } -void RemoveMenuIdIfOkay(Menu *pMenu, int menuid) -{ - /* :TODO: Move this to some sort of referencing counting thingy */ - bool removeMenuId = true; - for (size_t i = 0; i < g_NewMenus.size(); i++) - { - if (!g_NewMenus[i] || g_NewMenus[i]->isDestroying) - { - continue; - } - if (g_NewMenus[i]->menuId == menuid) - { - removeMenuId = false; - break; - } - } - if (removeMenuId) - { - g_menucmds.removeMenuId(menuid); - } -} - void validate_menu_text(char *str) { if (!g_coloredmenus) @@ -102,23 +81,31 @@ void validate_menu_text(char *str) } } -Menu::Menu(const char *title, int mid, int tid) +Menu::Menu(const char *title, AMX *amx, int fid) : m_Title(title), m_ItemColor("\\r"), +m_NeverExit(false), m_AutoColors(g_coloredmenus), thisId(0), func(fid), +isDestroying(false), items_per_page(7) { - m_Title.assign(title); - menuId = mid; - thisId = tid; + CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx); + menuId = g_menucmds.registerMenuId(title, amx); + + if (strcmp(pPlugin->getName(), "war3ft.amxx") == 0) + { + const char *version = pPlugin->getVersion(); + if (strncmp(pPlugin->getVersion(), "3.0 RC", 6) == 0 + && atoi(&version[6]) <= 8) + { + g_menucmds.registerMenuCmd( + g_plugins.findPluginFast(amx), + menuId, + -1, + g_forwards.duplicateSPForward(fid), + true); + } + } m_OptNames[abs(MENU_BACK)].assign("Back"); m_OptNames[abs(MENU_MORE)].assign("More"); m_OptNames[abs(MENU_EXIT)].assign("Exit"); - - m_ItemColor.assign("\\r"); - m_NeverExit = false; - m_AutoColors = g_coloredmenus; - - items_per_page = 7; - func = 0; - isDestroying = false; } Menu::~Menu() @@ -605,11 +592,7 @@ static cell AMX_NATIVE_CALL menu_create(AMX *amx, cell *params) return 0; } - int id = g_menucmds.registerMenuId(title, amx); - - Menu *pMenu = new Menu(title, id, 0); - - pMenu->func = func; + Menu *pMenu = new Menu(title, amx, func); if (g_MenuFreeStack.empty()) { @@ -727,7 +710,7 @@ static cell AMX_NATIVE_CALL menu_display(AMX *amx, cell *params) /* Infinite loop counter */ if (++loops >= 10) { - LogError(amx, AMX_ERR_NATIVE, "Recursion bug detected in menu handler"); + LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT"); return 0; } } @@ -902,22 +885,7 @@ static cell AMX_NATIVE_CALL menu_setprop(AMX *amx, cell *params) case MPROP_TITLE: { char *str = get_amxstring(amx, params[3], 0, len); - int old = pMenu->menuId; - RemoveMenuIdIfOkay(pMenu, old); pMenu->m_Title.assign(str); - pMenu->menuId = g_menucmds.registerMenuId(str, amx); - CPlayer *pl; - /** - * NOTE - this is actually bogus - * the client's screen won't actually match the cmd here - * I think, this scenario needs to be tested. - */ - for (int i=1; i<=gpGlobals->maxClients; i++) - { - pl = GET_PLAYER_POINTER_I(i); - if (pl->menu == old) - pl->menu = pMenu->menuId; - } break; } case MPROP_EXITALL: @@ -1005,8 +973,6 @@ static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params) pMenu->isDestroying = true; - RemoveMenuIdIfOkay(pMenu, pMenu->menuId); - CPlayer *player; for (int i=1; i<=gpGlobals->maxClients; i++) { diff --git a/amxmodx/newmenus.h b/amxmodx/newmenus.h index 858cdd1a..6cc56e06 100755 --- a/amxmodx/newmenus.h +++ b/amxmodx/newmenus.h @@ -75,7 +75,7 @@ typedef unsigned int page_t; class Menu { public: - Menu(const char *title, int menuId, int thisId); + Menu(const char *title, AMX *amx, int fid); ~Menu(); menuitem *GetMenuItem(item_t item); diff --git a/plugins/include/newmenus.inc b/plugins/include/newmenus.inc index 9470e0cd..9ad9164f 100644 --- a/plugins/include/newmenus.inc +++ b/plugins/include/newmenus.inc @@ -192,7 +192,10 @@ native menu_destroy(menu); /** * Returns information about a menu (if any) the client is currently viewing. * - * Either menu or newmenu can return a valid menu, but never both. + * If newmenu is valid, then the menu will refer to the menuid associated with + * the title. If newmenu is not valid, and the menu is valid, then the player + * is viewing a menu displayed with show_menu(). + * * Both may be invalid if the player is not viewing a menu. * * @param id Client index. @@ -201,7 +204,6 @@ native menu_destroy(menu); * @param newmenu Variable to store new menu id. If none, then -1 will be * stored. * @param menupage Variable to store current page of the new menu, if any. - * * @return 1 if the player is viewing a menu, 0 otherwise. * @error Invalid client. */