Squirrel: reverse more squirrel types and structures

This patch removes a lot of old code. Context is now exclusively grabbed from the CSquirrelVM instance. This patch also comes with a few new types: SQArray and SQTable!

The implementation also allows pushing Vector3D's on the stack, but these are handled slightly differently.. The largest field in tagSQObjectValue is 8 bytes, Vector3D is 12 bytes unaligned, but the tagSQObjectValue field in the tagSQObject struct is aligned to a 8 byte boundary while the field prior is only 4 bytes, Vector3D starts right after the type field in the tagSQObject (at the padding) to keep the whole structure the same size, therefore a new field has been added in between the padding (_pad) with a simple Vector3D accessor.

Also added a hook to allow registering proper script enums.
This commit is contained in:
Kawe Mazidjatari 2024-03-25 01:41:52 +01:00
parent bea1deeb9d
commit 1c32339305
21 changed files with 671 additions and 174 deletions

View File

@ -84,12 +84,7 @@ namespace VScriptCode
v_SQVM_ScriptError("%s", pString);
// this should be moved to a wrapper for all script funcs
if (*reinterpret_cast<DWORD*>(&v->_sharedstate->gap43b9[127]))
{
v_SQVM_ThrowError(*reinterpret_cast<QWORD*>(&v->_sharedstate->gap43b9[111]), v);
}
SCRIPT_CHECK_INTERNAL_ERROR(v);
return SQ_ERROR;
}
}
@ -118,3 +113,37 @@ void Script_RegisterListenServerConstants(CSquirrelVM* s)
const SQBool hasListenServer = !IsClientDLL();
s->RegisterConstant("LISTEN_SERVER", hasListenServer);
}
//---------------------------------------------------------------------------------
// Purpose: server enums
// Input : *s -
//---------------------------------------------------------------------------------
void Script_RegisterCommonEnums_Server(CSquirrelVM* const s)
{
v_Script_RegisterCommonEnums_Server(s);
if (ServerScriptRegisterEnum_Callback)
ServerScriptRegisterEnum_Callback(s);
}
//---------------------------------------------------------------------------------
// Purpose: client/ui enums
// Input : *s -
//---------------------------------------------------------------------------------
void Script_RegisterCommonEnums_Client(CSquirrelVM* const s)
{
v_Script_RegisterCommonEnums_Client(s);
const SQCONTEXT context = s->GetContext();
if (context == SQCONTEXT::CLIENT && ClientScriptRegisterEnum_Callback)
ClientScriptRegisterEnum_Callback(s);
else if (context == SQCONTEXT::UI && UIScriptRegisterEnum_Callback)
UIScriptRegisterEnum_Callback(s);
}
void VScriptShared::Detour(const bool bAttach) const
{
DetourSetup(&v_Script_RegisterCommonEnums_Server, &Script_RegisterCommonEnums_Server, bAttach);
DetourSetup(&v_Script_RegisterCommonEnums_Client, &Script_RegisterCommonEnums_Client, bAttach);
}

View File

@ -3,6 +3,9 @@
#include "vscript/languages/squirrel_re/include/squirrel.h"
#include "vscript/languages/squirrel_re/vsquirrel.h"
inline void (*v_Script_RegisterCommonEnums_Server)(CSquirrelVM* const s);
inline void (*v_Script_RegisterCommonEnums_Client)(CSquirrelVM* const s);
inline void*(*v_Script_Remote_BeginRegisteringFunctions)(void);
inline void*(*v_RestoreRemoteChecksumsFromSaveGame)(void* a1, void* a2);
@ -32,13 +35,22 @@ class VScriptShared : public IDetour
{
virtual void GetAdr(void) const
{
LogFunAdr("Script_RegisterCommonEnums_Server", v_Script_RegisterCommonEnums_Server);
LogFunAdr("Script_RegisterCommonEnums_Client", v_Script_RegisterCommonEnums_Client);
LogFunAdr("Remote_BeginRegisteringFunctions", v_Script_Remote_BeginRegisteringFunctions);
LogFunAdr("RestoreRemoteChecksumsFromSaveGame", v_RestoreRemoteChecksumsFromSaveGame);
LogVarAdr("g_nServerRemoteChecksum", g_nServerRemoteChecksum);
LogVarAdr("g_nClientRemoteChecksum", g_nClientRemoteChecksum);
}
virtual void GetFun(void) const
{
g_GameDll.FindPatternSIMD("E8 ? ? ? ? 48 8B CB E8 ? ? ? ? 48 8B 43 08 BF ? ? ? ? 48 8B 50 60 48 8D 05 ? ? ? ? 48 89 82 ? ? ? ? 65 48 8B 04 25 ? ? ? ? 48 03 38 8B 07 39 05 ? ? ? ? 0F 8F ? ? ? ? 48 8D 05 ? ? ? ? 48 8D 0D ? ? ? ? 48 89 05 ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 89 35 ? ? ? ? 48 89 05 ? ? ? ? 4C 8D 35 ? ? ? ?")
.FollowNearCallSelf().GetPtr(v_Script_RegisterCommonEnums_Server);
g_GameDll.FindPatternSIMD("E8 ? ? ? ? 48 8B CB E8 ? ? ? ? 48 8B 43 08 BF ? ? ? ? 48 8B 50 60 48 8D 05 ? ? ? ? 48 89 82 ? ? ? ? 65 48 8B 04 25 ? ? ? ? 48 03 38 8B 07 39 05 ? ? ? ? 0F 8F ? ? ? ? 48 8D 05 ? ? ? ? 48 8D 0D ? ? ? ? 48 89 05 ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 89 35 ? ? ? ? 48 89 05 ? ? ? ? 4C 8D 3D ? ? ? ?")
.FollowNearCallSelf().GetPtr(v_Script_RegisterCommonEnums_Client);
g_GameDll.FindPatternSIMD("48 83 EC 28 83 3D ?? ?? ?? ?? ?? 74 10").GetPtr(v_Script_Remote_BeginRegisteringFunctions);
g_GameDll.FindPatternSIMD("48 89 4C 24 ?? 41 54 48 83 EC 40").GetPtr(v_RestoreRemoteChecksumsFromSaveGame);
}
@ -48,7 +60,7 @@ class VScriptShared : public IDetour
g_nClientRemoteChecksum = CMemory(v_Script_Remote_BeginRegisteringFunctions).Offset(0x0).FindPatternSelf("89 05", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x2, 0x6).RCast<uint32_t*>();
}
virtual void GetCon(void) const { }
virtual void Detour(const bool bAttach) const { }
virtual void Detour(const bool bAttach) const;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -15,11 +15,14 @@ add_sources( SOURCE_GROUP "Squirrel_RE"
add_sources( SOURCE_GROUP "Squirrel_RE/squirrel"
"languages/squirrel_re/squirrel/sqapi.cpp"
"languages/squirrel_re/squirrel/sqdebug.cpp"
#"languages/squirrel_re/squirrel/sqcompiler.cpp"
"languages/squirrel_re/squirrel/sqfuncstate.cpp"
#"languages/squirrel_re/squirrel/sqlexer.cpp"
"languages/squirrel_re/squirrel/sqobject.cpp"
"languages/squirrel_re/squirrel/sqstring.cpp"
"languages/squirrel_re/squirrel/sqtable.cpp"
"languages/squirrel_re/squirrel/sqmem.cpp"
"languages/squirrel_re/squirrel/sqvm.cpp"
)
@ -33,11 +36,14 @@ add_sources( SOURCE_GROUP "Squirrel_RE/include"
#"languages/squirrel_re/include/sqcompiler.h"
"languages/squirrel_re/include/sqfuncstate.h"
#"languages/squirrel_re/include/sqlexer.h"
"languages/squirrel_re/include/sqarray.h"
"languages/squirrel_re/include/squtils.h"
"languages/squirrel_re/include/sqobject.h"
"languages/squirrel_re/include/sqopcodes.h"
"languages/squirrel_re/include/sqstate.h"
"languages/squirrel_re/include/sqstdaux.h"
"languages/squirrel_re/include/sqstring.h"
"languages/squirrel_re/include/sqtable.h"
"languages/squirrel_re/include/squirrel.h"
"languages/squirrel_re/include/sqvm.h"
)

View File

@ -0,0 +1,30 @@
/* see copyright notice in squirrel.h */
#ifndef _SQARRAY_H_
#define _SQARRAY_H_
struct SQArray : public CHAINABLE_OBJ
{
public:
bool Get(const SQInteger nidx, SQObjectPtr& val)
{
if (nidx >= 0 && nidx < (SQInteger)_values.size()) {
SQObjectPtr& o = _values[nidx];
val = _realval(o);
return true;
}
else return false;
}
bool Set(const SQInteger nidx, const SQObjectPtr& val)
{
if (nidx >= 0 && nidx < (SQInteger)_values.size()) {
_values[nidx] = val;
return true;
}
else return false;
}
SQInteger Size() const { return _values.size(); }
SQObjectPtrVec _values;
};
#endif //_SQARRAY_H_

View File

@ -7,7 +7,7 @@
struct SQFuncState
{
_BYTE gap0[17408];
_BYTE gap0[17400];
sqvector<SQInstruction> _instructions;
_BYTE gap4418[88];
SQObjectPtr _sourcename;

View File

@ -1,10 +1,15 @@
#ifndef SQOBJECT_H
#define SQOBJECT_H
/* see copyright notice in squirrel.h */
#ifndef _SQOBJECT_H_
#define _SQOBJECT_H_
#include "squirrel.h"
#include "squtils.h"
struct SQSharedState;
struct SQRefCounted
{
SQRefCounted() { _uiRef = 0; _weakref = NULL; }
SQRefCounted() { _uiRef = 0; _weakref = NULL; _globalnum = NULL; unk2 = NULL; }
virtual ~SQRefCounted();
virtual void Release() = 0;
@ -13,8 +18,21 @@ struct SQRefCounted
SQUnsignedInteger _uiRef;
SQObject* _weakref; // this is not an sqobject!
// index into the global array; see [r5apex + B1C7DE] for assignment
// and [r5apex + B2CAF8] for usage
SQInteger _globalnum;
void* unk2; // unknown
};
struct SQWeakRef : SQRefCounted
{
void Release();
SQObject _obj;
};
#define _realval(o) (sq_type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj)
#define __AddRef(type, unval) \
if(ISREFCOUNTED(type)) \
{ \
@ -27,17 +45,79 @@ struct SQRefCounted
unval.pRefCounted->Release(); \
}
#define __ObjAddRef(obj) { \
SQ_VALIDATE_REF_COUNT( obj ); \
(obj)->_uiRef++; \
}
#define __ObjRelease(obj) { \
if((obj)) { \
if( ( -- ((obj)->_uiRef) ) <= 0 ) \
{ \
SQ_VALIDATE_REF_COUNT( obj ); \
(obj)->Release(); \
} \
(obj) = NULL; \
} \
}
//#define type(obj) ((obj)._type)
// VALVE_BUILD -- define a version of 'type' that is less name-space polluting so that we can #undef
// and redef type around VS 2013 STL header files.
#define sq_type(obj) ((obj)._type)
#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE)
#define raw_type(obj) _RAW_TYPE((obj)._type)
#define _bool(obj) (!!(obj)._unVal.nInteger)
#define _integer(obj) ((obj)._unVal.nInteger)
#define _float(obj) ((obj)._unVal.fFloat)
#define _string(obj) ((obj)._unVal.pString)
#define _table(obj) ((obj)._unVal.pTable)
#define _array(obj) ((obj)._unVal.pArray)
#define _closure(obj) ((obj)._unVal.pClosure)
#define _generator(obj) ((obj)._unVal.pGenerator)
#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure)
#define _userdata(obj) ((obj)._unVal.pUserData)
#define _userpointer(obj) ((obj)._unVal.pUserPointer)
#define _thread(obj) ((obj)._unVal.pThread)
#define _funcproto(obj) ((obj)._unVal.pFunctionProto)
#define _class(obj) ((obj)._unVal.pClass)
#define _instance(obj) ((obj)._unVal.pInstance)
#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable)
#define _weakref(obj) ((obj)._unVal.pWeakRef)
#define _refcounted(obj) ((obj)._unVal.pRefCounted)
#define _rawval(obj) ((obj)._unVal.raw)
#define _vector3d(obj) ((Vector3D*)&(obj)._pad)
#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))
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
struct SQObjectPtr : public SQObject
{
SQObjectPtr()
{
_type = OT_NULL;
_pad = NULL;
_unVal.pUserPointer = nullptr;
}
SQObjectPtr(const SQObjectPtr& o)
{
_type = o._type;
_pad = o._pad;
_unVal = o._unVal;
__AddRef(_type, _unVal);
}
SQObjectPtr(const SQObject& o)
{
_type = o._type;
_pad = NULL;
_unVal = o._unVal;
__AddRef(_type, _unVal);
}
@ -47,6 +127,7 @@ struct SQObjectPtr : public SQObject
assert(pString);
_type = OT_STRING;
_pad = NULL;
_unVal.pString = pString;
__AddRef(_type, _unVal);
}
@ -54,18 +135,21 @@ struct SQObjectPtr : public SQObject
SQObjectPtr(bool bBool)
{
_type = OT_BOOL;
_pad = NULL;
_unVal.nInteger = bBool ? 1 : 0;
}
SQObjectPtr(SQInteger nInteger)
{
_type = OT_INTEGER;
_pad = NULL;
_unVal.nInteger = nInteger;
}
SQObjectPtr(SQFloat fFloat)
{
_type = OT_FLOAT;
_pad = NULL;
_unVal.fFloat = fFloat;
}
@ -80,6 +164,7 @@ struct SQObjectPtr : public SQObject
SQObjectValue oldVal = _unVal;
_type = obj._type;
_pad = obj._pad;
_unVal = obj._unVal;
__AddRef(_type, _unVal);
@ -87,17 +172,37 @@ struct SQObjectPtr : public SQObject
return *this;
}
const char* GetCString() const;
SQString* GetSQString() const
{
assert(_type == OT_STRING);
return _unVal.pString;
}
};
static SQObjectPtr _null_;
#endif // SQOBJECT_H
struct SQCollectable : public SQRefCounted {
SQCollectable* _next;
SQCollectable* _prev;
SQSharedState* _sharedstate;
virtual void Release() = 0;
virtual void Mark(SQCollectable** chain) = 0;
//void UnMark();
virtual void Finalize() = 0;
//static void AddToChain(SQCollectable** chain, SQCollectable* c);
//static void RemoveFromChain(SQCollectable** chain, SQCollectable* c);
};
#define CHAINABLE_OBJ SQCollectable
struct SQDelegable : public CHAINABLE_OBJ {
//bool SetDelegate(SQTable* m);
virtual void DumpToString(SQChar* buf, SQUnsignedInteger len, SQInteger start, SQInteger end) = 0;
//enum SQMetaMethod; // TODO
virtual bool GetMetaMethod(SQVM* v, /*SQMetaMethod*/ int mm, SQObjectPtr& res) = 0;
SQTable* _delegate;
};
typedef sqvector<SQObjectPtr> SQObjectPtrVec;
typedef sqvector<SQInteger> SQIntVec;
const SQChar* IdType2Name(const SQObjectType type);
#endif //_SQOBJECT_H_

View File

@ -1,37 +1,71 @@
#ifndef SQSTATE_H
#define SQSTATE_H
#include "squirrel.h"
#include "sqobject.h"
//#include "sqcompiler.h"
struct SQCompiler;
class CSquirrelVM;
struct RefTable {
struct RefNode {
SQObjectPtr obj;
SQUnsignedInteger refs;
struct RefNode* next;
};
private:
SQUnsignedInteger _numofslots;
SQUnsignedInteger _slotused;
RefNode* _nodes;
RefNode* _freelist;
RefNode** _buckets;
};
#pragma pack(push, 1)
struct SQSharedState
{
_BYTE gap0[16456];
void* _stringtable; // allocated with a size of 17488 in CSquirrelVM::Init - possibly stringtable
_BYTE gap4070[488];
SQCompiler* _compiler;
uint8_t gap1[320];
RefTable _refs_table;
uint8_t gap1[138];
SQTable* _unknowntable0;
uint8_t gap2[140];
void* _compilererrorhandler;
void* _printfunc;
uint8_t gap4390[33];
SQChar _contextname[8];
char gap43b9[135];
char* _scratchpad;
int _scratchpadsize;
SQChar _contextname_small_maybe[8];
char gap43b9[7];
SQTable* _unknowntable2;
char gap41E0[88];
SQCompiler* _compiler;
char gap4240[24];
char* _scratchpad_probablynot;
int _scratchpadsize_probablynot;
char unk[32];
SQCollectable* _gc_chain;
char pad_4290[289];
SQChar _contextname[32];
char pad_43D1[87];
CSquirrelVM* _scriptvm;
SQInteger _globalnum;
char pad_4434[4];
int _internal_error;
SQChar* _scratchpad;
SQInteger _scratchpadsize;
SQCompiler* GetCompiler()
{
return _compiler;
}
};
#pragma pack(pop)
static_assert(offsetof(SQSharedState, _compiler) == 0x4238);
static_assert(offsetof(SQSharedState, _printfunc) == 0x4388);
CSquirrelVM* GetScriptVM()
{
return _scriptvm;
}
};
//static_assert(offsetof(SQSharedState, _compiler) == 0x4238);
//static_assert(offsetof(SQSharedState, _printfunc) == 0x4388);
struct SQBufState
{

View File

@ -6,10 +6,10 @@
struct SQString : public SQRefCounted
{
char gap18[16];
SQSharedState* _sharedstate;
int _len;
char gap34[12];
SQInteger _len;
char gap34[4];
SQHash _hash;
SQChar _val[1];
static SQString* Create(SQSharedState* sharedstate, const SQChar* s, SQInteger len)

View File

@ -0,0 +1,56 @@
#ifndef SQTABLE_H
#define SQTABLE_H
#include "sqobject.h"
#include "sqstring.h"
#define hashptr(p) ((SQHash)(((SQInteger)((intp)p)) >> 3))
inline SQHash HashObj(const SQObjectPtr& key) // TODO: untested
{
switch (sq_type(key)) {
case OT_STRING: return _string(key)->_hash;
case OT_FLOAT: return (SQHash)((SQInteger)_float(key));
case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key));
default: return hashptr(key._unVal.pRefCounted);
}
}
struct SQTable : public SQDelegable
{
public:
struct _HashNode
{
_HashNode() { hash = NULL; prev = NULL; next = NULL; }
SQObjectPtr val;
SQObjectPtr key;
SQInteger hash;
SQShort prev;
SQShort next;
};
void _ClearNodes();
inline _HashNode* _Get(const SQObjectPtr& key, SQHash hash) // TODO: untested
{
_HashNode* n = &_nodes[hash];
do {
if (_rawval(n->key) == _rawval(key) && sq_type(n->key) == sq_type(key)) {
return n;
}
} while (n->hash != -1);
return NULL;
}
bool Get(const SQObjectPtr& key, SQObjectPtr& val);
_HashNode* _nodes;
SQInteger _numofnodes;
SQInteger _usednodes;
SQInteger _prev;
SQInteger _next;
SQInteger _last;
};
#define SQ_FOR_EACH_TABLE(tableName, iteratorName) \
for (int iteratorName = 0; iteratorName < tableName->_numofnodes; iteratorName++)
#endif // SQTABLE_H

