diff --git a/asm.h b/asm.h new file mode 100644 index 00000000..73a97a4e --- /dev/null +++ b/asm.h @@ -0,0 +1 @@ +#define SECTION(index, address) ".section h"#index"; .set h"#index","#address";" \ No newline at end of file diff --git a/hooks/GetTableSize.cpp b/hooks/GetTableSize.cpp deleted file mode 100644 index b201a87a..00000000 --- a/hooks/GetTableSize.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "../define.h" -asm( - ".section h0; .set h0,0x9283B1;" - "JMP "QU(RegTableFuncs)";" -); \ No newline at end of file diff --git a/hooks/TableFuncs.hook b/hooks/TableFuncs.hook new file mode 100644 index 00000000..106a422b --- /dev/null +++ b/hooks/TableFuncs.hook @@ -0,0 +1,2 @@ +0x0090AB1F: + call @lua_openlibtable \ No newline at end of file diff --git a/section/GetTableSize.cpp b/section/GetTableSize.cpp deleted file mode 100644 index baecc4ff..00000000 --- a/section/GetTableSize.cpp +++ /dev/null @@ -1,142 +0,0 @@ -void GetTableSize() -{ - asm( - "MOV EAX,[ESI+0xC];" - "CMP EAX,[ESI+0x8];" - "JAE Err;" - "CMP DWORD PTR [EAX],0x5;" - "JNE Err;" - "MOV EAX,[EAX+0x4];" - "XOR EBX,EBX;" - "MOV CL,[EAX+0x9];" - "TEST CL,CL;" - "JZ GTS_L2;" - "MOV EDX,1;" - "SHL EDX,CL;" - "MOV ECX,[EAX+0x14];" - "GTS_L3:;" - "CMP DWORD PTR [ECX+0x8],0x0;" - "JE GTS_L4;" - "ADD EBX,0x1;" - "GTS_L4:;" - "ADD ECX,0x14;" - "DEC EDX;" - "JNZ GTS_L3;" - "GTS_L2:;" - "MOV EDX,[EAX+0x20];" - "TEST EDX,EDX;" - "JZ GTS_L7;" - "MOV ECX,[EAX+0x10];" - "GTS_L5:;" - "CMP DWORD PTR [ECX],0x0;" - "JE GTS_L6;" - "ADD EBX,0x1;" - "GTS_L6:;" - "ADD ECX,0x8;" - "DEC EDX;" - "JNZ GTS_L5;" - "GTS_L7:;" - "CVTSI2SS XMM0,EBX;" - "SUB ESP,0x4;" - "MOVSS [ESP],XMM0;" - "PUSH ESI;" - "CALL 0x0090CD40;" //PushNumber - "ADD ESP,0x8;" - "MOV EAX,0x1;" - "RET;" - "Err:;" - "XOR EAX,EAX;" - ); -} - -void IsTableEmpty() -{ - asm( - "MOV EAX,[ESI+0xC];" - "CMP EAX,[ESI+0x8];" - "JAE ITE_L72;" - "CMP DWORD PTR [EAX],0x5;" - "JNE ITE_L72;" - "MOV EAX,[EAX+0x4];" - "MOV CL,[EAX+0x9];" - "TEST CL,CL;" - "JZ ITE_L22;" - "MOV EDX,1;" - "SHL EDX,CL;" - "MOV ECX,[EAX+0x14];" - "ITE_L32:;" - "CMP DWORD PTR [ECX+0x8],0x0;" - "JNE ITE_L62;" - "ADD ECX,0x14;" - "DEC EDX;" - "JNZ ITE_L32;" - "ITE_L22:;" - "MOV EDX,[EAX+0x20];" - "TEST EDX,EDX;" - "JZ ITE_L72;" - "MOV ECX,[EAX+0x10];" - "ITE_L5:;" - "CMP DWORD PTR [ECX],0x0;" - "JNE ITE_L62;" - "ADD ECX,0x8;" - "DEC EDX;" - "JNZ ITE_L5;" - "ITE_L72:;" - "PUSH 0x1;" - "JMP ITE_L12;" - "ITE_L62:;" - "PUSH 0x0;" - "ITE_L12:;" - "PUSH ESI;" - "CALL 0x0090CF80;" //PushBool - "ADD ESP,0x8;" - "MOV EAX,0x1;" - ); -} - -#include "LuaAPI.h" -int TableClone(lua_State* L) -{ - LuaObject obj{L->LuaState, 1}; - LuaObject cloned{}; - obj.Clone(&cloned); - cloned.PushStack(L); - return 1; -} - -// UI_Lua reprsl({table.unpack2({1,2,3,4},2,3)}) -// UI_Lua reprsl({table.unpack2({1,2,3,4},2)}) -// UI_Lua reprsl({table.unpack2({1,2,3,4})}) -// UI_Lua reprsl({table.unpack2({1,2,3,4},-1)}) -// UI_Lua reprsl({table.unpack2({1,2,3,4},-1000)}) -// UI_Lua reprsl({table.unpack2({1,2,3,4},0, 1000000)}) //stack overflow - -int lua_unpack(lua_State *l) { - luaL_checktype(l, 1, LUA_TTABLE); - const int n = lua_getn(l, 1); - const int start_i = luaL_optnumber(l, 2, 1); - const int end_i = luaL_optnumber(l, 3, n); - if(start_i > end_i) return 0; - - const int n_stack = end_i - start_i + 1; - luaL_checkstack(l, n_stack, "too many results to unpack"); - for (int i = start_i; i <= end_i; i++) { - lua_rawgeti(l, 1, i); - } - return n_stack; -} - -int RegTableFuncsDesc[] = {"getsize2",&GetTableSize, "empty2", &IsTableEmpty, - "getn2", 0x00927C20, "clone", &TableClone, - "unpack", &lua_unpack, 0, 0}; - -void RegTableFuncs() { - asm("CALL 0x0090DE00;" - "MOV DWORD PTR [ESP+0x8],%[RegTableFuncsDesc];" - "MOV DWORD PTR [ESP+0xC],0x0;" - "CALL 0x0090DE00;" - "JMP 0x009283B6;" - : - : [RegTableFuncsDesc] "i"(RegTableFuncsDesc) - :); -} \ No newline at end of file diff --git a/section/Lua/TableFuncs.cpp b/section/Lua/TableFuncs.cpp new file mode 100644 index 00000000..8053466d --- /dev/null +++ b/section/Lua/TableFuncs.cpp @@ -0,0 +1,177 @@ +#include +namespace lua +{ + struct TObject + { + int tt; + void *value; + }; + + struct Node + { + TObject i_key; + TObject i_val; + Node *next; + }; + + struct Table + { + /* lua::GCObject*/ void *next; + uint8_t tt; + uint8_t marked; + uint16_t gap; + uint8_t flags; + uint8_t lsizenode; + // padding byte + // padding byte + Table *metatable; + TObject *array; + lua::Node *node; + lua::Node *firstfree; + /*lua::GCObject*/ void *gclist; + int sizearray; + }; + +} // namespace lua + +VALIDATE_SIZE(lua::Table, 0x24); + +int lua_tablesize(lua_State *L) +{ + int size = 0; + auto base = GetField(L, 0xC); + auto top = GetField(L, 0x8); + if (base >= top || base->tt != LUA_TTABLE) + { + lua_pushnumber(L, size); + return 1; + } + + auto table = (lua::Table *)base->value; + uint8_t lsizenode = table->lsizenode; + if (lsizenode) + { + uint32_t num_nodes = 1 << lsizenode; + auto node = table->node; + do + { + if (node->i_val.tt) + ++size; + ++node; + --num_nodes; + } while (num_nodes); + } + int sizearray = table->sizearray; + if (sizearray) + { + auto array = table->array; + do + { + if (array->tt) + ++size; + ++array; + --sizearray; + } while (sizearray); + } + + lua_pushnumber(L, size); + return 1; +} + +int lua_tableempty(lua_State *L) +{ + auto base = GetField(L, 0xC); + auto top = GetField(L, 0x8); + if (base >= top || base->tt != LUA_TTABLE) + { + lua_pushboolean(L, true); + return 1; + } + + auto table = (lua::Table *)base->value; + constexpr auto has_nodes = [](lua::Table *t) + { + uint8_t lsizenode = t->lsizenode; + if (!lsizenode) + return false; + + uint32_t num_nodes = 1 << lsizenode; + auto node = t->node; + while (node->i_val.tt == LUA_TNIL) + { + ++node; + if (!--num_nodes) + return false; + } + return true; + }; + + constexpr auto has_array = [](lua::Table *t) + { + int sizearray = t->sizearray; + if (!sizearray) + return false; + + auto array = t->array; + while (array->tt == LUA_TNIL) + { + ++array; + if (!--sizearray) + return false; + } + return true; + }; + + lua_pushboolean(L, !(has_nodes(table) || has_array(table))); + return 1; +} + +int TableClone(lua_State *L) +{ + LuaObject obj{L->LuaState, 1}; + LuaObject cloned{}; + obj.Clone(&cloned); + cloned.PushStack(L); + return 1; +} + +// UI_Lua reprsl({table.unpack2({1,2,3,4},2,3)}) +// UI_Lua reprsl({table.unpack2({1,2,3,4},2)}) +// UI_Lua reprsl({table.unpack2({1,2,3,4})}) +// UI_Lua reprsl({table.unpack2({1,2,3,4},-1)}) +// UI_Lua reprsl({table.unpack2({1,2,3,4},-1000)}) +// UI_Lua reprsl({table.unpack2({1,2,3,4},0, 1000000)}) //stack overflow + +int lua_unpack(lua_State *l) +{ + luaL_checktype(l, 1, LUA_TTABLE); + const int n = lua_getn(l, 1); + const int start_i = luaL_optnumber(l, 2, 1); + const int end_i = luaL_optnumber(l, 3, n); + if (start_i > end_i) + return 0; + + const int n_stack = end_i - start_i + 1; + luaL_checkstack(l, n_stack, "too many results to unpack"); + for (int i = start_i; i <= end_i; i++) + { + lua_rawgeti(l, 1, i); + } + return n_stack; +} + +const luaL_reg RegTableFuncsDesc[] = {{"getsize2", &lua_tablesize}, + {"empty2", &lua_tableempty}, + {"getn2", (lua_CFunction)0x00927C20}, + {"clone", &TableClone}, + {"unpack", &lua_unpack}, + {nullptr, nullptr}}; + +extern const luaL_reg original_table_funcs[] asm("0x00D47418"); + +int __cdecl lua_openlibtable(lua_State *L) +{ + luaL_openlib(L, "table", original_table_funcs, 0); + luaL_openlib(L, "table", RegTableFuncsDesc, 0); + return 1; +} \ No newline at end of file