fixed amb18 and various associated menu re-entrancy bugs
This commit is contained in:
parent
b90bc3a3e4
commit
1ec4d9cc7d
|
@ -35,13 +35,14 @@
|
|||
// *****************************************************
|
||||
// class MenuMngr
|
||||
// *****************************************************
|
||||
MenuMngr::MenuCommand::MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f)
|
||||
MenuMngr::MenuCommand::MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, int n)
|
||||
{
|
||||
plugin = a;
|
||||
keys = k;
|
||||
menuid = mi;
|
||||
function = f;
|
||||
next = 0;
|
||||
newmenu = n;
|
||||
}
|
||||
|
||||
MenuMngr::~MenuMngr()
|
||||
|
@ -105,6 +106,33 @@ void MenuMngr::removeMenuId(int id)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -120,11 +148,11 @@ int MenuMngr::registerMenuId(const char* n, AMX* a)
|
|||
return headid->id;
|
||||
}
|
||||
|
||||
void MenuMngr::registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f)
|
||||
void MenuMngr::registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, int n)
|
||||
{
|
||||
MenuCommand** temp = &headcmd;
|
||||
while (*temp) temp = &(*temp)->next;
|
||||
*temp = new MenuCommand(a, mi, k, f);
|
||||
*temp = new MenuCommand(a, mi, k, f, n);
|
||||
}
|
||||
|
||||
void MenuMngr::clear()
|
||||
|
|
|
@ -68,11 +68,12 @@ private:
|
|||
int function;
|
||||
|
||||
MenuCommand* next;
|
||||
MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f);
|
||||
MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, int n=-1);
|
||||
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;
|
||||
} *headcmd;
|
||||
|
||||
public:
|
||||
|
@ -85,7 +86,8 @@ public:
|
|||
int findMenuId(const char* name, AMX* a = 0);
|
||||
int registerMenuId(const char* n, AMX* a);
|
||||
void removeMenuId(int id);
|
||||
void registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f);
|
||||
void removeMenuCmds(int newMenu);
|
||||
void registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, int n=-1);
|
||||
void clear();
|
||||
|
||||
class iterator
|
||||
|
|
|
@ -948,7 +948,7 @@ void C_ClientCommand(edict_t *pEntity)
|
|||
g_menucmds.SetWatchIter(a);
|
||||
if ((*a).matchCommand(menuid, bit_key) && (*a).getPlugin()->isExecutable((*a).getFunction()))
|
||||
{
|
||||
if (pPlayer->newmenu != -1)
|
||||
if (pPlayer->newmenu != -1 && pPlayer->newmenu == (*a).newmenu)
|
||||
{
|
||||
int menu = pPlayer->newmenu;
|
||||
pPlayer->newmenu = -1;
|
||||
|
|
|
@ -525,7 +525,6 @@ static cell AMX_NATIVE_CALL menu_create(AMX *amx, cell *params)
|
|||
}
|
||||
|
||||
int id = g_menucmds.registerMenuId(title, amx);
|
||||
g_menucmds.registerMenuCmd(g_plugins.findPluginFast(amx), id, 1023, func);
|
||||
|
||||
Menu *pMenu = new Menu(title, id, 0);
|
||||
|
||||
|
@ -535,14 +534,16 @@ static cell AMX_NATIVE_CALL menu_create(AMX *amx, cell *params)
|
|||
{
|
||||
g_NewMenus.push_back(pMenu);
|
||||
pMenu->thisId = (int)g_NewMenus.size() - 1;
|
||||
return (int)g_NewMenus.size() - 1;
|
||||
} else {
|
||||
int pos = g_MenuFreeStack.front();
|
||||
g_MenuFreeStack.pop();
|
||||
g_NewMenus[pos] = pMenu;
|
||||
pMenu->thisId = pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
g_menucmds.registerMenuCmd(g_plugins.findPluginFast(amx), id, 1023, func, pMenu->thisId);
|
||||
|
||||
return pMenu->thisId;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL menu_addblank(AMX *amx, cell *params)
|
||||
|
@ -622,6 +623,36 @@ static cell AMX_NATIVE_CALL menu_display(AMX *amx, cell *params)
|
|||
int page = params[3];
|
||||
CPlayer* pPlayer = GET_PLAYER_POINTER_I(player);
|
||||
|
||||
/* If the stupid handler keeps drawing menus,
|
||||
* We need to keep cancelling them. But we put in a quick infinite loop
|
||||
* counter to prevent this from going nuts.
|
||||
*/
|
||||
int menu;
|
||||
int loops = 0;
|
||||
while ((menu = pPlayer->newmenu) >= 0)
|
||||
{
|
||||
if ((size_t)menu >= g_NewMenus.size() || !g_NewMenus[menu])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Menu *pOther = g_NewMenus[menu];
|
||||
|
||||
pPlayer->newmenu = -1;
|
||||
pPlayer->menu = 0;
|
||||
executeForwards(pOther->func,
|
||||
static_cast<cell>(player),
|
||||
static_cast<cell>(pOther->thisId),
|
||||
static_cast<cell>(MENU_EXIT));
|
||||
|
||||
/* Infinite loop counter */
|
||||
if (++loops >= 10)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Recursion bug detected in menu handler");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This will set the expire time of the menu to infinite
|
||||
pPlayer->menuexpire = INFINITE;
|
||||
|
||||
|
@ -892,7 +923,27 @@ static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params)
|
|||
}
|
||||
|
||||
pMenu->isDestroying = true;
|
||||
g_menucmds.removeMenuId(pMenu->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 == pMenu->menuId)
|
||||
{
|
||||
removeMenuId = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removeMenuId)
|
||||
{
|
||||
g_menucmds.removeMenuId(pMenu->menuId);
|
||||
}
|
||||
g_menucmds.removeMenuCmds(pMenu->thisId);
|
||||
|
||||
CPlayer *player;
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
|
|
|
@ -55,6 +55,8 @@ public Test_Menu1_Handler(id, menu, item)
|
|||
|
||||
client_print(id, print_chat, "Menu resolved to: %s (%s)", name, cmd)
|
||||
|
||||
menu_destroy(menu)
|
||||
|
||||
return PLUGIN_HANDLED
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user