VScript: properly implement 'sq_getstring' and 'sq_getinteger' + more

sq_getstring and sq_getinteger are now properly implemented (code matches squirrel code, and generated assembly matches that of the game). Adjusted call sites to accommodate the new implementation and added a few extra checks. Also added:
* sq_getfloat
* sq_getbool
* sq_getthread
This commit is contained in:
Kawe Mazidjatari 2024-04-03 18:30:57 +02:00
parent ce64cc57a0
commit 250fd504af
8 changed files with 190 additions and 62 deletions

View File

@ -60,7 +60,7 @@ static ConCommand script_ui("script_ui", SQVM_UIScript_f, "Run input code as UI
//-----------------------------------------------------------------------------
// Purpose: checks if the server index is valid, raises an error if not
//-----------------------------------------------------------------------------
static SQBool Script_CheckServerIndex(HSQUIRRELVM v, SQInteger iServer)
static SQBool Script_CheckServerIndexAndFailure(HSQUIRRELVM v, SQInteger iServer)
{
SQInteger iCount = static_cast<SQInteger>(g_ServerListManager.m_vServerList.size());
@ -69,6 +69,11 @@ static SQBool Script_CheckServerIndex(HSQUIRRELVM v, SQInteger iServer)
v_SQVM_RaiseError(v, "Index must be less than %i.\n", iCount);
return false;
}
else if (iServer == -1) // If its still -1, then 'sq_getinteger' failed
{
v_SQVM_RaiseError(v, "Invalid argument type provided.\n");
return false;
}
return true;
}
@ -108,10 +113,13 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT GetHiddenServerName(HSQUIRRELVM v)
{
SQChar* privateToken = sq_getstring(v, 1);
const SQChar* privateToken = nullptr;
if (!VALID_CHARSTAR(privateToken))
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
if (SQ_FAILED(sq_getstring(v, 2, &privateToken)) || VALID_CHARSTAR(privateToken))
{
v_SQVM_ScriptError("Empty or null private token");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
string hiddenServerRequestMessage;
NetGameServer_t serverListing;
@ -154,9 +162,11 @@ namespace VScriptCode
SQRESULT GetServerName(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const string& serverName = g_ServerListManager.m_vServerList[iServer].name;
@ -171,9 +181,11 @@ namespace VScriptCode
SQRESULT GetServerDescription(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const string& serverDescription = g_ServerListManager.m_vServerList[iServer].description;
@ -188,9 +200,11 @@ namespace VScriptCode
SQRESULT GetServerMap(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const string& svServerMapName = g_ServerListManager.m_vServerList[iServer].map;
@ -205,9 +219,11 @@ namespace VScriptCode
SQRESULT GetServerPlaylist(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const string& serverPlaylist = g_ServerListManager.m_vServerList[iServer].playlist;
@ -222,9 +238,11 @@ namespace VScriptCode
SQRESULT GetServerCurrentPlayers(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const SQInteger playerCount = g_ServerListManager.m_vServerList[iServer].numPlayers;
@ -239,9 +257,11 @@ namespace VScriptCode
SQRESULT GetServerMaxPlayers(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
const SQInteger maxPlayers = g_ServerListManager.m_vServerList[iServer].maxPlayers;
@ -265,7 +285,10 @@ namespace VScriptCode
PromoRightDesc
};
R5RPromoData ePromoIndex = static_cast<R5RPromoData>(sq_getinteger(v, 1));
SQInteger idx = 0;
sq_getinteger(v, 2, &idx);
R5RPromoData ePromoIndex = static_cast<R5RPromoData>(idx);
const char* pszPromoKey;
switch (ePromoIndex)
@ -339,11 +362,19 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT ConnectToServer(HSQUIRRELVM v)
{
SQChar* ipAddress = sq_getstring(v, 1);
SQChar* cryptoKey = sq_getstring(v, 2);
const SQChar* ipAddress = nullptr;
if (SQ_FAILED(sq_getstring(v, 2, &ipAddress)))
{
v_SQVM_ScriptError("Missing ip address");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
if (!VALID_CHARSTAR(ipAddress) || VALID_CHARSTAR(cryptoKey))
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
const SQChar* cryptoKey = nullptr;
if (SQ_FAILED(sq_getstring(v, 3, &cryptoKey)))
{
v_SQVM_ScriptError("Missing encryption key");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
Msg(eDLL_T::UI, "Connecting to server with ip address '%s' and encryption key '%s'\n", ipAddress, cryptoKey);
g_ServerListManager.ConnectToServer(ipAddress, cryptoKey);
@ -357,9 +388,11 @@ namespace VScriptCode
SQRESULT ConnectToListedServer(HSQUIRRELVM v)
{
AUTO_LOCK(g_ServerListManager.m_Mutex);
SQInteger iServer = sq_getinteger(v, 1);
if (!Script_CheckServerIndex(v, iServer))
SQInteger iServer = -1;
sq_getinteger(v, 2, &iServer);
if (!Script_CheckServerIndexAndFailure(v, iServer))
{
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
@ -377,15 +410,19 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT ConnectToHiddenServer(HSQUIRRELVM v)
{
SQChar* privateToken = sq_getstring(v, 1);
const SQChar* privateToken = nullptr;
const SQRESULT strRet = sq_getstring(v, 2, &privateToken);
if (!VALID_CHARSTAR(privateToken))
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
if (SQ_FAILED(strRet) || VALID_CHARSTAR(privateToken))
{
v_SQVM_ScriptError("Empty or null private token");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
string hiddenServerRequestMessage;
NetGameServer_t netListing;
bool result = g_MasterServer.GetServerByToken(netListing, hiddenServerRequestMessage, privateToken); // Send token connect request.
const bool result = g_MasterServer.GetServerByToken(netListing, hiddenServerRequestMessage, privateToken); // Send token connect request.
if (result)
{
g_ServerListManager.ConnectToServer(netListing.address, netListing.port, netListing.netKey);

View File

@ -2178,10 +2178,15 @@ SQRESULT VScriptCode::Server::LiveAPI_LogRaw(HSQUIRRELVM v)
if (sq_istable(object))
{
const SQTable* const table = object._unVal.pTable;
const eLiveAPI_EventTypes eventType = eLiveAPI_EventTypes(sq_getinteger(v, 2));
const SQTable* const table = _table(object);
SQInteger eventType = 0;
if (!LiveAPI_HandleEventByCategory(v, table, eventType))
if (SQ_FAILED(sq_getinteger(v, 3, &eventType)))
{
v_SQVM_ScriptError("Second argument must be an integer.");
result = SQ_FAIL;
}
else if (!LiveAPI_HandleEventByCategory(v, table, eLiveAPI_EventTypes(eventType)))
result = SQ_ERROR;
}
else

View File

@ -48,17 +48,25 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT CreateServer(HSQUIRRELVM v)
{
SQChar* serverName = sq_getstring(v, 1);
SQChar* serverDescription = sq_getstring(v, 2);
SQChar* serverMapName = sq_getstring(v, 3);
SQChar* serverPlaylist = sq_getstring(v, 4);
ServerVisibility_e serverVisibility = static_cast<ServerVisibility_e>(sq_getinteger(v, 5));
const SQChar* serverName = nullptr;
const SQChar* serverDescription = nullptr;
const SQChar* serverMapName = nullptr;
const SQChar* serverPlaylist = nullptr;
sq_getstring(v, 2, &serverName);
sq_getstring(v, 3, &serverDescription);
sq_getstring(v, 4, &serverMapName);
sq_getstring(v, 5, &serverPlaylist);
SQInteger serverVisibility = 0;
sq_getinteger(v, 6, &serverVisibility);
if (!VALID_CHARSTAR(serverName) ||
!VALID_CHARSTAR(serverMapName) ||
!VALID_CHARSTAR(serverPlaylist))
{
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
v_SQVM_ScriptError("Empty or null server criteria");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
// Adjust browser settings.
@ -70,7 +78,7 @@ namespace VScriptCode
details.playlist = serverPlaylist;
// Launch server.
g_ServerHostManager.SetVisibility(serverVisibility);
g_ServerHostManager.SetVisibility(ServerVisibility_e(serverVisibility));
g_ServerHostManager.LaunchServer(g_pServer->IsActive());
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
@ -91,8 +99,17 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT KickPlayerByName(HSQUIRRELVM v)
{
SQChar* playerName = sq_getstring(v, 1);
SQChar* reason = sq_getstring(v, 2);
const SQChar* playerName = nullptr;
const SQChar* reason = nullptr;
sq_getstring(v, 2, &playerName);
sq_getstring(v, 3, &reason);
if (!VALID_CHARSTAR(playerName))
{
v_SQVM_ScriptError("Empty or null player name");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
// Discard empty strings, this will use the default message instead.
if (!VALID_CHARSTAR(reason))
@ -107,8 +124,17 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT KickPlayerById(HSQUIRRELVM v)
{
SQChar* playerHandle = sq_getstring(v, 1);
SQChar* reason = sq_getstring(v, 2);
const SQChar* playerHandle = nullptr;
const SQChar* reason = nullptr;
sq_getstring(v, 2, &playerHandle);
sq_getstring(v, 3, &reason);
if (!VALID_CHARSTAR(playerHandle))
{
v_SQVM_ScriptError("Empty or null player handle");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
// Discard empty strings, this will use the default message instead.
if (!VALID_CHARSTAR(reason))
@ -123,8 +149,17 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT BanPlayerByName(HSQUIRRELVM v)
{
SQChar* playerName = sq_getstring(v, 1);
SQChar* reason = sq_getstring(v, 2);
const SQChar* playerName = nullptr;
const SQChar* reason = nullptr;
sq_getstring(v, 2, &playerName);
sq_getstring(v, 3, &reason);
if (!VALID_CHARSTAR(playerName))
{
v_SQVM_ScriptError("Empty or null player name");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
// Discard empty strings, this will use the default message instead.
if (!VALID_CHARSTAR(reason))
@ -139,8 +174,17 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT BanPlayerById(HSQUIRRELVM v)
{
SQChar* playerHandle = sq_getstring(v, 1);
SQChar* reason = sq_getstring(v, 2);
const SQChar* playerHandle = nullptr;
const SQChar* reason = nullptr;
sq_getstring(v, 2, &playerHandle);
sq_getstring(v, 3, &reason);
if (!VALID_CHARSTAR(playerHandle))
{
v_SQVM_ScriptError("Empty or null player handle");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
// Discard empty strings, this will use the default message instead.
if (!VALID_CHARSTAR(reason))
@ -155,7 +199,15 @@ namespace VScriptCode
//-----------------------------------------------------------------------------
SQRESULT UnbanPlayer(HSQUIRRELVM v)
{
SQChar* szCriteria = sq_getstring(v, 1);
const SQChar* szCriteria = nullptr;
sq_getstring(v, 2, &szCriteria);
if (!VALID_CHARSTAR(szCriteria))
{
v_SQVM_ScriptError("Empty or null player criteria");
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
}
g_BanSystem.UnbanPlayer(szCriteria);
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);

View File

@ -93,8 +93,8 @@ struct SQWeakRef : SQRefCounted
#define _stringval(obj) (obj)._unVal.pString->_val
#define _userdataval(obj) (obj)._unVal.pUserData->_val
#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num))
#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num))
#define tofloat(num) ((sq_type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num))
#define tointeger(num) ((sq_type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num))
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
struct SQObjectPtr : public SQObject

View File

@ -163,8 +163,11 @@ typedef struct tagSQObject
///////////////////////////////////////////////////////////////////////////////
SQRESULT sq_pushroottable(HSQUIRRELVM v);
SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i);
SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i);
SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger* i);
SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat* f);
SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool* b);
SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* thread);
SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c);
SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx);
SQInteger sq_gettop(HSQUIRRELVM v);
SQRESULT sq_pushroottable(HSQUIRRELVM v);
@ -184,6 +187,7 @@ SQRESULT sq_startconsttable(HSQUIRRELVM v);
SQRESULT sq_endconsttable(HSQUIRRELVM v);
/*UTILITY MACRO*/
#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC)
#define sq_istable(o) ((o)._type==OT_TABLE)
#define sq_isarray(o) ((o)._type==OT_ARRAY)
#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO)

View File

@ -18,7 +18,7 @@ enum class SQCONTEXT : SQInteger
struct SQVM : public CHAINABLE_OBJ
{
void PrintObjVal(const SQObject& oin, SQObject& oout);
void PrintObjVal(const SQObject* oin, SQObject* oout);
// push sqobjectptr on to the stack
void Push(const SQObjectPtr& o);
@ -69,7 +69,7 @@ inline void(*v_SQVM_CompileError)(HSQUIRRELVM v, const SQChar* pszError, const S
inline void(*v_SQVM_LogicError)(SQBool bPrompt);
inline SQInteger(*v_SQVM_ScriptError)(const SQChar* pszFormat, ...);
inline SQInteger(*v_SQVM_RaiseError)(HSQUIRRELVM v, const SQChar* pszFormat, ...);
inline void(*v_SQVM_PrintObjVal)(HSQUIRRELVM v, const SQObjectPtr& oin, const SQObjectPtr& oout);
inline void(*v_SQVM_PrintObjVal)(HSQUIRRELVM v, const SQObject* oin, SQObject* oout);
SQRESULT SQVM_PrintFunc(HSQUIRRELVM v, SQChar* fmt, ...);
SQRESULT SQVM_sprintf(HSQUIRRELVM v, SQInteger a2, SQInteger a3, SQInteger* nStringSize, SQChar** ppString);

View File

@ -16,7 +16,7 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v, SQInteger idx, SQObjectType type, SQObjec
*o = &stack_get(v, idx);
if (sq_type(**o) != type) {
SQObjectPtr oval;
v->PrintObjVal(**o, oval);
v->PrintObjVal(*o, &oval);
v_SQVM_RaiseError(v, _SC("wrong argument type, expected '%s' got '%.50s'"), IdType2Name(type), _stringval(oval));
return false;
}
@ -32,9 +32,45 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v, SQInteger idx, SQObjectType type, SQObjec
}
//---------------------------------------------------------------------------------
SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i) // TODO: deprecate and remove!
SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger* i)
{
return v->_stackbase[i]._unVal.pString->_val;
SQObjectPtr& o = stack_get(v, idx);
if (sq_isnumeric(o)) {
*i = tointeger(o);
return SQ_OK;
}
return SQ_ERROR;
}
//---------------------------------------------------------------------------------
SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat* f)
{
SQObjectPtr& o = stack_get(v, idx);
if (sq_isnumeric(o)) {
*f = tofloat(o);
return SQ_OK;
}
return SQ_ERROR;
}
//---------------------------------------------------------------------------------
SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool* b)
{
SQObjectPtr& o = stack_get(v, idx);
if (sq_isbool(o)) {
*b = _integer(o);
return SQ_OK;
}
return SQ_ERROR;
}
//---------------------------------------------------------------------------------
SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* thread)
{
SQObjectPtr* o = NULL;
_GETSAFE_OBJ(v, idx, OT_THREAD, o);
*thread = _thread(*o);
return SQ_OK;
}
//---------------------------------------------------------------------------------
@ -46,12 +82,6 @@ SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c)
return SQ_OK;
}
//---------------------------------------------------------------------------------
SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i)
{
return v->_stackbase[i]._unVal.nInteger;
}
//---------------------------------------------------------------------------------
SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)
{

View File

@ -4,7 +4,7 @@
#include "sqvm.h"
#include "sqstring.h"
void SQVM::PrintObjVal(const SQObject& oin, SQObject& oout)
void SQVM::PrintObjVal(const SQObject* oin, SQObject* oout)
{
v_SQVM_PrintObjVal(this, oin, oout);
}