Здравствуйте, всем. Очень вдохновлен moonloader. Поэтому решил написать плагин позволяющий запускать lua скрипты для gta vice city, за основу был взять sdk plugin. Скажите пожалуйста, как вы смогли реализовать перезагрузку скриптов?.
Пытался сделал так. Когда игрок найден, запускается независимый поток с флагом завершения. Потом мы находим все lua файлы в папке и запускаем каждый файл в новом потоке со своим lua состоянием, которые добавляются в вектора, затем запускается функция main с бесконечным циклом во всех lua скриптах.
Попробовал через цикл for снять функция со стека и закрыть lua состояния, но приходит вылет.
Можно ли посмотреть как это реализовано в moonloader? Помогите пожалуйста, советом.
Пытался сделал так. Когда игрок найден, запускается независимый поток с флагом завершения. Потом мы находим все lua файлы в папке и запускаем каждый файл в новом потоке со своим lua состоянием, которые добавляются в вектора, затем запускается функция main с бесконечным циклом во всех lua скриптах.
Попробовал через цикл for снять функция со стека и закрыть lua состояния, но приходит вылет.
Можно ли посмотреть как это реализовано в moonloader? Помогите пожалуйста, советом.
C++:
#include<fstream>
#include <windows.h>
#include <winuser.h>
#include<thread> // std::thread
#include<chrono> // std::thread
#include <cstdlib>
#include <filesystem>
#include <string>
#include "include/lua.hpp"
#include "LuaBridge/LuaBridge.h"
#include "common.h"
#include "plugin.h"
#include "CWorld.h"
#include "extensions\KeyCheck.h"
#include "extensions\ScriptCommands.h"
#include "eScriptCommands.h"
#include "CMessages.h"
using namespace plugin;
using namespace std;
using namespace luabridge;
namespace fs = std::experimental::filesystem;
bool reload = false;
void writelog(const char x[]);// запись ошибок в файл.
int wait(lua_State* L);
int findplayer(lua_State* L);
int sethealth(lua_State* L);
int setarmour(lua_State* L);
void search(string res, vector<lua_State*>& luastate) {
lua_State* L = luaL_newstate();
luaL_openlibs(L);
getGlobalNamespace(L)//Пространства имен LuaBridge для регистрации функции и классов, видны только сценариям Lua.
.beginClass<CPed>("cped")// имя класса пед в lua.
.endClass()// закрыть регистрацию класса.
.beginClass<CVehicle>("CVehicle")// имя класса авто в lua.
.endClass()// закрыть регистрацию класса.
.addCFunction("findplayer", findplayer)// возвращает указатель игрока.
.addCFunction("sethealth", &sethealth)// название функции в lua и c++. уст здоровье.
.addCFunction("setarmour", setarmour)// название функции в lua и c++. уст броню.
.addCFunction("wait", wait);// название функции в lua и c++. задержка.
//writelog(file);
//checklua(L);// проверка и запуска lua файла.
char* file = new char[res.size() + 1]; copy(res.begin(), res.end(), file); file[res.size()] = '\0';// преобразуем строку в char.
luastate.push_back(L);
int status = luaL_loadfile(L, file);// проверка есть ли ошибки.
try { if (status == 0) {// если нет ошибки в файле.
string s1(file); string load = "loaded "; string er0 = load + s1; delete[] file; char* x = new char[er0.size() + 1]; copy(er0.begin(), er0.end(), x); x[er0.size()] = '\0'; writelog(x); delete[] x;
lua_pcall(L, 0, 0, 0);// запуск файла.
lua_getglobal(L, "main");
lua_pcall(L, 0, 0, 0); //
lua_close(L); // закрыть состояние
}
else { delete[] file; string er1 = lua_tostring(L, -1); string er = "could not load "; string er0 = er + er1; char* x = new char[er0.size() + 1]; copy(er0.begin(), er0.end(), x); x[er0.size()] = '\0'; throw x; delete[] x;
}
}
catch (const char* x) { writelog(x);}
};
void second(bool& reload) {vector<lua_State*>luastate;// вектор для lua состояний.
vector<thread>t;//вектор для lua потоков.
for (auto const& de : fs::recursive_directory_iterator{ fs::current_path() / "lualoader" }) { // папка для поиска
if (de.path().extension() == ".lua" || de.path().extension() == ".LUA") {
string res = de.path().string();// перевод имя файла в строку.
t.push_back(move((std::thread(search, res, std::ref(luastate)))));// добавить поток в вектор.
}
};
for (auto& i : t){ i.detach(); };// все потоки независимы.
while (true) {
if (KeyPressed(VK_CONTROL)) {// перезагрузка скрипта
this_thread::sleep_for(chrono::milliseconds(1));
static unsigned int time = 0;// обнулить таймер.
if (CTimer::m_snTimeInMilliseconds - time > 500) {
time = 0;// обнулить таймер
for (auto L : luastate) {
lua_pop(L, lua_gettop(L));
//lua_close(L); // закрыть состояние
};
CMessages::AddMessageJumpQ(L"res", 2000, 3);
}
reload = false; // флаг, что можно запускать новый поток.
break;
}
};
};
class Message {//имя класса
public: Message() {
Events::gameProcessEvent += [] {//обработчик событий игры
CPed* player = FindPlayerPed();// найти игрока
if (!player) return;// проверка найден игрок
if (reload == false) { reload = true;// флаг, что уже запущен поток.
thread th(second, std::ref(reload)); th.detach();// независимый поток.
}
};
}
} message;
void writelog(const char x[]) {// запись ошибок в файл.
string path = "lualoader\\log.txt";
fstream f1; {f1.open(path, fstream::in | fstream::out | fstream::app);
f1 << x; time_t rawtime; struct tm* timeinfo;
char buffer[80]; time(&rawtime); timeinfo = localtime(&rawtime);
strftime(buffer, sizeof(buffer), " %I:%M:%S %d-%m-%Y", timeinfo);
string er2(buffer); f1 << er2 << "\n"; }
f1.close();
};
int findplayer(lua_State* L) {
CPed* player = FindPlayerPed();// получить указатель на игрока.
Stack<CPed*>::push(L, player);// отправить в стек указатель на игрока.
return 1;};
int wait(lua_State* L) {
try {
if (LUA_TNUMBER == lua_type(L, -1)) {// значение число.
double x = lua_tonumber(L, -1);
int x2 = (int)x;
this_thread::sleep_for(chrono::milliseconds(x2));
return 0;}// int
if (LUA_TSTRING == lua_type(L, -1) || LUA_TBOOLEAN == lua_type(L, -1)) {
throw "bad argument in function wait";
}
if (LUA_TBOOLEAN == lua_type(L, -1)) {
throw "bad argument in function wait";
}
else { this_thread::sleep_for(chrono::milliseconds(1)); }
}
catch (const char* x) { writelog(x); }
return 0;
};
int sethealth(lua_State* L) {
try {if (LUA_TUSERDATA == lua_type(L, 1)) {// указатель на игрока.
double x = lua_tonumber(L, 2);// если число.
int health = (int)x;
if (x == health && LUA_TNUMBER == lua_type(L, 2)) {
CPed* b = (CPed*)Userdata::get<CPed>(L, 1, false);// получить указатель на игрока.
b->m_fHealth = health; }// уст здоровье игрока.
else { throw "bad argument in function sethealth option health"; }
}
else { throw "bad argument in function sethealth option of the player"; }
}
catch (const char* x) { writelog(x); }
return 0;
};
int setarmour(lua_State* L) {
try {
if (LUA_TUSERDATA == lua_type(L, -2)) {// указатель на игрока.
float armour = lua_tonumber(L, -1);// если число.
if (LUA_TNUMBER == lua_type(L, -1)) {
CPed* b = (CPed*)Userdata::get<CPed>(L, 1, false);// получить указатель на игрока.
b->m_fArmour = armour; }// уст броню игрока.
else { throw "bad argument in function setarmour option health"; }
}
else { throw "bad argument in function setarmour option of the player"; }
}
catch (const char* x) { writelog(x);}
return 0;
};
Lua:
require("lualoader/mod")
function main()
while true do
wait()
player = findplayer()-- получить игрока
sethealth(player, 22)
--setarmour(player, 1) -- уст броню
--printmessage("car in point", 1000)
end
end