diff --git a/r5dev/game/shared/vscript_shared.cpp b/r5dev/game/shared/vscript_shared.cpp index 646955ba..46dcd47d 100644 --- a/r5dev/game/shared/vscript_shared.cpp +++ b/r5dev/game/shared/vscript_shared.cpp @@ -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(&v->_sharedstate->gap43b9[127])) - { - v_SQVM_ThrowError(*reinterpret_cast(&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); +} diff --git a/r5dev/game/shared/vscript_shared.h b/r5dev/game/shared/vscript_shared.h index e5e87593..dd57ef08 100644 --- a/r5dev/game/shared/vscript_shared.h +++ b/r5dev/game/shared/vscript_shared.h @@ -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(); } virtual void GetCon(void) const { } - virtual void Detour(const bool bAttach) const { } + virtual void Detour(const bool bAttach) const; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/vscript/CMakeLists.txt b/r5dev/vscript/CMakeLists.txt index 7697e2cc..f7c28ec1 100644 --- a/r5dev/vscript/CMakeLists.txt +++ b/r5dev/vscript/CMakeLists.txt @@ -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" ) diff --git a/r5dev/vscript/languages/squirrel_re/include/sqarray.h b/r5dev/vscript/languages/squirrel_re/include/sqarray.h new file mode 100644 index 00000000..140cba3a --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/include/sqarray.h @@ -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_ diff --git a/r5dev/vscript/languages/squirrel_re/include/sqfuncstate.h b/r5dev/vscript/languages/squirrel_re/include/sqfuncstate.h index 3f2a9128..5c7f6d1f 100644 --- a/r5dev/vscript/languages/squirrel_re/include/sqfuncstate.h +++ b/r5dev/vscript/languages/squirrel_re/include/sqfuncstate.h @@ -7,7 +7,7 @@ struct SQFuncState { - _BYTE gap0[17408]; + _BYTE gap0[17400]; sqvector _instructions; _BYTE gap4418[88]; SQObjectPtr _sourcename; diff --git a/r5dev/vscript/languages/squirrel_re/include/sqobject.h b/r5dev/vscript/languages/squirrel_re/include/sqobject.h index 42b88dbc..4385f0bc 100644 --- a/r5dev/vscript/languages/squirrel_re/include/sqobject.h +++ b/r5dev/vscript/languages/squirrel_re/include/sqobject.h @@ -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 \ No newline at end of file +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 SQObjectPtrVec; +typedef sqvector SQIntVec; + +const SQChar* IdType2Name(const SQObjectType type); + +#endif //_SQOBJECT_H_ diff --git a/r5dev/vscript/languages/squirrel_re/include/sqstate.h b/r5dev/vscript/languages/squirrel_re/include/sqstate.h index 15dd96a1..1adbf85a 100644 --- a/r5dev/vscript/languages/squirrel_re/include/sqstate.h +++ b/r5dev/vscript/languages/squirrel_re/include/sqstate.h @@ -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 { diff --git a/r5dev/vscript/languages/squirrel_re/include/sqstring.h b/r5dev/vscript/languages/squirrel_re/include/sqstring.h index d9a94362..9ed30439 100644 --- a/r5dev/vscript/languages/squirrel_re/include/sqstring.h +++ b/r5dev/vscript/languages/squirrel_re/include/sqstring.h @@ -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) diff --git a/r5dev/vscript/languages/squirrel_re/include/sqtable.h b/r5dev/vscript/languages/squirrel_re/include/sqtable.h new file mode 100644 index 00000000..8b0fd1f3 --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/include/sqtable.h @@ -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 diff --git a/r5dev/vscript/languages/squirrel_re/include/squirrel.h b/r5dev/vscript/languages/squirrel_re/include/squirrel.h index 48b09195..7e650d4c 100644 --- a/r5dev/vscript/languages/squirrel_re/include/squirrel.h +++ b/r5dev/vscript/languages/squirrel_re/include/squirrel.h @@ -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 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_ diff --git a/r5dev/vscript/languages/squirrel_re/include/squtils.h b/r5dev/vscript/languages/squirrel_re/include/squtils.h new file mode 100644 index 00000000..c792fba1 --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/include/squtils.h @@ -0,0 +1,25 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQUTILS_H_ +#define _SQUTILS_H_ + +template 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_ diff --git a/r5dev/vscript/languages/squirrel_re/include/sqvm.h b/r5dev/vscript/languages/squirrel_re/include/sqvm.h index a5c43cad..9d38afa9 100644 --- a/r5dev/vscript/languages/squirrel_re/include/sqvm.h +++ b/r5dev/vscript/languages/squirrel_re/include/sqvm.h @@ -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 _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 { } diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp index 0b2f7655..fafb1b54 100644 --- a/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp @@ -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) { diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqdebug.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqdebug.cpp new file mode 100644 index 00000000..de368561 --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqdebug.cpp @@ -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); +} diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqmem.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqmem.cpp new file mode 100644 index 00000000..ad984e04 --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqmem.cpp @@ -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); } diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqobject.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqobject.cpp index 1f7e574b..f7ebd0bb 100644 --- a/r5dev/vscript/languages/squirrel_re/squirrel/sqobject.cpp +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqobject.cpp @@ -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)"; -} \ No newline at end of file diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqtable.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqtable.cpp new file mode 100644 index 00000000..2eb882a4 --- /dev/null +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqtable.cpp @@ -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; +} diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqvm.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqvm.cpp index ec54c900..ae478ea1 100644 --- a/r5dev/vscript/languages/squirrel_re/squirrel/sqvm.cpp +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqvm.cpp @@ -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(context), NO_ERROR, "%s SCRIPT COMPILE ERROR: %s\n", SQVM_GetContextName(context), pszError); - Error(static_cast(context), NO_ERROR, " -> %s\n\n", szContextBuf); - Error(static_cast(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(); } //--------------------------------------------------------------------------------- diff --git a/r5dev/vscript/languages/squirrel_re/vsquirrel.cpp b/r5dev/vscript/languages/squirrel_re/vsquirrel.cpp index 416f563f..be006df5 100644 --- a/r5dev/vscript/languages/squirrel_re/vsquirrel.cpp +++ b/r5dev/vscript/languages/squirrel_re/vsquirrel.cpp @@ -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: { diff --git a/r5dev/vscript/languages/squirrel_re/vsquirrel.h b/r5dev/vscript/languages/squirrel_re/vsquirrel.h index 2a45d061..45db493c 100644 --- a/r5dev/vscript/languages/squirrel_re/vsquirrel.h +++ b/r5dev/vscript/languages/squirrel_re/vsquirrel.h @@ -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(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(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 { } diff --git a/r5dev/vscript/vscript.cpp b/r5dev/vscript/vscript.cpp index 39ca5e03..ababaf01 100644 --- a/r5dev/vscript/vscript.cpp +++ b/r5dev/vscript/vscript.cpp @@ -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); } } }