Fix a menu recursion issue (#471)

* Factorize menu close logic in show_menu()

* Use CS-specific player's m_iMenu offset instead of menuselect command
This commit is contained in:
Vincent Herbet 2018-07-10 12:09:20 +02:00 committed by GitHub
parent 528fec1a29
commit 387dc6a188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 37 deletions

View File

@ -166,6 +166,19 @@ class CGameConfigManager : public IGameConfigManager
StringHashMap<ITextListener_SMC*> m_customHandlers; StringHashMap<ITextListener_SMC*> m_customHandlers;
}; };
#define GET_OFFSET(classname, member) \
static int member = -1; \
if (member == -1) \
{ \
TypeDescription type; \
if (!CommonConfig->GetOffsetByClass(classname, #member, &type) || type.fieldOffset < 0)\
{ \
LogError(amx, AMX_ERR_NATIVE, "Invalid %s offset. Native %s is disabled", #member, __FUNCTION__);\
return 0; \
} \
member = type.fieldOffset; \
}
extern CGameConfigManager ConfigManager; extern CGameConfigManager ConfigManager;
extern IGameConfig *CommonConfig; extern IGameConfig *CommonConfig;

View File

@ -1246,20 +1246,15 @@ static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params) /* 3 param */
static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */
{ {
// If show_menu is called from within a newmenu callback upon receiving MENU_EXIT auto closeMenu = [amx](int index) -> int
// it is possible for this native to recurse. We need to close newmenus right away
// because the recursive call would otherwise modify/corrupt the static get_amxstring
// buffer mid execution. This will either display incorrect text or result in UTIL_ShowMenu
// running into an infinite loop.
int index = params[1];
if (index == 0)
{ {
for (int i = 1; i <= gpGlobals->maxClients; ++i) auto pPlayer = GET_PLAYER_POINTER_I(index);
{
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
if (pPlayer->ingame) if (!pPlayer->ingame)
{ {
return 1;
}
pPlayer->keys = 0; pPlayer->keys = 0;
pPlayer->menu = 0; pPlayer->menu = 0;
@ -1267,10 +1262,32 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */
if (!CloseNewMenus(pPlayer)) if (!CloseNewMenus(pPlayer))
{ {
LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT"); LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT");
return 0; return 2;
} }
UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0); if (g_bmod_cstrike)
{
GET_OFFSET("CBasePlayer", m_iMenu);
set_pdata<int>(pPlayer->pEdict, m_iMenu, 0);
}
return 0;
};
int index = params[1];
// If show_menu is called from within a newmenu callback upon receiving MENU_EXIT
// it is possible for this native to recurse. We need to close newmenus right away
// because the recursive call would otherwise modify/corrupt the static get_amxstring
// buffer mid execution. This will either display incorrect text or result in UTIL_ShowMenu
// running into an infinite loop.
if (index == 0)
{
for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
if (closeMenu(i) == 2)
{
return 0;
} }
} }
} }
@ -1282,23 +1299,7 @@ static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */
return 0; return 0;
} }
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); if (closeMenu(index))
if (pPlayer->ingame)
{
pPlayer->keys = 0;
pPlayer->menu = 0;
// Fire newmenu callback so closing it can be handled by the plugin
if (!CloseNewMenus(pPlayer))
{
LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT");
return 0;
}
UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0);
}
else
{ {
return 0; return 0;
} }

View File

@ -316,11 +316,6 @@ bool Menu::Display(int player, page_t page)
CPlayer *pPlayer = GET_PLAYER_POINTER_I(player); CPlayer *pPlayer = GET_PLAYER_POINTER_I(player);
pPlayer->keys = 0;
pPlayer->menu = 0;
UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0);
pPlayer->keys = keys; pPlayer->keys = keys;
pPlayer->menu = menuId; pPlayer->menu = menuId;
pPlayer->newmenu = thisId; pPlayer->newmenu = thisId;
@ -828,6 +823,12 @@ static cell AMX_NATIVE_CALL menu_display(AMX *amx, cell *params)
return 0; return 0;
} }
if (g_bmod_cstrike)
{
GET_OFFSET("CBasePlayer", m_iMenu);
set_pdata<int>(pPlayer->pEdict, m_iMenu, 0);
}
int time = -1; int time = -1;
if (params[0] / sizeof(cell) >= 4) if (params[0] / sizeof(cell) >= 4)
time = params[4]; time = params[4];