added experimental voting API

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40883
This commit is contained in:
David Anderson
2007-06-05 16:27:45 +00:00
parent 2884483bef
commit aea69f5fe8
9 changed files with 352 additions and 285 deletions
+186 -204
View File
@@ -12,9 +12,9 @@
* Version: $Id$
*/
#include <stdarg.h>
#include <time.h>
#include <stdarg.h>
#include <stdlib.h>
#include "MenuManager.h"
#include "sm_stringutil.h"
#include "sourcemm_api.h"
@@ -25,115 +25,188 @@
MenuManager g_Menus;
/*************************************
*************************************
**** BROADCAST HANDLING WRAPPERS ****
*************************************
*************************************/
/*******************************
*******************************
******** VOTE HANDLER *********
*******************************
*******************************/
BroadcastHandler::BroadcastHandler(IMenuHandler *handler) : m_pHandler(handler), numClients(0)
{
}
unsigned int BroadcastHandler::GetMenuAPIVersion2()
unsigned int VoteMenuHandler::GetMenuAPIVersion2()
{
return m_pHandler->GetMenuAPIVersion2();
}
void BroadcastHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
bool VoteMenuHandler::IsVoteInProgress()
{
return (m_pCurMenu != NULL);
}
void VoteMenuHandler::InitializeVoting(IBaseMenu *menu)
{
m_Items = menu->GetItemCount();
if (m_Votes.size() < (size_t)m_Items)
{
/* Only clear the items we need to... */
size_t size = m_Votes.size();
for (size_t i=0; i<size; i++)
{
m_Votes[i] = 0;
}
m_Votes.resize(m_Items, 0);
} else {
for (unsigned int i=0; i<m_Items; i++)
{
m_Votes[i] = 0;
}
}
m_pCurMenu = menu;
m_pHandler->OnMenuStart(m_pCurMenu);
}
void VoteMenuHandler::StartVoting()
{
m_bStarted = true;
m_pHandler->OnMenuVoteStart(m_pCurMenu);
/* By now we know how many clients were set.
* If there are none, we should end IMMEDIATELY.
*/
if (m_Clients == 0)
{
EndVoting();
}
}
void VoteMenuHandler::DecrementPlayerCount()
{
assert(m_Clients > 0);
m_Clients--;
if (m_bStarted && m_Clients == 0)
{
EndVoting();
}
}
void VoteMenuHandler::EndVoting()
{
unsigned int chosen = 0;
/* If we got zero votes, take a shortcut. */
if (m_NumVotes == 0)
{
/* Pick a random item and then jump far, far away. */
srand((unsigned int)(time(NULL)));
chosen = (unsigned int)rand() % static_cast<unsigned int>(m_Votes.size());
goto picked_item;
}
/* We can't have more dups than this!
* This is the max number of players.
*/
unsigned int dup_array[256];
unsigned int dup_count = 0;
size_t highest = 0;
for (size_t i=1; i<m_Votes.size(); i++)
{
if (m_Votes[i] > m_Votes[highest])
{
/* If we have a new highest count, mark it and trash the duplicate
* list by setting the total to 0.
*/
highest = i;
dup_count = 0;
} else if (m_Votes[i] == m_Votes[highest]) {
/* If they're equal, mark it in the duplicate list.
* We'll add in the original later.
*/
dup_array[dup_count++] = i;
}
}
/* Check if we need to pick from the duplicate list */
if (dup_count)
{
/* Re-add the original to the list because it's not in there. */
dup_array[dup_count++] = (unsigned int)highest;
/* Pick a random slot. */
srand((unsigned int)(time(NULL)));
unsigned int r = (unsigned int)rand() % dup_count;
/* Pick the item. */
chosen = dup_array[r];
} else {
chosen = (unsigned int)highest;
}
picked_item:
m_pHandler->OnMenuVoteEnd(m_pCurMenu, chosen);
m_pHandler->OnMenuEnd(m_pCurMenu);
InternalReset();
}
void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
{
m_Clients++;
}
void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu)
{
DecrementPlayerCount();
}
void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
{
m_pHandler->OnMenuCancel(menu, client, reason);
}
void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
{
numClients++;
m_pHandler->OnMenuDisplay(menu, client, display);
}
void BroadcastHandler::OnBroadcastEnd(IBaseMenu *menu)
void VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display)
{
g_Menus.FreeBroadcastHandler(this);
m_pHandler->OnMenuDisplayItem(menu, client, item, display);
}
void BroadcastHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
{
m_pHandler->OnMenuDrawItem(menu, client, item, style);
}
void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
{
/* Check by our item count, NOT the vote array size */
if (item < m_Items)
{
m_Votes[item]++;
m_NumVotes++;
}
m_pHandler->OnMenuSelect(menu, client, item);
}
void BroadcastHandler::OnMenuEnd(IBaseMenu *menu)
void VoteMenuHandler::Reset(IMenuHandler *mh)
{
assert(numClients > 0);
/* Only fire if all clients have gotten a menu end */
if (--numClients == 0)
{
IMenuHandler *pHandler = m_pHandler;
OnBroadcastEnd(menu);
pHandler->OnMenuEnd(menu);
}
m_pHandler = mh;
InternalReset();
}
VoteHandler::VoteHandler(IMenuVoteHandler *handler)
: BroadcastHandler(handler), m_pVoteHandler(handler)
void VoteMenuHandler::InternalReset()
{
}
void VoteHandler::Initialize(IBaseMenu *menu)
{
unsigned int numItems = menu->GetItemCount();
if (m_counts.size() >= numItems)
{
for (size_t i=0; i<numItems; i++)
{
m_counts[i] = 0;
}
} else {
for (size_t i=0; i<m_counts.size(); i++)
{
m_counts[i] = 0;
}
m_counts.resize(numItems, 0);
}
}
void VoteHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
{
if (item < numItems)
{
m_counts[item]++;
}
BroadcastHandler::OnMenuSelect(menu, client, item);
}
void VoteHandler::OnBroadcastEnd(IBaseMenu *menu)
{
m_ties.clear();
size_t highest = 0;
for (size_t i=1; i<numItems; i++)
{
if (m_counts[i] > m_counts[highest])
{
m_ties.clear();
highest = i;
} else if (m_counts[i] == m_counts[highest]) {
m_ties.push_back(i);
}
}
if (m_ties.size())
{
m_ties.push_back(highest);
srand(static_cast<unsigned int>(time(NULL)));
highest = m_ties[rand() % m_ties.size()];
}
m_pVoteHandler->OnMenuVoteEnd(menu, highest);
g_Menus.FreeVoteHandler(this);
m_Clients = 0;
m_Items = 0;
m_bStarted = false;
m_pCurMenu = NULL;
m_NumVotes = 0;
}
/*******************************
@@ -169,12 +242,6 @@ void MenuManager::OnSourceModAllShutdown()
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
while (!m_BroadcastHandlers.empty())
{
delete m_BroadcastHandlers.front();
m_BroadcastHandlers.pop();
}
while (!m_VoteHandlers.empty())
{
delete m_VoteHandlers.front();
@@ -659,119 +726,34 @@ skip_search:
return display;
}
#if 0
unsigned int MenuManager::BroadcastMenu(IBaseMenu *menu,
IMenuHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time)
{
BroadcastHandler *bh;
if (m_BroadcastHandlers.empty())
{
bh = new BroadcastHandler(handler);
} else {
bh = m_BroadcastHandlers.front();
m_BroadcastHandlers.pop();
bh->m_pHandler = handler;
bh->numClients = 0;
}
handler->OnMenuStart(menu);
unsigned int total = 0;
for (unsigned int i=0; i<numClients; i++)
{
/* Only continue if displaying works */
if (!menu->Display(clients[i], bh, time))
{
continue;
}
/* :TODO: Allow sourcetv only, not all bots */
CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
if (player->IsFakeClient())
{
continue;
}
total++;
}
if (!total)
{
/* End the broadcast here */
handler->OnMenuEnd(menu);
FreeBroadcastHandler(bh);
}
return total;
}
unsigned int MenuManager::VoteMenu(IBaseMenu *menu,
IMenuVoteHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time)
{
VoteHandler *vh;
if (m_VoteHandlers.empty())
{
vh = new VoteHandler(handler);
} else {
vh = m_VoteHandlers.front();
m_VoteHandlers.pop();
vh->m_pHandler = handler;
vh->numClients = 0;
}
vh->Initialize(menu);
handler->OnMenuStart(menu);
unsigned int total = 0;
for (unsigned int i=0; i<numClients; i++)
{
/* Only continue if displaying works */
if (!menu->Display(clients[i], vh, time))
{
continue;
}
/* :TODO: Allow sourcetv only, not all bots */
CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
if (player->IsFakeClient())
{
continue;
}
total++;
}
if (!total)
{
/* End the broadcast here */
handler->OnMenuEnd(menu);
FreeVoteHandler(vh);
}
return total;
}
#endif
void MenuManager::FreeBroadcastHandler(BroadcastHandler *bh)
{
m_BroadcastHandlers.push(bh);
}
void MenuManager::FreeVoteHandler(VoteHandler *vh)
{
m_VoteHandlers.push(vh);
}
IMenuStyle *MenuManager::GetDefaultStyle()
{
return m_pDefaultStyle;
}
IVoteMenuHandler *MenuManager::CreateVoteWrapper(IMenuHandler *mh)
{
VoteMenuHandler *vh = NULL;
if (m_VoteHandlers.empty())
{
vh = new VoteMenuHandler;
} else {
vh = m_VoteHandlers.front();
m_VoteHandlers.pop();
}
vh->Reset(mh);
return vh;
}
void MenuManager::ReleaseVoteWrapper(IVoteMenuHandler *mh)
{
if (mh == NULL)
{
return;
}
m_VoteHandlers.push((VoteMenuHandler *)mh);
}
+26 -37
View File
@@ -25,36 +25,36 @@
using namespace SourceMod;
using namespace SourceHook;
class BroadcastHandler : public IMenuHandler
class VoteMenuHandler : public IVoteMenuHandler
{
public:
BroadcastHandler(IMenuHandler *handler);
public: //IMenuHandler
unsigned int GetMenuAPIVersion2();
void OnMenuStart(IBaseMenu *menu);
void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
void OnMenuEnd(IBaseMenu *menu);
void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
unsigned int GetMenuAPIVersion2();
void OnMenuEnd(IBaseMenu *menu);
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
public: //IVoteMenuHandler
bool IsVoteInProgress();
void InitializeVoting(IBaseMenu *menu);
void StartVoting();
public:
virtual void OnBroadcastEnd(IBaseMenu *menu);
public:
IMenuHandler *m_pHandler;
unsigned int numClients;
};
class VoteHandler : public BroadcastHandler
{
public:
VoteHandler(IMenuVoteHandler *handler);
public:
void Initialize(IBaseMenu *menu);
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
void OnBroadcastEnd(IBaseMenu *menu);
void Reset(IMenuHandler *mh);
private:
CVector<unsigned int> m_counts;
CVector<unsigned int> m_ties;
unsigned int numItems;
IMenuVoteHandler *m_pVoteHandler;
void DecrementPlayerCount();
void EndVoting();
void InternalReset();
private:
IMenuHandler *m_pHandler;
unsigned int m_Clients;
unsigned int m_Items;
CVector<unsigned int> m_Votes;
CVector<unsigned int> m_Dups;
IBaseMenu *m_pCurMenu;
bool m_bStarted;
unsigned int m_NumVotes;
};
class MenuManager :
@@ -84,35 +84,24 @@ public:
unsigned int GetStyleCount();
IMenuStyle *GetStyle(unsigned int index);
IMenuStyle *FindStyleByName(const char *name);
unsigned int BroadcastMenu(IBaseMenu *menu,
IMenuHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time);
unsigned int VoteMenu(IBaseMenu *menu,
IMenuVoteHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time);
IMenuStyle *GetDefaultStyle();
void AddStyle(IMenuStyle *style);
bool SetDefaultStyle(IMenuStyle *style);
IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh);
void ReleaseVoteWrapper(IVoteMenuHandler *mh);
public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
public:
HandleError ReadMenuHandle(Handle_t handle, IBaseMenu **menu);
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
protected:
void FreeBroadcastHandler(BroadcastHandler *bh);
void FreeVoteHandler(VoteHandler *vh);
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
Handle_t CreateStyleHandle(IMenuStyle *style);
private:
int m_ShowMenu;
IMenuStyle *m_pDefaultStyle;
CStack<BroadcastHandler *> m_BroadcastHandlers;
CStack<VoteHandler *> m_VoteHandlers;
CStack<VoteMenuHandler *> m_VoteHandlers;
CVector<IMenuStyle *> m_Styles;
HandleType_t m_StyleType;
HandleType_t m_MenuType;
+24 -1
View File
@@ -434,12 +434,14 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true),
m_bShouldDelete(false), m_bCancelling(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent),
m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler)
m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler),
m_pVoteHandler(NULL)
{
}
CBaseMenu::~CBaseMenu()
{
g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
}
Handle_t CBaseMenu::GetHandle()
@@ -647,3 +649,24 @@ void CBaseMenu::InternalDelete()
delete this;
}
bool CBaseMenu::BroadcastVote(int clients[],
unsigned int numClients,
unsigned int maxTime,
unsigned int flags)
{
if (!m_pVoteHandler)
{
m_pVoteHandler = g_Menus.CreateVoteWrapper(m_pHandler);
} else if (m_pVoteHandler->IsVoteInProgress()) {
return false;
}
m_pVoteHandler->InitializeVoting(this);
for (unsigned int i=0; i<numClients; i++)
{
VoteDisplay(clients[i], maxTime);
}
m_pVoteHandler->StartVoting();
}
+7
View File
@@ -111,6 +111,12 @@ public:
virtual void Destroy(bool releaseHandle);
virtual void Cancel_Finally() =0;
virtual Handle_t GetHandle();
bool BroadcastVote(int clients[],
unsigned int numClients,
unsigned int maxTime,
unsigned int flags=0);
public:
virtual void VoteDisplay(int client, unsigned int maxTime) =0;
private:
void InternalDelete();
protected:
@@ -127,6 +133,7 @@ protected:
bool m_bWillFreeHandle;
Handle_t m_hHandle;
IMenuHandler *m_pHandler;
IVoteMenuHandler *m_pVoteHandler;
};
#endif //_INCLUDE_MENUSTYLE_BASE_H
+15
View File
@@ -366,9 +366,24 @@ IMenuPanel *CRadioMenu::CreatePanel()
bool CRadioMenu::Display(int client, unsigned int time)
{
if (m_bCancelling)
{
return false;
}
return g_RadioMenuStyle.DoClientMenu(client, this, m_pHandler, time);
}
void CRadioMenu::VoteDisplay(int client, unsigned int maxTime)
{
if (m_bCancelling)
{
return;
}
g_RadioMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
}
void CRadioMenu::Cancel_Finally()
{
g_RadioMenuStyle.CancelMenu(this);
+1
View File
@@ -98,6 +98,7 @@ public:
IMenuPanel *CreatePanel();
bool Display(int client, unsigned int time);
void Cancel_Finally();
void VoteDisplay(int client, unsigned int maxTime);
};
extern CRadioStyle g_RadioMenuStyle;
+10
View File
@@ -375,6 +375,16 @@ bool CValveMenu::Display(int client, unsigned int time)
return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time);
}
void CValveMenu::VoteDisplay(int client, unsigned int maxTime)
{
if (m_bCancelling)
{
return;
}
g_ValveMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
}
IMenuPanel *CValveMenu::CreatePanel()
{
return new CValveMenuDisplay(this);
+1
View File
@@ -103,6 +103,7 @@ public: //IBaseMenu
bool SetExitButton(bool set);
bool SetPagination(unsigned int itemsPerPage);
bool Display(int client, unsigned int time);
void VoteDisplay(int client, unsigned int maxTime);
public: //CBaseMenu
void Cancel_Finally();
private: