Skip to content

Commit

Permalink
menusys: add MenuShufflePerClient native (#1073)
Browse files Browse the repository at this point in the history
* 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 <kyle.leet@gmail.com>
  • Loading branch information
BotoX and KyleSanderson committed Aug 7, 2020
1 parent 7bab9cc commit 6f21138
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 16 deletions.
6 changes: 3 additions & 3 deletions core/MenuManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand Down
67 changes: 64 additions & 3 deletions core/MenuStyle_Base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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();
Expand All @@ -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();
Expand Down
13 changes: 11 additions & 2 deletions core/MenuStyle_Base.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,23 @@ using namespace SourceMod;
class CItem
{
public:
CItem()
CItem(unsigned int index)
{
this->index = index;
style = 0;
access = 0;
}
CItem(CItem &&other)
: 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;
Expand All @@ -68,6 +71,7 @@ class CItem
}

public:
unsigned int index;
std::string info;
std::unique_ptr<std::string> display;
unsigned int style;
Expand Down Expand Up @@ -140,7 +144,7 @@ class CBaseMenu : public IBaseMenu
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();
Expand All @@ -154,6 +158,10 @@ class CBaseMenu : public IBaseMenu
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();
Expand All @@ -170,6 +178,7 @@ class CBaseMenu : public IBaseMenu
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
7 changes: 4 additions & 3 deletions core/MenuVoting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand Down
63 changes: 62 additions & 1 deletion core/logic/smn_menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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];
Expand Down Expand Up @@ -1645,6 +1702,8 @@ REGISTER_NATIVES(menuNatives)
{"SetPanelKeys", SetPanelKeys},
{"SetVoteResultCallback", SetVoteResultCallback},
{"VoteMenu", VoteMenu},
{"MenuShufflePerClient", MenuShufflePerClient},
{"MenuSetClientMapping", MenuSetClientMapping},
{"SetMenuNoVoteButton", SetMenuNoVoteButton},

// Transitional syntax support.
Expand Down Expand Up @@ -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},
Expand Down
39 changes: 37 additions & 2 deletions plugins/include/menus.inc
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,23 @@ methodmap Menu < Handle
// @param style By-reference variable to store drawing flags.
// @param dispBuf Display buffer.
// @param dispBufLen Maximum length of the display buffer.
// @param client Client index. Must be specified if menu is per-client random shuffled, -1 to ignore.
// @return True on success, false if position is invalid.
public native bool GetItem(int position, char[] infoBuf, int infoBufLen,
int &style=0, char[] dispBuf="", int dispBufLen=0);
int &style=0, char[] dispBuf="", int dispBufLen=0, int client=0);

// Generates a per-client random mapping for the current vote options.
//
// @param start Menu item index to start randomizing from.
// @param stop Menu item index to stop randomizing at. -1 = infinite
public native void ShufflePerClient(int start=0, int stop=-1);

// Fills the client vote option mapping with user supplied values.
//
// @param client Client index.
// @param array Integer array with mapping.
// @param length Length of array.
public native void SetClientMapping(int client, int[] array, int length);

// Sets the menu's default title/instruction message.
//
Expand Down Expand Up @@ -537,6 +551,7 @@ native void RemoveAllMenuItems(Handle menu);
* @param style By-reference variable to store drawing flags.
* @param dispBuf Display buffer.
* @param dispBufLen Maximum length of the display buffer.
* @param client Client index. Must be specified if menu is per-client random shuffled, -1 to ignore.
* @return True on success, false if position is invalid.
* @error Invalid Handle.
*/
Expand All @@ -546,7 +561,27 @@ native bool GetMenuItem(Handle menu,
int infoBufLen,
int &style=0,
char[] dispBuf="",
int dispBufLen=0);
int dispBufLen=0,
int client=0);

/**
* Generates a per-client random mapping for the current vote options.
*
* @param menu Menu Handle.
* @param start Menu item index to start randomizing from.
* @param stop Menu item index to stop randomizing at. -1 = infinite
*/
native void MenuShufflePerClient(Handle menu, int start=0, int stop=-1);

/*
* Fills the client vote option mapping with user supplied values.
*
* @param menu Menu Handle.
* @param client Client index.
* @param array Integer array with mapping.
* @param length Length of array.
*/
native void MenuSetClientMapping(Handle menu, int client, int[] array, int length);

/**
* Returns the first item on the page of a currently selected menu.
Expand Down
Loading

0 comments on commit 6f21138

Please sign in to comment.