View File

@ -1,7 +1,38 @@
#ifndef SQTYPE_H
#define SQTYPE_H
/*
Copyright (c) 2003-2009 Alberto Demichelis
This software is provided 'as-is', without any
express or implied warranty. In no event will the
authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software
for any purpose, including commercial applications,
and to alter it and redistribute it freely, subject
to the following restrictions:
1. The origin of this software must not be
misrepresented; you must not claim that
you wrote the original software. If you
use this software in a product, an
acknowledgment in the product
documentation would be appreciated but is
not required.
2. Altered source versions must be plainly
marked as such, and must not be
misrepresented as being the original
software.
3. This notice may not be removed or
altered from any source distribution.
*/
#ifndef _SQUIRREL_H_
#define _SQUIRREL_H_
#define SQ_OK (1)
#define SQ_FAIL (0)
#define SQ_ERROR (-1)
#define SQ_FAILED(res) (res<0)
#define SQ_SUCCEEDED(res) (res>=0)
@ -14,10 +45,17 @@
#define GET_FLAG_RAW 0x00000001
#define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002
typedef char SQChar;
typedef float SQFloat;
#define _SC(a) a
typedef long SQInteger;
typedef unsigned long SQUnsignedInteger;
typedef short SQShort;
typedef unsigned short SQUnsignedShort;
typedef uint64 SQHash; /*should be the same size of a pointer*/
typedef float SQFloat;
typedef void* SQFunctor;
typedef SQUnsignedInteger SQBool;
@ -28,32 +66,67 @@ typedef int ScriptDataType_t;
typedef struct SQVM* HSQUIRRELVM;
struct SQBufState;
typedef char SQChar;
struct SQString;
#define SQOBJECT_REF_COUNTED 0x08000000
#define SQOBJECT_NUMERIC 0x04000000
#define SQOBJECT_DELEGABLE 0x02000000
#define SQOBJECT_CANBEFALSE 0x01000000
#define SQ_MATCHTYPEMASKSTRING (-99999)
#define _RT_MASK 0x00FFFFFF
#define _RAW_TYPE(type) (type&_RT_MASK)
#define _RT_NULL 0x00000001
#define _RT_INTEGER 0x00000002
#define _RT_FLOAT 0x00000004
#define _RT_BOOL 0x00000008
#define _RT_STRING 0x00000010
#define _RT_TABLE 0x00000020
#define _RT_ARRAY 0x00000040
#define _RT_USERDATA 0x00000080
#define _RT_CLOSURE 0x00000100
#define _RT_NATIVECLOSURE 0x00000200
#define _RT_ASSET 0x00000400
#define _RT_USERPOINTER 0x00000800
#define _RT_THREAD 0x00001000
#define _RT_FUNCPROTO 0x00002000
#define _RT_CLASS 0x00004000
#define _RT_INSTANCE 0x00008000
#define _RT_WEAKREF 0x00010000
#define _RT_VECTOR 0x00040000
#define _RT_UNIMPLEMENTED 0x00080000
#define _RT_STRUCTDEF 0x00100000
#define _RT_STRUCTINSTANCE 0x00200000
#define _RT_ENTITY 0x00400000
typedef enum tagSQObjectType
{
OT_VECTOR = 0x40000,
OT_NULL = 0x1000001,
OT_INTEGER = 0x5000002,
OT_FLOAT = 0x5000004,
OT_BOOL = 0x1000008,
OT_STRING = 0x8000010,
OT_TABLE = 0xA000020,
OT_ARRAY = 0x8000040,
OT_USERDATA = 0xA000080,
OT_CLOSURE = 0x8000100,
OT_NATIVECLOSURE = 0x8000200,
OT_ASSET = 0x8000400,
OT_USERPOINTER = 0x800,
OT_THREAD = 0x8001000,
OT_FUNCPROTO = 0x8002000,
OT_CLASS = 0x8004000,
OT_STRUCT = 0x8200000,
OT_INSTANCE = 0xA008000,
OT_ENTITY = 0xA400000,
OT_WEAKREF = 0x8010000,
OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE),
OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),
OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),
OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE),
OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED),
OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),
OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED),
OT_VAR = NULL,
OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),
OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED),
OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED),
OT_ASSET = (_RT_ASSET|SQOBJECT_REF_COUNTED),
OT_USERPOINTER = _RT_USERPOINTER,
OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) ,
OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only
OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED),
OT_WEAKREF = (_RT_WEAKREF|SQOBJECT_REF_COUNTED),
OT_VECTOR = _RT_VECTOR,
OT_UNIMPLEMENTED = (_RT_UNIMPLEMENTED|SQOBJECT_REF_COUNTED),
OT_STRUCTDEF = (_RT_STRUCTDEF|SQOBJECT_REF_COUNTED),
OT_STRUCTINSTANCE = (_RT_STRUCTINSTANCE|SQOBJECT_REF_COUNTED),
OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),
OT_ENTITY = (_RT_ENTITY|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),
} SQObjectType;
// does the type keep track of references?
@ -84,21 +157,16 @@ typedef union tagSQObjectValue
typedef struct tagSQObject
{
SQObjectType _type;
SQInteger _pad;
SQObjectValue _unVal;
} SQObject;
template<typename T> class sqvector
{
public:
T* _vals;
SQUnsignedInteger _size;
SQUnsignedInteger _allocated;
};
///////////////////////////////////////////////////////////////////////////////
SQRESULT sq_pushroottable(HSQUIRRELVM v);
SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i);
SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i);
SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx);
SQInteger sq_gettop(HSQUIRRELVM v);
SQRESULT sq_pushroottable(HSQUIRRELVM v);
void sq_pushbool(HSQUIRRELVM v, SQBool b);
void sq_pushstring(HSQUIRRELVM v, const SQChar* string, SQInteger len);
@ -115,6 +183,26 @@ SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerr
SQRESULT sq_startconsttable(HSQUIRRELVM v);
SQRESULT sq_endconsttable(HSQUIRRELVM v);
/*UTILITY MACRO*/
#define sq_istable(o) ((o)._type==OT_TABLE)
#define sq_isarray(o) ((o)._type==OT_ARRAY)
#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO)
#define sq_isclosure(o) ((o)._type==OT_CLOSURE)
#define sq_isgenerator(o) ((o)._type==OT_GENERATOR)
#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE)
#define sq_isstring(o) ((o)._type==OT_STRING)
#define sq_isinteger(o) ((o)._type==OT_INTEGER)
#define sq_isfloat(o) ((o)._type==OT_FLOAT)
#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER)
#define sq_isuserdata(o) ((o)._type==OT_USERDATA)
#define sq_isthread(o) ((o)._type==OT_THREAD)
#define sq_isnull(o) ((o)._type==OT_NULL)
#define sq_isclass(o) ((o)._type==OT_CLASS)
#define sq_isinstance(o) ((o)._type==OT_INSTANCE)
#define sq_isbool(o) ((o)._type==OT_BOOL)
#define sq_isweakref(o) ((o)._type==OT_WEAKREF)
#define sq_type(o) ((o)._type)
/* ==== SQUIRREL ======================================================================================================================================================== */
inline SQRESULT(*v_sq_pushroottable)(HSQUIRRELVM v);
inline void(*v_sq_pushbool)(HSQUIRRELVM v, SQBool b);
@ -128,6 +216,7 @@ inline SQRESULT(*v_sq_arrayappend)(HSQUIRRELVM v, SQInteger idx);
inline SQRESULT(*v_sq_pushstructure)(HSQUIRRELVM v, const SQChar* name, const SQChar* member, const SQChar* codeclass1, const SQChar* codeclass2);
inline SQRESULT(*v_sq_compilebuffer)(HSQUIRRELVM v, SQBufState* bufferstate, const SQChar* buffer, SQInteger level);
inline SQRESULT(*v_sq_call)(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror);
inline SQRESULT(*v_sq_get)(HSQUIRRELVM v, SQInteger idx);
inline SQRESULT (*v_sq_startconsttable)(HSQUIRRELVM v);
inline SQRESULT (*v_sq_endconsttable)(HSQUIRRELVM v);
@ -151,6 +240,7 @@ class VSquirrelAPI : public IDetour
LogFunAdr("sq_pushstructure", v_sq_pushstructure);
LogFunAdr("sq_compilebuffer", v_sq_compilebuffer);
LogFunAdr("sq_call", v_sq_call);
LogFunAdr("sq_get", v_sq_get);
LogFunAdr("sq_startconsttable", v_sq_startconsttable);
LogFunAdr("sq_endconsttable", v_sq_endconsttable);
@ -171,6 +261,7 @@ class VSquirrelAPI : public IDetour
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 60 48 8B 59 60").GetPtr(v_sq_pushstructure);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 50 41 8B E9 49 8B F8").GetPtr(v_sq_compilebuffer);
g_GameDll.FindPatternSIMD("4C 8B DC 49 89 5B 08 49 89 6B 10 49 89 73 18 57 48 83 EC 50 8B F2").GetPtr(v_sq_call);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 48 8B F9 8B 49 78").GetPtr(v_sq_get);
g_GameDll.FindPatternSIMD("8B 51 78 4C 8B 49 60 44 8B C2 49 C1 E0 04 4C 03 81 ?? ?? ?? ?? 8D 42 01 89 41 78 41 F7 81 ?? ?? ?? ?? ?? ?? ?? ?? 74 0A 49 8B 81 ?? ?? ?? ?? FF 40 08 41 F7 00 ?? ?? ?? ?? 41 0F 10 81 ?? ?? ?? ?? 74 15").GetPtr(v_sq_startconsttable);
g_GameDll.FindPatternSIMD("8B 41 78 45 33 C0 FF C8 8B D0 89 41 78 48 C1 E2 04 48 03 91 ?? ?? ?? ?? 8B 02 48 C7 02 ?? ?? ?? ?? 25 ?? ?? ?? ?? 74 15").GetPtr(v_sq_endconsttable);
@ -182,4 +273,4 @@ class VSquirrelAPI : public IDetour
virtual void Detour(const bool bAttach) const;
};
///////////////////////////////////////////////////////////////////////////////
#endif // SQTYPE_H
#endif // _SQUIRREL_H_

