fixed amb18 and various associated menu re-entrancy bugs

This commit is contained in:
David Anderson 2007-04-16 18:00:54 +00:00
parent b90bc3a3e4
commit 1ec4d9cc7d
5 changed files with 93 additions and 10 deletions

View File

@ -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()

View File

@ -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

View File

@ -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;

View File

@ -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++)
{

View File

@ -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
}