menusys: add MenuShufflePerClient native (#1073)
* Implement per-client randomized menus with MenuShufflePerClient native. * Add MenuSetClientMapping native. * fix remaining issues * fix build issues from rebase * Update MenuStyle_Base.cpp Co-authored-by: Kyle Sanderson <[email protected]>
This commit is contained in:
@@ -308,7 +308,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
{
|
||||
ItemDrawInfo &dr = drawItems[foundItems].draw;
|
||||
/* Is the item valid? */
|
||||
if (menu->GetItemInfo(i, &dr) != NULL)
|
||||
if (menu->GetItemInfo(i, &dr, client) != NULL)
|
||||
{
|
||||
/* Ask the user to change the style, if necessary */
|
||||
mh->OnMenuDrawItem(menu, client, i, dr.style);
|
||||
@@ -398,7 +398,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
}
|
||||
while (++lastItem < totalItems)
|
||||
{
|
||||
if (menu->GetItemInfo(lastItem, &dr) != NULL)
|
||||
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
|
||||
{
|
||||
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
|
||||
if (IsSlotItem(panel, dr.style))
|
||||
@@ -420,7 +420,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
lastItem--;
|
||||
while (lastItem != 0)
|
||||
{
|
||||
if (menu->GetItemInfo(lastItem, &dr) != NULL)
|
||||
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
|
||||
{
|
||||
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
|
||||
if (IsSlotItem(panel, dr.style))
|
||||
|
||||
+64
-3
@@ -633,7 +633,7 @@ bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||
return false;
|
||||
}
|
||||
|
||||
CItem item;
|
||||
CItem item(m_items.size());
|
||||
|
||||
item.info = info;
|
||||
if (draw.display)
|
||||
@@ -655,7 +655,7 @@ bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDr
|
||||
if (position >= m_items.size())
|
||||
return false;
|
||||
|
||||
CItem item;
|
||||
CItem item(position);
|
||||
item.info = info;
|
||||
if (draw.display)
|
||||
item.display = std::make_unique<std::string>(draw.display);
|
||||
@@ -679,11 +679,16 @@ void CBaseMenu::RemoveAllItems()
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
|
||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
||||
{
|
||||
if (position >= m_items.size())
|
||||
return NULL;
|
||||
|
||||
if (client > 0 && position < m_RandomMaps[client].size())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
}
|
||||
|
||||
if (draw)
|
||||
{
|
||||
draw->display = m_items[position].display->c_str();
|
||||
@@ -693,6 +698,62 @@ const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =
|
||||
return m_items[position].info.c_str();
|
||||
}
|
||||
|
||||
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||
{
|
||||
// limit map len to 255 items since it's using uint8
|
||||
int length = MIN(GetItemCount(), 255);
|
||||
if (stop >= 0)
|
||||
length = MIN(length, stop);
|
||||
|
||||
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
// populate per-client map ...
|
||||
m_RandomMaps[i].resize(length);
|
||||
for (int j = 0; j < length; j++)
|
||||
m_RandomMaps[i][j] = j;
|
||||
|
||||
// ... and random shuffle it
|
||||
for (int j = length - 1; j > start; j--)
|
||||
{
|
||||
int x = rand() % (j - start + 1) + start;
|
||||
uint8_t tmp = m_RandomMaps[i][x];
|
||||
m_RandomMaps[i][x] = m_RandomMaps[i][j];
|
||||
m_RandomMaps[i][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMenu::SetClientMapping(int client, int *array, int length)
|
||||
{
|
||||
length = MIN(length, 255);
|
||||
m_RandomMaps[client].resize(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
m_RandomMaps[client][i] = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool CBaseMenu::IsPerClientShuffled()
|
||||
{
|
||||
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
if(m_RandomMaps[i].size() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||
{
|
||||
if (client > 0 && position < m_RandomMaps[client].size())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
return m_items[position].index;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetItemCount()
|
||||
{
|
||||
return m_items.size();
|
||||
|
||||
+11
-2
@@ -46,8 +46,9 @@ using namespace SourceMod;
|
||||
class CItem
|
||||
{
|
||||
public:
|
||||
CItem()
|
||||
CItem(unsigned int index)
|
||||
{
|
||||
this->index = index;
|
||||
style = 0;
|
||||
access = 0;
|
||||
}
|
||||
@@ -55,11 +56,13 @@ public:
|
||||
: info(std::move(other.info)),
|
||||
display(std::move(other.display))
|
||||
{
|
||||
index = other.index;
|
||||
style = other.style;
|
||||
access = other.access;
|
||||
}
|
||||
CItem & operator =(CItem &&other)
|
||||
{
|
||||
index = other.index;
|
||||
info = std::move(other.info);
|
||||
display = std::move(other.display);
|
||||
style = other.style;
|
||||
@@ -68,6 +71,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int index;
|
||||
std::string info;
|
||||
std::unique_ptr<std::string> display;
|
||||
unsigned int style;
|
||||
@@ -140,7 +144,7 @@ public:
|
||||
virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw);
|
||||
virtual bool RemoveItem(unsigned int position);
|
||||
virtual void RemoveAllItems();
|
||||
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
|
||||
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL, int client=0);
|
||||
virtual unsigned int GetItemCount();
|
||||
virtual bool SetPagination(unsigned int itemsPerPage);
|
||||
virtual unsigned int GetPagination();
|
||||
@@ -154,6 +158,10 @@ public:
|
||||
virtual unsigned int GetMenuOptionFlags();
|
||||
virtual void SetMenuOptionFlags(unsigned int flags);
|
||||
virtual IMenuHandler *GetHandler();
|
||||
virtual void ShufflePerClient(int start, int stop);
|
||||
virtual void SetClientMapping(int client, int *array, int length);
|
||||
virtual bool IsPerClientShuffled();
|
||||
virtual unsigned int GetRealItemIndex(int client, unsigned int position);
|
||||
unsigned int GetBaseMemUsage();
|
||||
private:
|
||||
void InternalDelete();
|
||||
@@ -170,6 +178,7 @@ protected:
|
||||
Handle_t m_hHandle;
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_nFlags;
|
||||
std::vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
||||
|
||||
+4
-3
@@ -514,15 +514,16 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
|
||||
/* Check by our item count, NOT the vote array size */
|
||||
if (item < m_Items)
|
||||
{
|
||||
m_ClientVotes[client] = item;
|
||||
m_Votes[item]++;
|
||||
unsigned int index = menu->GetRealItemIndex(client, item);
|
||||
m_ClientVotes[client] = index;
|
||||
m_Votes[index]++;
|
||||
m_NumVotes++;
|
||||
|
||||
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
|
||||
{
|
||||
static char buffer[1024];
|
||||
ItemDrawInfo dr;
|
||||
menu->GetItemInfo(item, &dr);
|
||||
menu->GetItemInfo(item, &dr, client);
|
||||
|
||||
if (sm_vote_console.GetBool())
|
||||
{
|
||||
|
||||
@@ -816,8 +816,14 @@ static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
ItemDrawInfo dr;
|
||||
const char *info;
|
||||
cell_t client = (params[0] >= 8) ? params[8] : 0;
|
||||
if(!client && menu->IsPerClientShuffled())
|
||||
{
|
||||
return pContext->ThrowNativeError("This menu has been per-client random shuffled. "
|
||||
"You have to call GetMenuItem with a client index!");
|
||||
}
|
||||
|
||||
if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
|
||||
if ((info=menu->GetItemInfo(params[2], &dr, client)) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -832,6 +838,57 @@ static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t MenuShufflePerClient(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IBaseMenu *menu;
|
||||
|
||||
if ((err = ReadMenuHandle(params[1], &menu)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int start = params[2];
|
||||
int stop = params[3];
|
||||
|
||||
if (stop > 0 && !(stop >= start))
|
||||
{
|
||||
return pContext->ThrowNativeError("Stop must be -1 or >= start!");
|
||||
}
|
||||
|
||||
menu->ShufflePerClient(start, stop);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t MenuSetClientMapping(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IBaseMenu *menu;
|
||||
|
||||
if ((err = ReadMenuHandle(params[1], &menu)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
int client = params[2];
|
||||
if (client < 1 || client > SM_MAXPLAYERS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index!");
|
||||
}
|
||||
|
||||
cell_t *array;
|
||||
pContext->LocalToPhysAddr(params[3], &array);
|
||||
|
||||
int length = params[4];
|
||||
|
||||
menu->SetClientMapping(client, array, length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
@@ -1645,6 +1702,8 @@ REGISTER_NATIVES(menuNatives)
|
||||
{"SetPanelKeys", SetPanelKeys},
|
||||
{"SetVoteResultCallback", SetVoteResultCallback},
|
||||
{"VoteMenu", VoteMenu},
|
||||
{"MenuShufflePerClient", MenuShufflePerClient},
|
||||
{"MenuSetClientMapping", MenuSetClientMapping},
|
||||
{"SetMenuNoVoteButton", SetMenuNoVoteButton},
|
||||
|
||||
// Transitional syntax support.
|
||||
@@ -1673,6 +1732,8 @@ REGISTER_NATIVES(menuNatives)
|
||||
{"Menu.ToPanel", CreatePanelFromMenu},
|
||||
{"Menu.Cancel", CancelMenu},
|
||||
{"Menu.DisplayVote", VoteMenu},
|
||||
{"Menu.ShufflePerClient", MenuShufflePerClient},
|
||||
{"Menu.SetClientMapping", MenuSetClientMapping},
|
||||
{"Menu.Pagination.get", GetMenuPagination},
|
||||
{"Menu.Pagination.set", SetMenuPagination},
|
||||
{"Menu.OptionFlags.get", GetMenuOptionFlags},
|
||||
|
||||
Reference in New Issue
Block a user