View File

@ -0,0 +1,25 @@
/* see copyright notice in squirrel.h */
#ifndef _SQUTILS_H_
#define _SQUTILS_H_
template<typename T> class sqvector
{
private:
SQInteger _globalnum;
public:
T& top() const { return _vals[_size - 1]; }
inline SQUnsignedInteger size() const { return _size; }
bool empty() const { return (_size <= 0); }
SQUnsignedInteger capacity() { return _allocated; }
inline T& back() const { return _vals[_size - 1]; }
inline T& operator[](SQUnsignedInteger pos) const { return _vals[pos]; }
T* _vals;
private:
SQUnsignedInteger _size;
SQUnsignedInteger _allocated;
};
#endif //_SQUTILS_H_

View File

@ -3,6 +3,8 @@
#include "sqstate.h"
#include "sqobject.h"
class CSquirrelVM;
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
@ -14,45 +16,32 @@ enum class SQCONTEXT : SQInteger
NONE
};
struct SQVM
struct SQVM : public CHAINABLE_OBJ
{
SQVM* GetVTable() const
{
return _vftable;
}
SQCONTEXT GetContext() const
{
return _contextidx;
}
eDLL_T GetNativeContext() const
{
return (eDLL_T)GetContext();
}
void PrintObjVal(const SQObject& oin, SQObject& oout);
// push sqobjectptr on to the stack
inline void Push(const SQObjectPtr& o)
{
this->_stack._vals[_top++] = o;
}
void Push(const SQObjectPtr& o);
SQObjectPtr& Top();
SQObjectPtr& PopGet();
SQObjectPtr& GetUp(SQInteger n);
SQObjectPtr& GetAt(SQInteger n);
CSquirrelVM* GetScriptVM();
SQChar* GetContextName();
SQCONTEXT GetContext();
eDLL_T GetNativeContext();
// ================================= //
SQVM* _vftable;
_BYTE gap000[16];
SQCONTEXT _contextidx;
_BYTE gap001[8];
_BYTE gap002[4];
void* _ncvftable;
void* _table;
_BYTE gap003[14];
_BYTE gap1C[8];
void* _callstack;
int _unk;
int _bottom;
SQObjectPtr* _stackbase;
SQSharedState* _sharedstate;
char gap004[16];
char gap68[16];
int _top;
__int64 gap80;
sqvector<SQObjectPtr> _stack;
char gap_98[24];
SQObjectPtr temp_reg;
@ -69,6 +58,8 @@ struct SQVM
static_assert(offsetof(SQVM, _top) == 0x78);
static_assert(offsetof(SQVM, _nnativecalls) == 0x130);
inline SQObjectPtr& stack_get(HSQUIRRELVM v, SQInteger idx) { return ((idx >= 0) ? (v->_stackbase[idx-1]) : (v->GetUp(idx))); }
/* ==== SQUIRREL ======================================================================================================================================================== */
inline SQRESULT(*v_SQVM_PrintFunc)(HSQUIRRELVM v, SQChar* fmt, ...);
inline SQRESULT(*v_SQVM_sprintf)(HSQUIRRELVM v, SQInteger a2, SQInteger a3, SQInteger* nStringSize, SQChar** ppString);
@ -78,15 +69,12 @@ 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 SQBool(*v_SQVM_ThrowError)(__int64 a1, HSQUIRRELVM v);
inline void(*v_SQVM_PrintObjVal)(HSQUIRRELVM v, const SQObjectPtr& oin, const SQObjectPtr& oout);
SQRESULT SQVM_PrintFunc(HSQUIRRELVM v, SQChar* fmt, ...);
SQRESULT SQVM_sprintf(HSQUIRRELVM v, SQInteger a2, SQInteger a3, SQInteger* nStringSize, SQChar** ppString);
void SQVM_CompileError(HSQUIRRELVM v, const SQChar* pszError, const SQChar* pszFile, SQUnsignedInteger nLine, SQInteger nColumn);
const SQChar* SQVM_GetContextName(SQCONTEXT context);
const SQCONTEXT SQVM_GetContextIndex(HSQUIRRELVM v);
///////////////////////////////////////////////////////////////////////////////
class VSquirrelVM : public IDetour
{
@ -100,7 +88,7 @@ class VSquirrelVM : public IDetour
LogFunAdr("SQVM_LogicError", v_SQVM_LogicError);
LogFunAdr("SQVM_ScriptError", v_SQVM_ScriptError);
LogFunAdr("SQVM_RaiseError", v_SQVM_RaiseError);
LogFunAdr("SQVM_ThrowError", v_SQVM_ThrowError);
LogFunAdr("SQVM_PrintObjVal", v_SQVM_PrintObjVal);
}
virtual void GetFun(void) const
{
@ -112,7 +100,7 @@ class VSquirrelVM : public IDetour
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 48 8B D9 4C 8B F2").GetPtr(v_SQVM_CompileError);
g_GameDll.FindPatternSIMD("E9 ?? ?? ?? ?? F7 D2").FollowNearCallSelf().GetPtr(v_SQVM_ScriptError);
g_GameDll.FindPatternSIMD("48 89 54 24 ?? 4C 89 44 24 ?? 4C 89 4C 24 ?? 53 56 57 48 83 EC 40").GetPtr(v_SQVM_RaiseError);
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? BB ?? ?? ?? ?? 8B C3").FollowNearCallSelf().GetPtr(v_SQVM_ThrowError);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ? 55 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 50 45 33 ED").GetPtr(v_SQVM_PrintObjVal);
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }

