fixed amb18 and various associated menu re-entrancy bugs
This commit is contained in:
parent
b90bc3a3e4
commit
1ec4d9cc7d
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user