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:
parent
528fec1a29
commit
387dc6a188
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user