View File

@ -7,20 +7,63 @@
#include "core/stdafx.h"
#include "squirrel.h"
#include "sqvm.h"
#include "sqarray.h"
#include "sqstring.h"
//---------------------------------------------------------------------------------
SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i)
bool sq_aux_gettypedarg(HSQUIRRELVM v, SQInteger idx, SQObjectType type, SQObjectPtr** o)
{
*o = &stack_get(v, idx);
if (sq_type(**o) != type) {
SQObjectPtr oval;
v->PrintObjVal(**o, oval);
v_SQVM_RaiseError(v, _SC("wrong argument type, expected '%s' got '%.50s'"), IdType2Name(type), _stringval(oval));
return false;
}
return true;
}
//---------------------------------------------------------------------------------
#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; }
#define sq_aux_paramscheck(v,count) \
{ \
if(sq_gettop(v) < count){ v_SQVM_RaiseError(v, _SC("not enough params in the stack")); return SQ_ERROR; }\
}
//---------------------------------------------------------------------------------
SQChar* sq_getstring(HSQUIRRELVM v, SQInteger i) // TODO: deprecate and remove!
{
return v->_stackbase[i]._unVal.pString->_val;
}
//---------------------------------------------------------------------------------
SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c)
{
SQObjectPtr* o = NULL;
_GETSAFE_OBJ(v, idx, OT_STRING, o);
*c = _stringval(*o);
return SQ_OK;
}
//---------------------------------------------------------------------------------
SQInteger sq_getinteger(HSQUIRRELVM v, SQInteger i)
{
return v->_stackbase[i]._unVal.nInteger;
}
//---------------------------------------------------------------------------------
SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)
{
return v_sq_get(v, idx);
}
//---------------------------------------------------------------------------------
SQInteger sq_gettop(HSQUIRRELVM v)
{
return (v->_top - v->_bottom);
}
//---------------------------------------------------------------------------------
SQRESULT sq_pushroottable(HSQUIRRELVM v)
{

View File

@ -0,0 +1,10 @@
/*
see copyright notice in squirrel.h
*/
#include "sqvm.h"
#include "sqstring.h"
void SQVM::PrintObjVal(const SQObject& oin, SQObject& oout)
{
v_SQVM_PrintObjVal(this, oin, oout);
}

View File

@ -0,0 +1,12 @@
/*
see copyright notice in squirrel.h
*/
//#include "sqpcheader.h"
// TODO: commented because we need to hook up globals '14D4F3900' and '14D4F38F8', which is used for
// the global memory management of the squirrel implementation in this game
//void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); }
//void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); }
//void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); }

View File

@ -2,6 +2,39 @@
#include "sqobject.h"
#include "sqstring.h"
const SQChar* IdType2Name(const SQObjectType type)
{
switch (type)
{
case OT_NULL:return _SC("null");
case OT_INTEGER:return _SC("int");
case OT_FLOAT:return _SC("float");
case OT_BOOL:return _SC("bool");
case OT_STRING:return _SC("string");
case OT_TABLE:return _SC("table");
case OT_VAR:return _SC("var");
case OT_ARRAY:return _SC("array");
case OT_CLOSURE: return _SC("function");
case OT_THREAD: return _SC("thread");
case OT_FUNCPROTO: return _SC("function");
case OT_UNIMPLEMENTED: return _SC("unimplemented function");
case OT_CLASS: return _SC("class");
case OT_INSTANCE: return _SC("instance");
case OT_WEAKREF: return _SC("weakref");
case OT_VECTOR: return _SC("vector");
case OT_ASSET: return _SC("asset");
case OT_STRUCTDEF: return _SC("structdef");
case OT_STRUCTINSTANCE: return _SC("struct instance");
case OT_ENTITY: return _SC("entity");
default:
const int ival = (int)type;
if (ival == SQOBJECT_NUMERIC) return _SC("float or int");
if (ival == _RT_USERDATA || ival == _RT_USERPOINTER) return _SC("userdata");
return NULL;
}
}
SQRefCounted::~SQRefCounted()
{
if (_weakref) {
@ -9,13 +42,3 @@ SQRefCounted::~SQRefCounted()
_weakref->_unVal.pRefCounted = NULL;
}
}
const char* SQObjectPtr::GetCString() const
{
//assert(_type == OT_STRING);
if (_type == OT_STRING)
return _unVal.pString->_val;
else
return "(unknown)";
}

View File

@ -0,0 +1,19 @@
#include "sqtable.h"
void SQTable::_ClearNodes()
{
for (SQInteger i = 0; i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; }
}
// TODO: untested
bool SQTable::Get(const SQObjectPtr& key, SQObjectPtr& val)
{
if (sq_type(key) == OT_NULL)
return false;
_HashNode* n = _Get(key, HashObj(key) & (_numofnodes - 1));
if (n) {
val = _realval(n->val);
return true;
}
return false;
}

View File

@ -147,15 +147,13 @@ SQRESULT SQVM_sprintf(HSQUIRRELVM v, SQInteger a2, SQInteger a3, SQInteger* nStr
//---------------------------------------------------------------------------------
void SQVM_CompileError(HSQUIRRELVM v, const SQChar* pszError, const SQChar* pszFile, SQUnsignedInteger nLine, SQInteger nColumn)
{
static SQCONTEXT context{};
static char szContextBuf[256]{};
context = v->GetContext();
v_SQVM_GetErrorLine(pszFile, nLine, szContextBuf, sizeof(szContextBuf) - 1);
Error(static_cast<eDLL_T>(context), NO_ERROR, "%s SCRIPT COMPILE ERROR: %s\n", SQVM_GetContextName(context), pszError);
Error(static_cast<eDLL_T>(context), NO_ERROR, " -> %s\n\n", szContextBuf);
Error(static_cast<eDLL_T>(context), NO_ERROR, "%s line [%d] column [%d]\n", pszFile, nLine, nColumn);
const eDLL_T context = v->GetNativeContext();
Error(context, NO_ERROR, "%s SCRIPT COMPILE ERROR: %s\n", v->GetContextName(), pszError);
Error(context, NO_ERROR, " -> %s\n\n", szContextBuf);
Error(context, NO_ERROR, "%s line [%d] column [%d]\n", pszFile, nLine, nColumn);
}
//---------------------------------------------------------------------------------
@ -176,41 +174,31 @@ void SQVM_LogicError(SQBool bPrompt)
v_SQVM_LogicError(bPrompt);
}
//---------------------------------------------------------------------------------
// Purpose: Returns the VM name by context
// Input : context -
// Output : const SQChar*
//---------------------------------------------------------------------------------
const SQChar* SQVM_GetContextName(SQCONTEXT context)
void SQVM::Push(const SQObjectPtr& o) { _stack[_top++] = o; }
SQObjectPtr& SQVM::Top() { return _stack[_top - 1]; }
SQObjectPtr& SQVM::PopGet() { return _stack[--_top]; }
SQObjectPtr& SQVM::GetUp(SQInteger n) { return _stack[_top + n]; }
SQObjectPtr& SQVM::GetAt(SQInteger n) { return _stack[n]; }
#include "vscript/languages/squirrel_re/vsquirrel.h"
CSquirrelVM* SQVM::GetScriptVM()
{
switch (context)
{
case SQCONTEXT::SERVER:
return "SERVER";
case SQCONTEXT::CLIENT:
return "CLIENT";
case SQCONTEXT::UI:
return "UI";
default:
return nullptr;
}
return _sharedstate->GetScriptVM();
}
//---------------------------------------------------------------------------------
// Purpose: Returns the VM context by name
// Input : *sqvm -
// Output : const SQCONTEXT*
//---------------------------------------------------------------------------------
const SQCONTEXT SQVM_GetContextIndex(HSQUIRRELVM v)
SQChar* SQVM::GetContextName()
{
if (strcmp(v->_sharedstate->_contextname, "SERVER") == 0)
return SQCONTEXT::SERVER;
if (strcmp(v->_sharedstate->_contextname, "CLIENT") == 0)
return SQCONTEXT::CLIENT;
if (strcmp(v->_sharedstate->_contextname, "UI") == 0)
return SQCONTEXT::UI;
return _sharedstate->_contextname;
}
return SQCONTEXT::NONE;
SQCONTEXT SQVM::GetContext()
{
return GetScriptVM()->GetContext();
}
eDLL_T SQVM::GetNativeContext()
{
return (eDLL_T)GetContext();
}
//---------------------------------------------------------------------------------

View File

@ -13,6 +13,11 @@ void(*ServerScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*ClientScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*UiScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
// Callbacks for registering script enums.
void(*ServerScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
void(*ClientScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
void(*UIScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
// Admin panel functions, NULL on client only builds.
void(*CoreServerScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*AdminPanelScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
@ -159,7 +164,7 @@ void CSquirrelVM::CompileModScripts()
RSON::Node_t* rson = mod->LoadScriptCompileList();
if (!rson)
Error(GetVM()->GetNativeContext(), NO_ERROR,
Error(GetNativeContext(), NO_ERROR,
"%s: Failed to load RSON file '%s'\n",
__FUNCTION__, mod->GetScriptCompileListPath().Get());
@ -197,7 +202,7 @@ void CSquirrelVM::CompileModScripts()
scriptPathArray[j] = pszScriptPath;
}
switch (GetVM()->GetContext())
switch (GetContext())
{
case SQCONTEXT::SERVER:
{

View File

@ -23,6 +23,7 @@ public:
FORCEINLINE HSQUIRRELVM GetVM() const { return m_sqVM; }
FORCEINLINE SQCONTEXT GetContext() const { return m_iContext; }
FORCEINLINE eDLL_T GetNativeContext() const { return (eDLL_T)GetContext(); }
private:
SQChar pad0[0x8];
@ -42,6 +43,10 @@ extern void(*ServerScriptRegister_Callback)(CSquirrelVM* s);
extern void(*ClientScriptRegister_Callback)(CSquirrelVM* s);
extern void(*UiScriptRegister_Callback)(CSquirrelVM* s);
extern void(*ServerScriptRegisterEnum_Callback)(CSquirrelVM* const s);
extern void(*ClientScriptRegisterEnum_Callback)(CSquirrelVM* const s);
extern void(*UIScriptRegisterEnum_Callback)(CSquirrelVM* const s);
extern void(*CoreServerScriptRegister_Callback)(CSquirrelVM* s);
extern void(*AdminPanelScriptRegister_Callback)(CSquirrelVM* s);
@ -60,6 +65,8 @@ inline bool(*CSquirrelVM__PrecompileClientScripts)(CSquirrelVM* vm, SQCONTEXT co
inline bool(*CSquirrelVM__PrecompileServerScripts)(CSquirrelVM* vm, SQCONTEXT context, char** scriptArray, int scriptCount);
#endif
inline bool(*CSquirrelVM__ThrowError)(CSquirrelVM* vm, HSQUIRRELVM v);
#ifndef CLIENT_DLL
inline CSquirrelVM* g_pServerScript;
#endif // !CLIENT_DLL
@ -70,24 +77,30 @@ inline CSquirrelVM* g_pUIScript;
#endif // !DEDICATED
#define DEFINE_SCRIPTENUM_NAMED(s, enumName, startValue, ...) \
do { \
HSQUIRRELVM const v = s->GetVM(); \
const eDLL_T context = static_cast<eDLL_T>(s->GetContext());\
sq_startconsttable(v); \
sq_pushstring(v, enumName, -1); \
sq_newtable(v); \
const char* const enumFields[] = { __VA_ARGS__ }; \
int enumValue = startValue; \
for (int i = 0; i < V_ARRAYSIZE(enumFields); i++) { \
sq_pushstring(v, enumFields[i], -1); \
sq_pushinteger(v, enumValue++); \
if (sq_newslot(v, -3) < 0) \
Error(context, EXIT_FAILURE, "Error adding entry '%s' for enum '%s'.", enumFields[i], enumName); \
} \
HSQUIRRELVM const v = s->GetVM(); \
const eDLL_T context = static_cast<eDLL_T>(s->GetContext());\
sq_startconsttable(v); \
sq_pushstring(v, enumName, -1); \
sq_newtable(v); \
const char* const enumFields[] = { __VA_ARGS__ }; \
int enumValue = startValue; \
for (int i = 0; i < V_ARRAYSIZE(enumFields); i++) { \
sq_pushstring(v, enumFields[i], -1); \
sq_pushinteger(v, enumValue++); \
if (sq_newslot(v, -3) < 0) \
Error(context, EXIT_FAILURE, "Error adding enum '%s' to const table.", enumName); \
sq_endconsttable(v); \
} while (0)
Error(context, EXIT_FAILURE, "Error adding entry '%s' for enum '%s'.", enumFields[i], enumName); \
} \
if (sq_newslot(v, -3) < 0) \
Error(context, EXIT_FAILURE, "Error adding enum '%s' to const table.", enumName); \
sq_endconsttable(v); \
// Place this at the end of every script func
#define SCRIPT_CHECK_INTERNAL_ERROR(v) \
SQSharedState* const sharedState = v->_sharedstate; \
if (sharedState->_internal_error) { \
CSquirrelVM__ThrowError(sharedState->_scriptvm, v); \
return SQ_ERROR; \
}
///////////////////////////////////////////////////////////////////////////////
class VSquirrel : public IDetour
@ -105,6 +118,7 @@ class VSquirrel : public IDetour
#ifndef DEDICATED
LogFunAdr("CSquirrelVM::PrecompileClientScripts", CSquirrelVM__PrecompileClientScripts);
#endif // !DEDICATED
LogFunAdr("CSquirrelVM::ThrowError", CSquirrelVM__ThrowError);
}
virtual void GetFun(void) const
{
@ -122,6 +136,7 @@ class VSquirrel : public IDetour
// cl/ui scripts.rson compiling
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 44 0F B6 F0 48 85 DB").FollowNearCallSelf().GetPtr(CSquirrelVM__PrecompileClientScripts);
#endif
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? BB ?? ?? ?? ?? 8B C3").FollowNearCallSelf().GetPtr(CSquirrelVM__ThrowError);
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }

View File

@ -12,6 +12,8 @@
#include "game/shared/vscript_shared.h"
#include "pluginsystem/modsystem.h"
static const char* s_scriptContextNames[] = { "SERVER", "CLIENT", "UI", "NONE" };
//---------------------------------------------------------------------------------
// Purpose: Returns the script VM pointer by context
// Input : context -
@ -130,7 +132,9 @@ SQBool Script_PrecompileClientScripts(CSquirrelVM* vm)
//---------------------------------------------------------------------------------
void Script_Execute(const SQChar* code, const SQCONTEXT context)
{
if (!ThreadInMainThread())
Assert(context != SQCONTEXT::NONE);
if (!ThreadInMainThread()) // TODO[ AMOS ]: server frame thread
{
const string scode(code);
g_TaskQueue.Dispatch([scode, context]()
@ -142,16 +146,18 @@ void Script_Execute(const SQChar* code, const SQCONTEXT context)
}
CSquirrelVM* s = Script_GetScriptHandle(context);
const char* const contextName = s_scriptContextNames[(int)context];
if (!s)
{
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script with no handle to VM\n", SQVM_GetContextName(context));
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script with no handle to VM\n", contextName);
return;
}
HSQUIRRELVM v = s->GetVM();
if (!v)
{
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", SQVM_GetContextName(context));
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", contextName);
return;
}
@ -165,7 +171,7 @@ void Script_Execute(const SQChar* code, const SQCONTEXT context)
if (!SQ_SUCCEEDED(callResult))
{
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to execute %s script \"%s\"\n", SQVM_GetContextName(context), code);
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to execute %s script \"%s\"\n", contextName, code);
}
}
}