Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

523 рядки
15 KiB

  1. #include "BL3Lua.h"
  2. #include "LuaUtility.h"
  3. #include "include/patternscan.hpp"
  4. int lua_exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description) {
  5. // L is the lua state, which you can wrap in a state_view if necessary
  6. // maybe_exception will contain exception, if it exists
  7. // description will either be the what() of the exception or a description saying that we hit the general-case catch(...)
  8. std::cout << "An exception occurred in a function, here's what it says ";
  9. if (maybe_exception) {
  10. std::cout << "(straight from the exception): ";
  11. const std::exception& ex = *maybe_exception;
  12. std::cout << ex.what() << std::endl;
  13. }
  14. else {
  15. std::cout << "(from the description parameter): ";
  16. std::cout.write(description.data(), static_cast<std::streamsize>(description.size()));
  17. std::cout << std::endl;
  18. }
  19. // you must push 1 element onto the stack to be
  20. // transported through as the error object in Lua
  21. // note that Lua -- and 99.5% of all Lua users and libraries -- expects a string
  22. // so we push a single string (in our case, the description of the error)
  23. return sol::stack::push(L, description);
  24. }
  25. inline void my_panic(sol::optional<std::string> maybe_msg) {
  26. std::cerr << "Lua is in a panic state and will now abort() the application" << std::endl;
  27. if (maybe_msg) {
  28. const std::string& msg = maybe_msg.value();
  29. std::cerr << "\terror message: " << msg << std::endl;
  30. }
  31. // When this function exits, Lua will exhibit default behavior and abort()
  32. }
  33. BL3Lua::BL3Lua()
  34. {
  35. InitializeCriticalSection(&luaCritSec);
  36. /*InitializeCriticalSection(&procEventCritSec);
  37. InitializeCriticalSection(&consoleCommandCritSec);*/
  38. lua = new sol::state();
  39. lua->open_libraries();
  40. lua->set_exception_handler(lua_exception_handler);
  41. lua->set_panic(sol::c_call<decltype(&my_panic), &my_panic>);
  42. registerBase();
  43. while (SDK::GEngine == nullptr)
  44. {
  45. auto engineAddress = PatternScan::FindSignature(NULL, "48 8b 4c 24 50 48 89 05 ?? ?? ?? ?? 48 85 c9 74 05 e8");
  46. if (engineAddress != NULL)
  47. {
  48. auto tmp = (engineAddress + 5);
  49. auto tmp2 = tmp + 3;
  50. SDK::GEngine = reinterpret_cast<SDK::UEngine**>((tmp + 7 + *(int*)(tmp2)));
  51. }
  52. }
  53. consoleEnvironment = sol::environment(*lua, sol::create, lua->globals());
  54. }
  55. BL3Lua::~BL3Lua()
  56. {
  57. lua_close(lua->lua_state());
  58. DeleteCriticalSection(&luaCritSec);
  59. }
  60. bool BL3Lua::ExecuteScriptFile(const char* filePath, bool printInGame)
  61. {
  62. bool result = false;
  63. EnterCriticalSection(&luaCritSec);
  64. int indexToDelete = -1;
  65. for (int i = 0; i < loadedComponents.size(); i++) {
  66. if (!strcmp(loadedComponents[i]->m_FileName.c_str(), filePath)) {
  67. indexToDelete = i;
  68. break;
  69. }
  70. }
  71. // TODO: Properly delete references during iteration
  72. // Implement iterator instead of loop
  73. if (indexToDelete != -1) {
  74. // Remove registered Hotkeys from this env
  75. auto hkIT = registeredHotkeys.begin();
  76. while (hkIT != registeredHotkeys.end()) {
  77. /*for (auto& r : hkIT) {*/
  78. sol::reference eRef = std::get<0>(*hkIT);
  79. sol::environment env = sol::get_environment(eRef);
  80. if (env == loadedComponents[indexToDelete]->m_Env) {
  81. eRef.abandon();
  82. hkIT = registeredHotkeys.erase(hkIT);
  83. //registeredHotkeys.erase(std::remove(registeredHotkeys.begin(), registeredHotkeys.end(), r), registeredHotkeys.end());
  84. }
  85. if(hkIT != registeredHotkeys.end())
  86. ++hkIT;
  87. }
  88. auto procEventIT = procEventHooks.begin();
  89. // Remove procEventHooks from this env
  90. //for (auto& r : procEventHooks) {
  91. while(procEventIT != procEventHooks.end()){
  92. bool didErase = false;
  93. for (auto& p : procEventIT->second) {
  94. sol::reference eRef = std::get<0>(p);
  95. sol::environment env = sol::get_environment(eRef);
  96. if (env == loadedComponents[indexToDelete]->m_Env) {
  97. eRef.abandon();
  98. //r.second.erase(std::remove(r.second.begin(), r.second.end(), p), r.second.end());
  99. didErase = true;
  100. }
  101. }
  102. if (didErase) {
  103. procEventIT = procEventHooks.erase(procEventIT);
  104. if (procEventIT != procEventHooks.end())
  105. ++procEventIT;
  106. }
  107. }
  108. // Remove consoleCommands from this env
  109. auto ccIT = consoleCommands.begin();
  110. //for (auto& r : consoleCommands) {
  111. while(ccIT != consoleCommands.end()){
  112. sol::reference eRef = std::get<0>(ccIT->second);
  113. sol::environment env = sol::get_environment(eRef);
  114. if (env == loadedComponents[indexToDelete]->m_Env) {
  115. eRef.abandon();
  116. ccIT = consoleCommands.erase(ccIT);
  117. //consoleCommands.erase(r.first);
  118. }
  119. if (ccIT != consoleCommands.end())
  120. ++ccIT;
  121. }
  122. delete loadedComponents[indexToDelete];
  123. loadedComponents.erase(loadedComponents.begin() + indexToDelete);
  124. }
  125. lua->collect_garbage();
  126. LuaComponent* nComp = new LuaComponent(filePath, lua);
  127. nComp->Init();
  128. loadedComponents.push_back(nComp);
  129. lua->collect_garbage();
  130. LeaveCriticalSection(&luaCritSec);
  131. return nComp->m_Env != sol::lua_nil;
  132. }
  133. bool BL3Lua::ExecuteScriptString(const char* scriptCode, bool printInGame)
  134. {
  135. bool result = false;
  136. EnterCriticalSection(&luaCritSec);
  137. try {
  138. auto func_result = lua->safe_script(scriptCode, consoleEnvironment);
  139. if (!func_result.valid()) {
  140. sol::error err = func_result;
  141. std::cout << "[LUA] failed with error: " << err.what() << std::endl;
  142. if (printInGame) {
  143. sol::protected_function printFunc = (*(lua))["PrintGameConsole"];
  144. if (printFunc.valid()) {
  145. std::string errorMessage = std::string("[LUA] failed with error: ").append(err.what());
  146. printFunc(errorMessage);
  147. }
  148. }
  149. }
  150. else {
  151. result = true;
  152. }
  153. }
  154. catch (...) {
  155. }
  156. lua->collect_garbage();
  157. LeaveCriticalSection(&luaCritSec);
  158. return result;
  159. }
  160. void BL3Lua::RunCallbacks(const char* callbackName, sol::object data)
  161. {
  162. EnterCriticalSection(&luaCritSec);
  163. try{
  164. sol::protected_function runCallbackFunc = (*lua)["RunCallbacks"];
  165. if (runCallbackFunc.valid()){
  166. sol::protected_function_result result = runCallbackFunc(callbackName, data);
  167. if (!result.valid()) {
  168. sol::error err = result;
  169. std::cout << "Error during callbacks: " << err.what() << std::endl;
  170. }
  171. }
  172. }
  173. catch(...){}
  174. lua->collect_garbage();
  175. LeaveCriticalSection(&luaCritSec);
  176. }
  177. void BL3Lua::TDump(sol::object tableToDump)
  178. {
  179. EnterCriticalSection(&luaCritSec);
  180. try {
  181. sol::protected_function tdumpFunc = (*lua)["internalTDump"];
  182. if (tdumpFunc.valid()) {
  183. sol::protected_function_result result = tdumpFunc(tableToDump);
  184. if (!result.valid()) {
  185. sol::error err = result;
  186. std::cout << "Error during tdump: " << err.what() << std::endl;
  187. }
  188. }
  189. }
  190. catch (...) {}
  191. LeaveCriticalSection(&luaCritSec);
  192. }
  193. void BL3Lua::ClearCallbacks()
  194. {
  195. EnterCriticalSection(&luaCritSec);
  196. while (callbacks && !callbacks.empty()) {
  197. callbacks.clear();
  198. }
  199. callbacks = lua->create_named_table("Callbacks");
  200. lua->collect_garbage();
  201. LeaveCriticalSection(&luaCritSec);
  202. }
  203. void BL3Lua::ValidateHotkeys()
  204. {
  205. EnterCriticalSection(&luaCritSec);
  206. std::vector<int> toDelete;
  207. std::vector<std::tuple<sol::reference, lua_State*, std::string, std::string, std::string>> tmp;
  208. bool needsFixup = false;
  209. for (int i = 0; i < registeredHotkeys.size(); ++i) {
  210. if (!std::get<0>(registeredHotkeys[i]).valid())
  211. {
  212. needsFixup = true;
  213. }
  214. else {
  215. tmp.push_back(registeredHotkeys[i]);
  216. }
  217. }
  218. if (needsFixup) {
  219. registeredHotkeys = tmp;
  220. }
  221. LeaveCriticalSection(&luaCritSec);
  222. }
  223. // Registering works
  224. uint32_t BL3Lua::RegisterHotkey(sol::this_state s, sol::this_environment e, sol::variadic_args va) {
  225. bool anyError = false;
  226. ValidateHotkeys();
  227. EnterCriticalSection(&luaCritSec);
  228. std::vector<std::string> hotkeys;
  229. sol::function func;
  230. for (auto v : va) {
  231. if (v.is<std::string_view>()) {
  232. std::string hk = v.as<std::string>();
  233. if (!LuaUtility::ContainsKey(hk))
  234. {
  235. anyError = true;
  236. sol::protected_function printFunc = (*(lua))["PrintGameConsole"];
  237. if (printFunc.valid()) {
  238. char buffer[1024];
  239. sprintf_s(buffer, sizeof(buffer), "\"%s\" is not a valid keybind!", hk.c_str());
  240. std::string errorMessage = std::string(buffer);
  241. printFunc(errorMessage);
  242. }
  243. }
  244. else {
  245. hotkeys.push_back(hk);
  246. }
  247. }
  248. else if (v.is<sol::function>()) {
  249. func = v.as<sol::function>();
  250. }
  251. }
  252. //std::vector<std::string> hotkeys = hotkeyTable.as<std::vector<std::string>>();
  253. if (hotkeys.size() >= 1 && hotkeys.size() <= 3 && func.valid()) {
  254. for (auto& hk : hotkeys) {
  255. if (!LuaUtility::ContainsKey(hk))
  256. {
  257. anyError = true;
  258. sol::protected_function printFunc = (*(lua))["PrintGameConsole"];
  259. if (printFunc.valid()) {
  260. char buffer[1024];
  261. sprintf_s(buffer, sizeof(buffer), "\"%s\" is not a valid keybind!", hk.c_str());
  262. std::string errorMessage = std::string(buffer);
  263. printFunc(errorMessage);
  264. }
  265. }
  266. }
  267. if (anyError) {
  268. LeaveCriticalSection(&luaCritSec);
  269. return 0;
  270. }
  271. int index = -1;
  272. for (int i = 0; i < registeredHotkeys.size(); ++i) {
  273. sol::function testFunc = std::get<0>(registeredHotkeys[i]);
  274. if (std::get<0>(registeredHotkeys[i]) == func) {
  275. index = i;
  276. break;
  277. }
  278. }
  279. switch (hotkeys.size())
  280. {
  281. case 1:
  282. if (index != -1) {
  283. registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", "");
  284. }
  285. else {
  286. registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), "", ""));
  287. }
  288. break;
  289. case 2:
  290. if (index != -1) {
  291. registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", "");
  292. }
  293. else {
  294. registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), hotkeys.at(1), ""));
  295. }
  296. break;
  297. case 3:
  298. if (index != -1) {
  299. registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", "");
  300. }
  301. else {
  302. registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), hotkeys.at(1), hotkeys.at(2)));
  303. }
  304. break;
  305. default:
  306. break;
  307. }
  308. }
  309. LeaveCriticalSection(&luaCritSec);
  310. return 0;
  311. }
  312. void BL3Lua::RemoveHotkey(sol::this_state s, sol::this_environment e, uint32_t, sol::function func) {
  313. lua->collect_garbage();
  314. }
  315. void BL3Lua::RemoveAllHotkeys() {
  316. EnterCriticalSection(&luaCritSec);
  317. registeredHotkeys.clear();
  318. lua->collect_garbage();
  319. LeaveCriticalSection(&luaCritSec);
  320. }
  321. void BL3Lua::AddHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func, bool preHook)
  322. {
  323. EnterCriticalSection(&luaCritSec);
  324. procEventHooks[hookName].push_back(std::make_tuple(func, s.L, preHook));
  325. lua->collect_garbage();
  326. LeaveCriticalSection(&luaCritSec);
  327. }
  328. void BL3Lua::RemoveAllHooks()
  329. {
  330. EnterCriticalSection(&luaCritSec);
  331. if (procEventHooks.size() > 0) {
  332. procEventHooks.clear();
  333. }
  334. lua->collect_garbage();
  335. LeaveCriticalSection(&luaCritSec);
  336. }
  337. void BL3Lua::RemoveHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func)
  338. {
  339. int index = -1;
  340. EnterCriticalSection(&luaCritSec);
  341. for (int i = 0; i < procEventHooks[hookName].size(); ++i) {
  342. if (std::get<0>(procEventHooks[hookName][i]).registry_index() == func.registry_index()) {
  343. index = i;
  344. break;
  345. }
  346. }
  347. if (index != -1)
  348. procEventHooks[hookName].erase(procEventHooks[hookName].begin(), procEventHooks[hookName].begin() + index);
  349. lua->collect_garbage();
  350. LeaveCriticalSection(&luaCritSec);
  351. }
  352. void BL3Lua::AddConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func)
  353. {
  354. EnterCriticalSection(&luaCritSec);
  355. consoleCommands[command] = std::make_tuple(func, s.L, command.size());
  356. lua->collect_garbage();
  357. LeaveCriticalSection(&luaCritSec);
  358. }
  359. void BL3Lua::RemoveAllConsoleCommands()
  360. {
  361. EnterCriticalSection(&luaCritSec);
  362. if (consoleCommands.size() > 0) {
  363. consoleCommands.clear();
  364. }
  365. lua->collect_garbage();
  366. LeaveCriticalSection(&luaCritSec);
  367. }
  368. void BL3Lua::RemoveConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func)
  369. {
  370. int index = -1;
  371. EnterCriticalSection(&luaCritSec);
  372. for (int i = 0; i < consoleCommands.size(); ++i) {
  373. if (std::get<0>(consoleCommands[command]) == func) {
  374. index = i;
  375. break;
  376. }
  377. }
  378. if (index != -1){
  379. consoleCommands.erase(command);
  380. }
  381. lua->collect_garbage();
  382. LeaveCriticalSection(&luaCritSec);
  383. }
  384. void BL3Lua::registerBase()
  385. {
  386. lua->set_function("IsKeyPressed", sol::overload(
  387. [](std::string keyName) { return LuaUtility::IsKeyPressed(keyName); },
  388. [](std::string keyName, std::string keyName2) {return LuaUtility::IsKeyPressed(keyName, keyName2); },
  389. [](std::string keyName, std::string keyName2, std::string keyName3) {return LuaUtility::IsKeyPressed(keyName, keyName2, keyName3);
  390. }));
  391. lua->set_function("FindObject", [](std::string name) {
  392. auto tmp = SDK::UObject::FindObject<SDK::UObject>(name);
  393. return tmp;
  394. });
  395. lua->set_function("StaticFindObject", [](SDK::UClass* pClass, const std::wstring_view name)
  396. {
  397. return StaticFindObject(pClass, reinterpret_cast<SDK::UObject*>(-1), &name.data()[0], false);
  398. });
  399. lua->set_function("RegisterHotkey", [&](sol::this_state s, sol::this_environment e, sol::variadic_args va) {
  400. RegisterHotkey(s, e, va);
  401. });
  402. lua->set_function("ClearHotkeys", [&]() {RemoveAllHotkeys(); });
  403. sol::protected_function_result result = lua->safe_script(R"(
  404. function RegisterCallback(onEventName, lCallback)
  405. while true do
  406. if Callbacks then
  407. break
  408. end
  409. end
  410. if Callbacks then
  411. Callbacks[lCallback] = onEventName
  412. else
  413. print("Callback-Table does not exist!")
  414. end
  415. end
  416. function RunCallbacks(eventName, data)
  417. for key, value in pairs(Callbacks) do
  418. key(data)
  419. end
  420. end
  421. function internalTDump(object)
  422. if object == nil then
  423. return
  424. end
  425. for key, value in pairs(getmetatable(object)) do
  426. if not string.find(key, "_") and key ~= "new" then
  427. -- if type(value) == "function" then
  428. -- print("[Function] " .. tostring(key))
  429. -- else
  430. -- print(tostring(key))
  431. -- end
  432. print(tostring(key))
  433. end
  434. end
  435. end
  436. defPrint = print
  437. print = function(...)
  438. for i,v in ipairs{...} do
  439. if PrintGameConsole then
  440. PrintGameConsole(tostring(v))
  441. end
  442. end
  443. defPrint(...)
  444. end
  445. )");
  446. if (!result.valid()) {
  447. sol::error err = result;
  448. std::cout << err.what() << std::endl;
  449. }
  450. SDK::UObject::SetupLuaBind(lua);
  451. loadlibs();
  452. adjustRequirePath();
  453. removeAbusableFuncs();
  454. callbacks = lua->create_named_table("Callbacks");
  455. }
  456. void BL3Lua::loadlibs()
  457. {
  458. const char* jsonlua =
  459. #include "include/json.lua"
  460. ;
  461. const char* splitlua =
  462. #include "include/split.lua"
  463. ;
  464. lua->require_script("json", jsonlua);
  465. lua->require_script("split", splitlua);
  466. }
  467. void BL3Lua::adjustRequirePath() {
  468. const std::string defaultPath = (*lua)["package"]["path"];
  469. wchar_t pBuffer[MAX_PATH];
  470. GetCurrentDirectory(sizeof(pBuffer), pBuffer);
  471. std::wstring widePath(pBuffer);
  472. std::string path(widePath.begin(), widePath.end());
  473. path.append("\\lua\\Modules\\?.lua");
  474. (*lua)["package"]["path"] = defaultPath + ";" + path;
  475. }
  476. void BL3Lua::removeAbusableFuncs() {
  477. sol::table global = lua->globals();
  478. if (global.valid()) {
  479. global["os"]["remove"] = sol::lua_nil;
  480. }
  481. }