Implement per-client randomized menus with MenuShufflePerClient native.
Add MenuSetClientMapping native.
This commit is contained in:
		
							parent
							
								
									7ed4e88915
								
							
						
					
					
						commit
						2c8071995d
					
				| @ -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)) | ||||
|  | ||||
| @ -633,7 +633,7 @@ bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	CItem item; | ||||
| 	CItem item(m_items.length()); | ||||
| 
 | ||||
| 	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.length()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	CItem item; | ||||
| 	CItem item(position); | ||||
| 	item.info = info; | ||||
| 	if (draw.display) | ||||
| 		item.display = new ke::AString(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.length()) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (client > 0 && position < m_RandomMaps[client].length()) | ||||
| 	{ | ||||
| 		position = m_RandomMaps[client][position]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (draw) | ||||
| 	{ | ||||
| 		draw->display = m_items[position].display->chars(); | ||||
| @ -693,6 +698,62 @@ const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* = | ||||
| 	return m_items[position].info.chars(); | ||||
| } | ||||
| 
 | ||||
| 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 + 1; 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 + 1; i++) | ||||
| 	{ | ||||
| 		if(m_RandomMaps[i].length() > 0) | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position) | ||||
| { | ||||
| 	if (client > 0 && position < m_RandomMaps[client].length()) | ||||
| 	{ | ||||
| 		position = m_RandomMaps[client][position]; | ||||
| 		return m_items[position].index; | ||||
| 	} | ||||
| 
 | ||||
| 	return position; | ||||
| } | ||||
| 
 | ||||
| unsigned int CBaseMenu::GetItemCount() | ||||
| { | ||||
| 	return m_items.length(); | ||||
|  | ||||
| @ -44,8 +44,9 @@ using namespace SourceMod; | ||||
| class CItem | ||||
| { | ||||
| public: | ||||
| 	CItem() | ||||
| 	CItem(unsigned int index) | ||||
| 	{ | ||||
| 		this->index = index; | ||||
| 		style = 0; | ||||
| 		access = 0; | ||||
| 	} | ||||
| @ -53,11 +54,13 @@ public: | ||||
| 	: info(ke::Move(other.info)), | ||||
| 	  display(ke::Move(other.display)) | ||||
| 	{ | ||||
| 		index = other.index; | ||||
| 		style = other.style; | ||||
| 		access = other.access; | ||||
| 	} | ||||
| 	CItem & operator =(CItem &&other) | ||||
| 	{ | ||||
| 		index = other.index; | ||||
| 		info = ke::Move(other.info); | ||||
| 		display = ke::Move(other.display); | ||||
| 		style = other.style; | ||||
| @ -66,6 +69,7 @@ public: | ||||
| 	} | ||||
| 
 | ||||
| public: | ||||
| 	unsigned int index; | ||||
| 	ke::AString info; | ||||
| 	ke::AutoPtr<ke::AString> display; | ||||
| 	unsigned int style; | ||||
| @ -138,7 +142,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(); | ||||
| @ -152,6 +156,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(); | ||||
| @ -168,6 +176,7 @@ protected: | ||||
| 	Handle_t m_hHandle; | ||||
| 	IMenuHandler *m_pHandler; | ||||
| 	unsigned int m_nFlags; | ||||
| 	ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1]; | ||||
| }; | ||||
| 
 | ||||
| #endif //_INCLUDE_MENUSTYLE_BASE_H
 | ||||
|  | ||||
| @ -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}, | ||||
|  | ||||
| @ -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.
 | ||||
| 	//
 | ||||
| @ -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. | ||||
|  */ | ||||
| @ -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. | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
| #include <IHandleSys.h> | ||||
| 
 | ||||
| #define SMINTERFACE_MENUMANAGER_NAME		"IMenuManager" | ||||
| #define SMINTERFACE_MENUMANAGER_VERSION		16 | ||||
| #define SMINTERFACE_MENUMANAGER_VERSION		17 | ||||
| 
 | ||||
| /**
 | ||||
|  * @file IMenuManager.h | ||||
| @ -485,9 +485,10 @@ namespace SourceMod | ||||
| 		 * | ||||
| 		 * @param position		Position, starting from 0. | ||||
| 		 * @param draw			Optional pointer to store a draw information. | ||||
| 		 * @param client		Client index. (Important for randomized menus.) | ||||
| 		 * @return				Info string pointer, or NULL if position was invalid. | ||||
| 		 */ | ||||
| 		virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw) =0; | ||||
| 		virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw, int client=0) =0; | ||||
| 
 | ||||
| 		/**
 | ||||
| 		 * @brief Returns the number of items. | ||||
| @ -636,6 +637,35 @@ namespace SourceMod | ||||
| 		 * @return				Approximate number of bytes being used. | ||||
| 		 */ | ||||
| 		virtual unsigned int GetApproxMemUsage() =0; | ||||
| 
 | ||||
| 		/**
 | ||||
| 		 * @brief 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 | ||||
| 		 */ | ||||
| 		virtual void ShufflePerClient(int start=0, int stop=-1) =0; | ||||
| 
 | ||||
| 		/**
 | ||||
| 		 * @brief 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. | ||||
| 		 */ | ||||
| 		virtual void SetClientMapping(int client, int *array, int length) =0; | ||||
| 
 | ||||
| 		/**
 | ||||
| 		 * @brief Returns true if the menu has a per-client random mapping. | ||||
| 		 * @return				True on success, false otherwise. | ||||
| 		 */ | ||||
| 		virtual bool IsPerClientShuffled() =0; | ||||
| 
 | ||||
| 		/**
 | ||||
| 		 * @brief Returns the actual (not shuffled) item index from the client position. | ||||
| 		 * @param client		Client index. | ||||
| 		 * @param position		Position, starting from 0. | ||||
| 		 * @return				Actual item index in menu. | ||||
| 		 */ | ||||
| 		virtual unsigned int GetRealItemIndex(int client, unsigned int position) =0; | ||||
| 	}; | ||||
| 
 | ||||
| 	/** 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user