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 // 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; plugin = a;
keys = k; keys = k;
menuid = mi; menuid = mi;
function = f; function = f;
next = 0; next = 0;
newmenu = n;
} }
MenuMngr::~MenuMngr() 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 MenuMngr::registerMenuId(const char* n, AMX* a)
{ {
int id = findMenuId(n, a); int id = findMenuId(n, a);
@ -120,11 +148,11 @@ int MenuMngr::registerMenuId(const char* n, AMX* a)
return headid->id; 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; MenuCommand** temp = &headcmd;
while (*temp) temp = &(*temp)->next; while (*temp) temp = &(*temp)->next;
*temp = new MenuCommand(a, mi, k, f); *temp = new MenuCommand(a, mi, k, f, n);
} }
void MenuMngr::clear() void MenuMngr::clear()

View File

@ -68,11 +68,12 @@ private:
int function; int function;
MenuCommand* next; 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: public:
inline int getFunction() { return function; } inline int getFunction() { return function; }
inline CPluginMngr::CPlugin* getPlugin() { return plugin; } inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
inline bool matchCommand(int m, int k) { return ((m == menuid) && (keys & k)); } inline bool matchCommand(int m, int k) { return ((m == menuid) && (keys & k)); }
int newmenu;
} *headcmd; } *headcmd;
public: public:
@ -85,7 +86,8 @@ public:
int findMenuId(const char* name, AMX* a = 0); int findMenuId(const char* name, AMX* a = 0);
int registerMenuId(const char* n, AMX* a); int registerMenuId(const char* n, AMX* a);
void removeMenuId(int id); 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(); void clear();
class iterator class iterator

View File

@ -948,7 +948,7 @@ void C_ClientCommand(edict_t *pEntity)
g_menucmds.SetWatchIter(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()))
{ {
if (pPlayer->newmenu != -1) if (pPlayer->newmenu != -1 && pPlayer->newmenu == (*a).newmenu)
{ {
int menu = pPlayer->newmenu; int menu = pPlayer->newmenu;
pPlayer->newmenu = -1; 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); int id = g_menucmds.registerMenuId(title, amx);
g_menucmds.registerMenuCmd(g_plugins.findPluginFast(amx), id, 1023, func);
Menu *pMenu = new Menu(title, id, 0); 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); g_NewMenus.push_back(pMenu);
pMenu->thisId = (int)g_NewMenus.size() - 1; pMenu->thisId = (int)g_NewMenus.size() - 1;
return (int)g_NewMenus.size() - 1;
} else { } else {
int pos = g_MenuFreeStack.front(); int pos = g_MenuFreeStack.front();
g_MenuFreeStack.pop(); g_MenuFreeStack.pop();
g_NewMenus[pos] = pMenu; g_NewMenus[pos] = pMenu;
pMenu->thisId = pos; 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) 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]; int page = params[3];
CPlayer* pPlayer = GET_PLAYER_POINTER_I(player); 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 // This will set the expire time of the menu to infinite
pPlayer->menuexpire = INFINITE; pPlayer->menuexpire = INFINITE;
@ -892,7 +923,27 @@ static cell AMX_NATIVE_CALL menu_destroy(AMX *amx, cell *params)
} }
pMenu->isDestroying = true; 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; CPlayer *player;
for (int i=1; i<=gpGlobals->maxClients; i++) 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) client_print(id, print_chat, "Menu resolved to: %s (%s)", name, cmd)
menu_destroy(menu)
return PLUGIN_HANDLED return PLUGIN_HANDLED
} }