merged trunk back into 1.1.0 branch for "safety"
--HG-- branch : sourcemod-1.1.0 extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/sourcemod-1.1.0%401721
This commit is contained in:
@@ -32,6 +32,8 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
extern HandleType_t htCellArray;
|
||||
|
||||
class CellArray
|
||||
{
|
||||
public:
|
||||
@@ -149,6 +151,11 @@ public:
|
||||
return array;
|
||||
}
|
||||
|
||||
cell_t *base()
|
||||
{
|
||||
return m_Data;
|
||||
}
|
||||
|
||||
private:
|
||||
bool GrowIfNeeded(size_t count)
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ public: //IRecipientFilter
|
||||
int GetRecipientCount() const;
|
||||
int GetRecipientIndex(int slot) const;
|
||||
public:
|
||||
void Initialize(cell_t *ptr, size_t count);
|
||||
void Initialize(const cell_t *ptr, size_t count);
|
||||
void SetToReliable(bool isreliable);
|
||||
void SetToInit(bool isinitmsg);
|
||||
void Reset();
|
||||
@@ -98,7 +98,7 @@ inline void CellRecipientFilter::SetToReliable(bool isreliable)
|
||||
m_IsReliable = isreliable;
|
||||
}
|
||||
|
||||
inline void CellRecipientFilter::Initialize(cell_t *ptr, size_t count)
|
||||
inline void CellRecipientFilter::Initialize(const cell_t *ptr, size_t count)
|
||||
{
|
||||
memcpy(m_Players, ptr, count * sizeof(cell_t));
|
||||
m_Size = count;
|
||||
|
||||
+6
-1
@@ -35,6 +35,7 @@
|
||||
#include "UserMessages.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "GameConfigs.h"
|
||||
#include <compat_wrappers.h>
|
||||
|
||||
CHalfLife2 g_HL2;
|
||||
@@ -308,7 +309,11 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
pBitBuf->WriteByte(1);
|
||||
const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte");
|
||||
if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0)
|
||||
{
|
||||
pBitBuf->WriteByte(1);
|
||||
}
|
||||
pBitBuf->WriteString(msg);
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
|
||||
+3
-1
@@ -380,7 +380,9 @@ void Logger::LogError(const char *vafmt, ...)
|
||||
LogToOpenFileEx(fp, vafmt, ap);
|
||||
va_end(ap);
|
||||
fclose(fp);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformError(error, sizeof(error));
|
||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
|
||||
|
||||
+124
-12
@@ -42,9 +42,15 @@ extern const char *g_RadioNumTable[];
|
||||
CRadioStyle g_RadioMenuStyle;
|
||||
int g_ShowMenuId = -1;
|
||||
bool g_bRadioInit = false;
|
||||
unsigned int g_RadioMenuTimeout = 0;
|
||||
|
||||
CRadioStyle::CRadioStyle() : m_players(new CBaseMenuPlayer[256+1])
|
||||
CRadioStyle::CRadioStyle()
|
||||
{
|
||||
m_players = new CRadioMenuPlayer[256+1];
|
||||
for (size_t i = 0; i < 256+1; i++)
|
||||
{
|
||||
m_players[i].Radio_SetIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
void CRadioStyle::OnSourceModAllInitialized()
|
||||
@@ -73,6 +79,16 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
return;
|
||||
}
|
||||
|
||||
const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout");
|
||||
if (val != NULL)
|
||||
{
|
||||
g_RadioMenuTimeout = atoi(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RadioMenuTimeout = 0;
|
||||
}
|
||||
|
||||
g_Menus.AddStyle(this);
|
||||
g_Menus.SetDefaultStyle(this);
|
||||
|
||||
@@ -190,7 +206,9 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
||||
if (m_FreeDisplays.empty())
|
||||
{
|
||||
display = new CRadioDisplay();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
display = m_FreeDisplays.front();
|
||||
m_FreeDisplays.pop();
|
||||
display->Reset();
|
||||
@@ -198,11 +216,51 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
||||
return display;
|
||||
}
|
||||
|
||||
IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
|
||||
{
|
||||
CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
|
||||
|
||||
pPanel->DirectSet(str, keys);
|
||||
|
||||
return pPanel;
|
||||
}
|
||||
|
||||
void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
|
||||
{
|
||||
m_FreeDisplays.push(display);
|
||||
}
|
||||
|
||||
CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client)
|
||||
{
|
||||
return &m_players[client];
|
||||
}
|
||||
|
||||
void CRadioStyle::ProcessWatchList()
|
||||
{
|
||||
if (!g_RadioMenuTimeout)
|
||||
{
|
||||
BaseMenuStyle::ProcessWatchList();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseMenuStyle::ProcessWatchList();
|
||||
|
||||
CRadioMenuPlayer *pPlayer;
|
||||
unsigned int max_clients = g_Players.GetMaxClients();
|
||||
for (unsigned int i = 1; i <= max_clients; i++)
|
||||
{
|
||||
pPlayer = GetRadioMenuPlayer(i);
|
||||
if (!pPlayer->bInMenu || pPlayer->bInExternMenu)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pPlayer->Radio_NeedsRefresh())
|
||||
{
|
||||
pPlayer->Radio_Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRadioDisplay::CRadioDisplay()
|
||||
{
|
||||
Reset();
|
||||
@@ -228,6 +286,13 @@ void CRadioDisplay::Reset()
|
||||
keys = 0;
|
||||
}
|
||||
|
||||
void CRadioDisplay::DirectSet(const char *str, int keymap)
|
||||
{
|
||||
m_Title.clear();
|
||||
m_BufferText.assign(str);
|
||||
keys = keymap;
|
||||
}
|
||||
|
||||
unsigned int CRadioDisplay::GetCurrentKey()
|
||||
{
|
||||
return m_NextPos;
|
||||
@@ -326,17 +391,60 @@ bool CRadioDisplay::CanDrawItem(unsigned int drawFlags)
|
||||
|
||||
void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
{
|
||||
char buffer[4096];
|
||||
size_t len;
|
||||
|
||||
len = UTIL_Format(buffer, sizeof(buffer), "%s\n%s", m_Title.c_str(), m_BufferText.c_str());
|
||||
|
||||
cell_t players[1] = {client};
|
||||
|
||||
int _sel_keys = (keys == 0) ? (1<<9) : keys;
|
||||
CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client);
|
||||
pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str());
|
||||
pPlayer->Radio_Refresh();
|
||||
}
|
||||
|
||||
char *ptr = buffer;
|
||||
void CRadioMenuPlayer::Radio_SetIndex(unsigned int index)
|
||||
{
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
bool CRadioMenuPlayer::Radio_NeedsRefresh()
|
||||
{
|
||||
return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout);
|
||||
}
|
||||
|
||||
void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
||||
{
|
||||
if (title[0] != '\0')
|
||||
{
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s\n%s",
|
||||
title,
|
||||
text);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s",
|
||||
text);
|
||||
}
|
||||
display_keys = keys;
|
||||
}
|
||||
|
||||
void CRadioMenuPlayer::Radio_Refresh()
|
||||
{
|
||||
cell_t players[1] = {m_index};
|
||||
char *ptr = display_pkt;
|
||||
char save = 0;
|
||||
size_t len = display_len;
|
||||
unsigned int time;
|
||||
|
||||
/* Compute the new time */
|
||||
if (menuHoldTime == 0)
|
||||
{
|
||||
time = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (len > 240)
|
||||
@@ -345,7 +453,7 @@ void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
ptr[240] = '\0';
|
||||
}
|
||||
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
buffer->WriteWord(_sel_keys);
|
||||
buffer->WriteWord(display_keys);
|
||||
buffer->WriteChar(time ? time : -1);
|
||||
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
||||
buffer->WriteString(ptr);
|
||||
@@ -355,10 +463,14 @@ void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
ptr[240] = save;
|
||||
ptr = &ptr[240];
|
||||
len -= 240;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
display_last_refresh = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
int CRadioDisplay::GetAmountRemaining()
|
||||
|
||||
+21
-1
@@ -47,6 +47,21 @@ using namespace SourceMod;
|
||||
class CRadioDisplay;
|
||||
class CRadioMenu;
|
||||
|
||||
class CRadioMenuPlayer : public CBaseMenuPlayer
|
||||
{
|
||||
public:
|
||||
void Radio_Init(int keys, const char *title, const char *buffer);
|
||||
bool Radio_NeedsRefresh();
|
||||
void Radio_Refresh();
|
||||
void Radio_SetIndex(unsigned int index);
|
||||
private:
|
||||
unsigned int m_index;
|
||||
size_t display_len;
|
||||
char display_pkt[512];
|
||||
int display_keys;
|
||||
float display_last_refresh;
|
||||
};
|
||||
|
||||
class CRadioStyle :
|
||||
public BaseMenuStyle,
|
||||
public SMGlobalClass,
|
||||
@@ -61,6 +76,7 @@ public: //SMGlobalClass
|
||||
public: //BaseMenuStyle
|
||||
CBaseMenuPlayer *GetMenuPlayer(int client);
|
||||
void SendDisplay(int client, IMenuPanel *display);
|
||||
void ProcessWatchList();
|
||||
public: //IMenuStyle
|
||||
const char *GetStyleName();
|
||||
IMenuPanel *CreatePanel();
|
||||
@@ -75,8 +91,10 @@ public:
|
||||
public:
|
||||
CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL);
|
||||
void FreeRadioDisplay(CRadioDisplay *display);
|
||||
CRadioMenuPlayer *GetRadioMenuPlayer(int client);
|
||||
IMenuPanel *MakeRadioDisplay(const char *str, int keys);
|
||||
private:
|
||||
CBaseMenuPlayer *m_players;
|
||||
CRadioMenuPlayer *m_players;
|
||||
CStack<CRadioDisplay *> m_FreeDisplays;
|
||||
};
|
||||
|
||||
@@ -101,6 +119,8 @@ public: //IMenuPanel
|
||||
unsigned int GetCurrentKey();
|
||||
bool SetCurrentKey(unsigned int key);
|
||||
int GetAmountRemaining();
|
||||
public:
|
||||
void DirectSet(const char *str, int keymap);
|
||||
private:
|
||||
String m_BufferText;
|
||||
String m_Title;
|
||||
|
||||
+45
-1
@@ -1295,12 +1295,32 @@ void CPlayer::Authorize_Post()
|
||||
|
||||
void CPlayer::DoPostConnectAuthorization()
|
||||
{
|
||||
bool delay = false;
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
for (iter = g_Players.m_hooks.begin();
|
||||
iter != g_Players.m_hooks.end();
|
||||
iter++)
|
||||
{
|
||||
IClientListener *pListener = (*iter);
|
||||
#if defined MIN_API_FOR_ADMINCALLS
|
||||
if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (!pListener->OnClientPreAdminCheck(m_iIndex))
|
||||
{
|
||||
delay = true;
|
||||
}
|
||||
}
|
||||
|
||||
cell_t result = 0;
|
||||
PreAdminCheck->PushCell(m_iIndex);
|
||||
PreAdminCheck->Execute(&result);
|
||||
|
||||
/* Defer, for better or worse */
|
||||
if ((ResultType)result >= Pl_Handled)
|
||||
if (delay || (ResultType)result >= Pl_Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1318,6 +1338,15 @@ void CPlayer::DoPostConnectAuthorization()
|
||||
NotifyPostAdminChecks();
|
||||
}
|
||||
|
||||
bool CPlayer::RunAdminCacheChecks()
|
||||
{
|
||||
AdminId old_id = GetAdminId();
|
||||
|
||||
DoBasicAdminChecks();
|
||||
|
||||
return (GetAdminId() != old_id);
|
||||
}
|
||||
|
||||
void CPlayer::NotifyPostAdminChecks()
|
||||
{
|
||||
if (m_bAdminCheckSignalled)
|
||||
@@ -1328,6 +1357,21 @@ void CPlayer::NotifyPostAdminChecks()
|
||||
/* Block beforehand so they can't double-call */
|
||||
m_bAdminCheckSignalled = true;
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
for (iter = g_Players.m_hooks.begin();
|
||||
iter != g_Players.m_hooks.end();
|
||||
iter++)
|
||||
{
|
||||
IClientListener *pListener = (*iter);
|
||||
#if defined MIN_API_FOR_ADMINCALLS
|
||||
if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
pListener->OnClientPostAdminCheck(m_iIndex);
|
||||
}
|
||||
|
||||
PostAdminCheck->PushCell(m_iIndex);
|
||||
PostAdminCheck->Execute(NULL);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ using namespace SourceHook;
|
||||
#define PLAYER_LIFE_ALIVE 1
|
||||
#define PLAYER_LIFE_DEAD 2
|
||||
|
||||
#define MIN_API_FOR_ADMINCALLS 7
|
||||
|
||||
class CPlayer : public IGamePlayer
|
||||
{
|
||||
friend class PlayerManager;
|
||||
@@ -69,8 +71,9 @@ public:
|
||||
IPlayerInfo *GetPlayerInfo();
|
||||
unsigned int GetLanguageId();
|
||||
int GetUserId();
|
||||
public:
|
||||
bool RunAdminCacheChecks();
|
||||
void NotifyPostAdminChecks();
|
||||
public:
|
||||
void DoBasicAdminChecks();
|
||||
bool IsInKickQueue();
|
||||
void MarkAsBeingKicked();
|
||||
@@ -108,6 +111,7 @@ class PlayerManager :
|
||||
public SMGlobalClass,
|
||||
public IPlayerManager
|
||||
{
|
||||
friend class CPlayer;
|
||||
public:
|
||||
PlayerManager();
|
||||
~PlayerManager();
|
||||
|
||||
+6
-6
@@ -48,16 +48,16 @@ SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar
|
||||
#endif
|
||||
|
||||
TimerSystem g_Timers;
|
||||
float g_fUniversalTime = 0.0f;
|
||||
double g_fUniversalTime = 0.0f;
|
||||
float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */
|
||||
float g_fTimerThink = 0.0f; /* Timer's next think time */
|
||||
const float *g_pUniversalTime = &g_fUniversalTime;
|
||||
double g_fTimerThink = 0.0f; /* Timer's next think time */
|
||||
const double *g_pUniversalTime = &g_fUniversalTime;
|
||||
ConVar *mp_timelimit = NULL;
|
||||
int g_TimeLeftMode = 0;
|
||||
|
||||
ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
|
||||
|
||||
inline float GetSimulatedTime()
|
||||
inline double GetSimulatedTime()
|
||||
{
|
||||
return g_fUniversalTime;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ private:
|
||||
* that a drastic jump in time will continue acting normally. Users
|
||||
* may not expect this, but... I think it is the best solution.
|
||||
*/
|
||||
inline float CalcNextThink(float last, float interval)
|
||||
inline double CalcNextThink(double last, float interval)
|
||||
{
|
||||
if (g_fUniversalTime - last - interval <= TIMER_MIN_ACCURACY)
|
||||
{
|
||||
@@ -274,7 +274,7 @@ void TimerSystem::RunFrame()
|
||||
ITimer *pTimer;
|
||||
TimerIter iter;
|
||||
|
||||
float curtime = GetSimulatedTime();
|
||||
double curtime = GetSimulatedTime();
|
||||
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
|
||||
{
|
||||
pTimer = (*iter);
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@ public:
|
||||
ITimedEvent *m_Listener;
|
||||
void *m_pData;
|
||||
float m_Interval;
|
||||
float m_ToExec;
|
||||
double m_ToExec;
|
||||
int m_Flags;
|
||||
bool m_InExec;
|
||||
bool m_KillMe;
|
||||
@@ -103,7 +103,7 @@ private:
|
||||
|
||||
time_t GetAdjustedTime(time_t *buf = NULL);
|
||||
|
||||
extern const float *g_pUniversalTime;
|
||||
extern const double *g_pUniversalTime;
|
||||
extern TimerSystem g_Timers;
|
||||
extern int g_TimeLeftMode;
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
||||
return false;
|
||||
}
|
||||
|
||||
bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
|
||||
bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
|
||||
{
|
||||
bf_write *buffer;
|
||||
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ public: //IUserMessages
|
||||
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
|
||||
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags);
|
||||
bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
|
||||
bool EndMessage();
|
||||
public:
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type);
|
||||
|
||||
+47
-10
@@ -290,6 +290,34 @@ CON_COMMAND(sm, "SourceMod Menu")
|
||||
g_RootMenu.GotRootCmd(args);
|
||||
}
|
||||
|
||||
FILE *g_pHndlLog = NULL;
|
||||
|
||||
void write_handles_to_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(g_pHndlLog, fmt, ap);
|
||||
fprintf(g_pHndlLog, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void write_handles_to_game(const char *fmt, ...)
|
||||
{
|
||||
size_t len;
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
buffer[len] = '\n';
|
||||
buffer[len+1] = '\0';
|
||||
|
||||
engine->LogPrint(buffer);
|
||||
}
|
||||
|
||||
CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
|
||||
{
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
@@ -297,19 +325,28 @@ CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle le
|
||||
#endif
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file>");
|
||||
g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *arg = args.Arg(1);
|
||||
FILE *fp = fopen(arg, "wt");
|
||||
if (!fp)
|
||||
if (strcmp(args.Arg(1), "log") != 0)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
|
||||
return;
|
||||
const char *arg = args.Arg(1);
|
||||
FILE *fp = fopen(arg, "wt");
|
||||
if (!fp)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHndlLog = fp;
|
||||
g_HandleSys.Dump(write_handles_to_log);
|
||||
g_pHndlLog = NULL;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_HandleSys.Dump(write_handles_to_game);
|
||||
}
|
||||
|
||||
g_HandleSys.Dump(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
+140
-70
@@ -207,7 +207,9 @@ void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
while (string[size++]);
|
||||
size--;
|
||||
}
|
||||
@@ -234,78 +236,125 @@ void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
|
||||
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
|
||||
{
|
||||
char text[32];
|
||||
int digits;
|
||||
double signedVal;
|
||||
char *buf;
|
||||
int val;
|
||||
|
||||
// get the sign
|
||||
signedVal = fval;
|
||||
if (fval < 0)
|
||||
{
|
||||
fval = -fval;
|
||||
}
|
||||
|
||||
// write the float number
|
||||
digits = 0;
|
||||
val = (int)fval;
|
||||
do
|
||||
{
|
||||
text[digits++] = '0' + val % 10;
|
||||
val /= 10;
|
||||
} while (val);
|
||||
|
||||
if (signedVal < 0)
|
||||
{
|
||||
text[digits++] = '-';
|
||||
}
|
||||
|
||||
buf = *buf_p;
|
||||
|
||||
while ((digits < width) && maxlen)
|
||||
{
|
||||
*buf++ = ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
while ((digits--) && maxlen)
|
||||
{
|
||||
*buf++ = text[digits];
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
*buf_p = buf;
|
||||
int digits; // non-fraction part digits
|
||||
double tmp; // temporary
|
||||
char *buf = *buf_p; // output buffer pointer
|
||||
int val; // temporary
|
||||
int sign = 0; // 0: positive, 1: negative
|
||||
int fieldlength; // for padding
|
||||
int significant_digits = 0; // number of significant digits written
|
||||
const int MAX_SIGNIFICANT_DIGITS = 16;
|
||||
|
||||
// default precision
|
||||
if (prec < 0)
|
||||
{
|
||||
prec = 6;
|
||||
}
|
||||
// write the fraction
|
||||
digits = 0;
|
||||
while (digits < prec)
|
||||
|
||||
// get the sign
|
||||
if (fval < 0)
|
||||
{
|
||||
fval -= (int)fval;
|
||||
fval *= 10.0;
|
||||
val = (int)fval;
|
||||
text[digits++] = '0' + val % 10;
|
||||
fval = -fval;
|
||||
sign = 1;
|
||||
}
|
||||
|
||||
if ((digits > 0) && maxlen)
|
||||
// compute whole-part digits count
|
||||
digits = (int)log10(fval) + 1;
|
||||
|
||||
// Only print 0.something if 0 < fval < 1
|
||||
if (digits < 1)
|
||||
{
|
||||
buf = *buf_p;
|
||||
*buf++ = '.';
|
||||
digits = 1;
|
||||
}
|
||||
|
||||
// compute the field length
|
||||
fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
|
||||
|
||||
// minus sign BEFORE left padding if padding with zeros
|
||||
if (sign && maxlen && (flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
for (prec = 0; maxlen && (prec < digits); prec++)
|
||||
}
|
||||
|
||||
// right justify if required
|
||||
if ((flags & LADJUST) == 0)
|
||||
{
|
||||
while ((fieldlength < width) && maxlen)
|
||||
{
|
||||
*buf++ = text[prec];
|
||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
// minus sign AFTER left padding if padding with spaces
|
||||
if (sign && maxlen && !(flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// write the whole part
|
||||
tmp = pow(10.0, digits-1);
|
||||
while ((digits--) && maxlen)
|
||||
{
|
||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
||||
{
|
||||
*buf++ = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)(fval / tmp);
|
||||
*buf++ = '0' + val;
|
||||
fval -= val * tmp;
|
||||
tmp *= 0.1;
|
||||
}
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// write the fraction part
|
||||
if (maxlen)
|
||||
{
|
||||
*buf++ = '.';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
tmp = pow(10.0, prec);
|
||||
|
||||
fval *= tmp;
|
||||
while (prec-- && maxlen)
|
||||
{
|
||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
||||
{
|
||||
*buf++ = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp *= 0.1;
|
||||
val = (int)(fval / tmp);
|
||||
*buf++ = '0' + val;
|
||||
fval -= val * tmp;
|
||||
}
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// left justify if required
|
||||
if (flags & LADJUST)
|
||||
{
|
||||
while ((fieldlength < width) && maxlen)
|
||||
{
|
||||
// right-padding only with spaces, ZEROPAD is ignored
|
||||
*buf++ = ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
}
|
||||
|
||||
// update parent's buffer pointer
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
||||
@@ -366,9 +415,12 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
|
||||
{
|
||||
/* we want the unsigned version */
|
||||
unsignedVal = abs(val);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
unsignedVal = val;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
text[digits++] = '0' + unsignedVal % 10;
|
||||
@@ -422,7 +474,9 @@ void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags
|
||||
if (flags & UPPERDIGITS)
|
||||
{
|
||||
hexadjust = 'A' - '9' - 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
hexadjust = 'a' - '9' - 1;
|
||||
}
|
||||
|
||||
@@ -587,7 +641,7 @@ reswitch:
|
||||
case 'f':
|
||||
{
|
||||
float *value = (float *)args[arg];
|
||||
AddFloat(&buf_p, llen, *value, width, prec);
|
||||
AddFloat(&buf_p, llen, *value, width, prec, flags);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
@@ -779,7 +833,7 @@ reswitch:
|
||||
CHECK_ARGS(0);
|
||||
cell_t *value;
|
||||
pCtx->LocalToPhysAddr(params[arg], &value);
|
||||
AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
|
||||
AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
@@ -808,7 +862,9 @@ reswitch:
|
||||
player->GetName(),
|
||||
userid,
|
||||
auth);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_Format(buffer,
|
||||
sizeof(buffer),
|
||||
"Console<0><Console><Console>");
|
||||
@@ -964,7 +1020,9 @@ const char *stristr(const char *str, const char *substr)
|
||||
{
|
||||
return prevloc;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
haystack = ++prevloc;
|
||||
needle = (char *)substr;
|
||||
}
|
||||
@@ -1001,7 +1059,9 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
{
|
||||
buffer[maxlength - 1] = '\0';
|
||||
return (maxlength - 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@@ -1014,7 +1074,9 @@ size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list
|
||||
{
|
||||
buffer[maxlength - 1] = '\0';
|
||||
return (maxlength - 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@@ -1117,7 +1179,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
replaceLen = maxLen - browsed;
|
||||
/* Note, we add one to the final result for the null terminator */
|
||||
strncopy(ptr, replace, replaceLen+1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@@ -1138,7 +1202,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
/* Now, do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@@ -1158,7 +1224,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
/* Now do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
} else if (replaceLen < searchLen) {
|
||||
}
|
||||
else if (replaceLen < searchLen)
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@@ -1184,7 +1252,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
|
||||
/* Move the rest of the string down */
|
||||
memmove(moveTo, moveFrom, bytesToCopy);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
|
||||
@@ -406,6 +406,33 @@ static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvJumpToKeySymbol(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
HandleError herr;
|
||||
HandleSecurity sec;
|
||||
KeyValueStack *pStk;
|
||||
|
||||
sec.pOwner = NULL;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
|
||||
}
|
||||
|
||||
KeyValues *pSubKey = pStk->pCurRoot.front();
|
||||
pSubKey = pSubKey->FindKey(params[2]);
|
||||
if (!pSubKey)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
pStk->pCurRoot.push(pSubKey);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
@@ -921,6 +948,36 @@ static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvGetSectionSymbol(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
HandleError herr;
|
||||
HandleSecurity sec;
|
||||
KeyValueStack *pStk;
|
||||
cell_t *val;
|
||||
|
||||
sec.pOwner = NULL;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
|
||||
}
|
||||
|
||||
KeyValues *pSection = pStk->pCurRoot.front();
|
||||
|
||||
pCtx->LocalToPhysAddr(params[2], &val);
|
||||
*val = pSection->GetNameSymbol();
|
||||
|
||||
if (!*val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static KeyValueNatives s_KeyValueNatives;
|
||||
|
||||
REGISTER_NATIVES(keyvaluenatives)
|
||||
@@ -937,6 +994,7 @@ REGISTER_NATIVES(keyvaluenatives)
|
||||
{"KvGetUInt64", smn_KvGetUInt64},
|
||||
{"CreateKeyValues", smn_CreateKeyValues},
|
||||
{"KvJumpToKey", smn_KvJumpToKey},
|
||||
{"KvJumpToKeySymbol", smn_KvJumpToKeySymbol},
|
||||
{"KvGotoNextKey", smn_KvGotoNextKey},
|
||||
{"KvJumpFirstSubKey", smn_KvGotoFirstSubKey}, /* BACKWARDS COMPAT SHIM */
|
||||
{"KvGotoFirstSubKey", smn_KvGotoFirstSubKey},
|
||||
@@ -956,5 +1014,6 @@ REGISTER_NATIVES(keyvaluenatives)
|
||||
{"KvCopySubkeys", smn_CopySubkeys},
|
||||
{"KvFindKeyById", smn_FindKeyById},
|
||||
{"KvGetNameSymbol", smn_GetNameSymbol},
|
||||
{"KvGetSectionSymbol", smn_KvGetSectionSymbol},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "MenuStyle_Radio.h"
|
||||
#include "HandleSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#if defined MENU_DEBUG
|
||||
@@ -1398,6 +1399,73 @@ static cell_t GetMenuSelectionPosition(IPluginContext *pContext, const cell_t *p
|
||||
return *s_CurSelectPosition;
|
||||
}
|
||||
|
||||
class EmptyMenuHandler : public IMenuHandler
|
||||
{
|
||||
public:
|
||||
} s_EmptyMenuHandler;
|
||||
|
||||
static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client = params[1];
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", client);
|
||||
}
|
||||
else if (!pPlayer->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
if (!g_RadioMenuStyle.IsSupported())
|
||||
{
|
||||
return pContext->ThrowNativeError("Radio menus are not supported on this mod");
|
||||
}
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
IMenuPanel *pPanel = g_RadioMenuStyle.MakeRadioDisplay(str, params[4]);
|
||||
|
||||
if (pPanel == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMenuHandler *pHandler;
|
||||
CPanelHandler *pActualHandler = NULL;
|
||||
if (params[5] != -1)
|
||||
{
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
|
||||
if (pFunction == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function index %x", params[5]);
|
||||
}
|
||||
pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
|
||||
}
|
||||
|
||||
if (pActualHandler == NULL)
|
||||
{
|
||||
pHandler = &s_EmptyMenuHandler;
|
||||
}
|
||||
else
|
||||
{
|
||||
pHandler = pActualHandler;
|
||||
}
|
||||
|
||||
bool bSuccess = pPanel->SendDisplay(client, pHandler, params[3]);
|
||||
|
||||
pPanel->DeleteThis();
|
||||
|
||||
if (!bSuccess && pActualHandler != NULL)
|
||||
{
|
||||
g_MenuHelpers.FreePanelHandler(pActualHandler);
|
||||
}
|
||||
|
||||
return bSuccess ? 1 : 0;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(menuNatives)
|
||||
{
|
||||
{"AddMenuItem", AddMenuItem},
|
||||
@@ -1430,6 +1498,7 @@ REGISTER_NATIVES(menuNatives)
|
||||
{"GetPanelCurrentKey", GetPanelCurrentKey},
|
||||
{"GetPanelStyle", GetPanelStyle},
|
||||
{"InsertMenuItem", InsertMenuItem},
|
||||
{"InternalShowMenu", InternalShowMenu},
|
||||
{"IsVoteInProgress", IsVoteInProgress},
|
||||
{"RedrawMenuItem", RedrawMenuItem},
|
||||
{"RemoveAllMenuItems", RemoveAllMenuItems},
|
||||
|
||||
+1
-1
@@ -259,7 +259,7 @@ static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not connected", client);
|
||||
}
|
||||
if (!g_Admins.IsValidAdmin(params[2]))
|
||||
if (!g_Admins.IsValidAdmin(params[2]) && params[2] != INVALID_ADMIN_ID)
|
||||
{
|
||||
return pContext->ThrowNativeError("AdminId %x is invalid", params[2]);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <IHandleSys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "HandleSys.h"
|
||||
#include "CellArray.h"
|
||||
|
||||
/***********************************
|
||||
* About the double array hack *
|
||||
@@ -373,6 +375,139 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum SortType
|
||||
{
|
||||
Sort_Integer = 0,
|
||||
Sort_Float,
|
||||
Sort_String,
|
||||
};
|
||||
|
||||
int sort_adtarray_strings_asc(const void *str1, const void *str2)
|
||||
{
|
||||
return strcmp((char *) str1, (char *) str2);
|
||||
}
|
||||
|
||||
int sort_adtarray_strings_desc(const void *str1, const void *str2)
|
||||
{
|
||||
return strcmp((char *) str2, (char *) str1);
|
||||
}
|
||||
|
||||
static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *cArray;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
cell_t order = params[2];
|
||||
cell_t type = params[3];
|
||||
size_t arraysize = cArray->size();
|
||||
size_t blocksize = cArray->blocksize();
|
||||
cell_t *array = cArray->base();
|
||||
|
||||
if (type == Sort_Integer)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_desc);
|
||||
}
|
||||
}
|
||||
else if (type == Sort_Float)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc);
|
||||
}
|
||||
}
|
||||
else if (type == Sort_String)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sort_infoADT
|
||||
{
|
||||
IPluginFunction *pFunc;
|
||||
cell_t *array_base;
|
||||
cell_t array_bsize;
|
||||
Handle_t array_hndl;
|
||||
Handle_t hndl;
|
||||
};
|
||||
|
||||
sort_infoADT g_SortInfoADT;
|
||||
|
||||
int sort_adtarray_custom(const void *elem1, const void *elem2)
|
||||
{
|
||||
cell_t result = 0;
|
||||
IPluginFunction *pf = g_SortInfoADT.pFunc;
|
||||
pf->PushCell(((cell_t) ((cell_t *) elem1 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
|
||||
pf->PushCell(((cell_t) ((cell_t *) elem2 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
|
||||
pf->PushCell(g_SortInfoADT.array_hndl);
|
||||
pf->PushCell(g_SortInfoADT.hndl);
|
||||
pf->Execute(&result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *cArray;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
|
||||
if (!pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
|
||||
}
|
||||
|
||||
size_t arraysize = cArray->size();
|
||||
size_t blocksize = cArray->blocksize();
|
||||
cell_t *array = cArray->base();
|
||||
|
||||
sort_infoADT oldinfo = g_SortInfoADT;
|
||||
|
||||
g_SortInfoADT.pFunc = pFunction;
|
||||
g_SortInfoADT.array_base = array;
|
||||
g_SortInfoADT.array_bsize = (cell_t) blocksize;
|
||||
g_SortInfoADT.array_hndl = params[1];
|
||||
g_SortInfoADT.hndl = params[3];
|
||||
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_custom);
|
||||
|
||||
g_SortInfoADT = oldinfo;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(sortNatives)
|
||||
{
|
||||
{"SortIntegers", sm_SortIntegers},
|
||||
@@ -380,5 +515,7 @@ REGISTER_NATIVES(sortNatives)
|
||||
{"SortStrings", sm_SortStrings},
|
||||
{"SortCustom1D", sm_SortCustom1D},
|
||||
{"SortCustom2D", sm_SortCustom2D},
|
||||
{"SortADTArray", sm_SortADTArray},
|
||||
{"SortADTArrayCustom", sm_SortADTArrayCustom},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
+3
-1
@@ -586,9 +586,11 @@ const char *SourceModBase::GetGamePath() const
|
||||
return g_BaseDir.c_str();
|
||||
}
|
||||
|
||||
void SourceModBase::SetGlobalTarget(unsigned int index)
|
||||
unsigned int SourceModBase::SetGlobalTarget(unsigned int index)
|
||||
{
|
||||
unsigned int old = m_target;
|
||||
m_target = index;
|
||||
return old;
|
||||
}
|
||||
|
||||
unsigned int SourceModBase::GetGlobalTarget() const
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ public:
|
||||
/**
|
||||
* @brief Stores the global target index.
|
||||
*/
|
||||
void SetGlobalTarget(unsigned int index);
|
||||
unsigned int SetGlobalTarget(unsigned int index);
|
||||
|
||||
/**
|
||||
* @brief Returns the global target index.
|
||||
|
||||
@@ -285,7 +285,22 @@ void CExtension::RemovePlugin(IPlugin *pPlugin)
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakNatives.erase(iter);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
iter = m_ReplacedNatives.begin();
|
||||
while (iter != m_ReplacedNatives.end())
|
||||
{
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_ReplacedNatives.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@@ -703,6 +718,7 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
uint32_t natives = pContext->GetNativesNum();
|
||||
sp_native_t *native;
|
||||
sm_extnative_t *x_native;
|
||||
sm_repnative_t *r_native;
|
||||
for (uint32_t i=0; i<natives; i++)
|
||||
{
|
||||
/* Make sure the native is valid */
|
||||
@@ -710,11 +726,26 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure the native is not already bound */
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
/* If it is bound, see if there is a replacement. */
|
||||
if ((r_native = m_RepNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rewrite the address. Whee! */
|
||||
native->pfn = r_native->info.func;
|
||||
|
||||
/* Make sure this will unload safely */
|
||||
WeakNative wn((CPlugin *)pPlugin, i);
|
||||
r_native->owner->m_ReplacedNatives.push_back(wn);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* See if we've got this native in our cache */
|
||||
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
@@ -789,7 +820,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
||||
}
|
||||
|
||||
/* Unbound weak natives */
|
||||
/* Unbind weak natives */
|
||||
List<WeakNative>::iterator wkn_iter;
|
||||
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
|
||||
{
|
||||
@@ -798,6 +829,21 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
|
||||
}
|
||||
|
||||
/* Unbind replacement natives, link them back to their originals */
|
||||
for (wkn_iter = pExt->m_ReplacedNatives.begin();
|
||||
wkn_iter != pExt->m_ReplacedNatives.end();
|
||||
wkn_iter++)
|
||||
{
|
||||
WeakNative & wkn = (*wkn_iter);
|
||||
sp_context_t *ctx = wkn.pl->GetContext();
|
||||
sm_repnative_t *r_native = m_RepNatives.retrieve(ctx->natives[wkn.idx].name);
|
||||
if (r_native == NULL || ctx->natives[wkn.idx].pfn != r_native->info.func)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ctx->natives[wkn.idx].pfn = r_native->original;
|
||||
}
|
||||
|
||||
/* Notify and/or unload all dependencies */
|
||||
List<CExtension *>::iterator c_iter;
|
||||
CExtension *pDep;
|
||||
@@ -871,6 +917,22 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
}
|
||||
|
||||
/* Unbind our replacement natives */
|
||||
List<sm_repnative_t>::iterator rep_iter = m_RepNativeList.begin();
|
||||
while (rep_iter != m_RepNativeList.end())
|
||||
{
|
||||
sm_repnative_t & r_native = (*rep_iter);
|
||||
if (r_native.owner == pExt)
|
||||
{
|
||||
m_RepNatives.remove(r_native.info.name);
|
||||
rep_iter = m_RepNativeList.erase(rep_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell it to unload */
|
||||
pAPI = pExt->GetAPI();
|
||||
pAPI->OnExtensionUnload();
|
||||
@@ -919,6 +981,25 @@ void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *na
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
SPVM_NATIVE_FUNC orig;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((orig = g_PluginSys.FindCoreNative(natives[i].name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sm_repnative_t rep;
|
||||
rep.info = natives[i];
|
||||
rep.owner = (CExtension *)myself;
|
||||
rep.original = orig;
|
||||
m_RepNativeList.push_back(rep);
|
||||
m_RepNatives.insert(natives[i].name, rep);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::MarkAllLoaded()
|
||||
{
|
||||
List<CExtension *>::iterator iter;
|
||||
|
||||
@@ -55,6 +55,14 @@ struct sm_extnative_t
|
||||
const sp_nativeinfo_t *info;
|
||||
};
|
||||
|
||||
/* Replacement native */
|
||||
struct sm_repnative_t
|
||||
{
|
||||
CExtension *owner;
|
||||
sp_nativeinfo_t info;
|
||||
SPVM_NATIVE_FUNC original;
|
||||
};
|
||||
|
||||
class CExtension : public IExtension
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
@@ -98,6 +106,7 @@ protected:
|
||||
List<IPlugin *> m_Plugins;
|
||||
List<const sp_nativeinfo_t *> m_Natives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<WeakNative> m_ReplacedNatives;
|
||||
List<String> m_Libraries;
|
||||
unsigned int unload_code;
|
||||
bool m_bFullyLoaded;
|
||||
@@ -168,6 +177,7 @@ public:
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
@@ -175,6 +185,8 @@ private:
|
||||
CExtension *FindByOrder(unsigned int num);
|
||||
private:
|
||||
List<CExtension *> m_Libs;
|
||||
List<sm_repnative_t> m_RepNativeList;
|
||||
KTrie<sm_repnative_t> m_RepNatives;
|
||||
KTrie<sm_extnative_t> m_ExtNatives;
|
||||
};
|
||||
|
||||
|
||||
@@ -994,10 +994,10 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
||||
}
|
||||
|
||||
void HandleSystem::Dump(FILE *fp)
|
||||
void HandleSystem::Dump(HANDLE_REPORTER rep)
|
||||
{
|
||||
fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type");
|
||||
fprintf(fp, "---------------------------------------------\n");
|
||||
rep("%-10.10s\t%-20.20s\t%-20.20s", "Handle", "Owner", "Type");
|
||||
rep("---------------------------------------------");
|
||||
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
||||
{
|
||||
if (m_Handles[i].set != HandleSet_Used)
|
||||
@@ -1046,7 +1046,7 @@ void HandleSystem::Dump(FILE *fp)
|
||||
{
|
||||
type = m_strtab->GetString(pType->nameIdx);
|
||||
}
|
||||
fprintf(fp, "0x%08x\t%-20.20s\t%-20.20s\n", index, owner, type);
|
||||
rep("0x%08x\t%-20.20s\t%-20.20s", index, owner, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@ struct QHandleType
|
||||
int nameIdx;
|
||||
};
|
||||
|
||||
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
||||
|
||||
class HandleSystem :
|
||||
public IHandleSys
|
||||
{
|
||||
@@ -155,7 +157,7 @@ public: //IHandleSystem
|
||||
const HandleAccess *pAccess,
|
||||
HandleError *err);
|
||||
|
||||
void Dump(FILE *fp);
|
||||
void Dump(HANDLE_REPORTER rep);
|
||||
protected:
|
||||
/**
|
||||
* Decodes a handle with sanity and security checking.
|
||||
|
||||
@@ -1440,6 +1440,18 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
SPVM_NATIVE_FUNC CPluginManager::FindCoreNative(const char *name)
|
||||
{
|
||||
SPVM_NATIVE_FUNC pfn;
|
||||
|
||||
if (!sm_trie_retrieve(m_pCoreNatives, name, (void **)&pfn))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pfn;
|
||||
}
|
||||
|
||||
void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
|
||||
{
|
||||
assert(pPlugin->GetBaseContext() != NULL);
|
||||
|
||||
@@ -489,6 +489,7 @@ public:
|
||||
}
|
||||
public:
|
||||
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
SPVM_NATIVE_FUNC FindCoreNative(const char *name);
|
||||
private:
|
||||
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
||||
void TryRefreshDependencies(CPlugin *pOther);
|
||||
|
||||
@@ -243,3 +243,8 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
|
||||
{
|
||||
g_Extensions.AddLibrary(myself, name);
|
||||
}
|
||||
|
||||
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
g_Extensions.OverrideNatives(myself, natives);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ public: //IShareSys
|
||||
void DestroyIdentity(IdentityToken_t *identity);
|
||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
void RegisterLibrary(IExtension *myself, const char *name);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public: //SMGlobalClass
|
||||
/* Pre-empt in case anything tries to register idents early */
|
||||
void OnSourceModStartup(bool late);
|
||||
|
||||
Reference in New Issue
Block a user