Информация MoonLoader - разработка

egor230

Участник
47
16
Здравствуйте, всем. Очень вдохновлен moonloader. Поэтому решил написать плагин позволяющий запускать lua скрипты для gta vice city, за основу был взять sdk plugin. Скажите пожалуйста, как вы смогли реализовать перезагрузку скриптов?.


Пытался сделал так. Когда игрок найден, запускается независимый поток с флагом завершения. Потом мы находим все 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
 
  • Нравится
Реакции: imring

Pakulichev

Software Developer & System Administrator
Друг
1,789
2,132
@FYP, очень давно заметил такую вещь: отправляю я, к примеру, пакет sampSendDialogResponse(id, 1, ", 'text') (сейчас представим диалог который должен будет закрыться при вводе текста и нажатия кнопки 1), но таким способом диалог остаётся открытым. но при связке с sampCloseCurrentDialogWithButton(1) - всё работает как надо, что немного странно. ведь я и так отправляю пакет о нажатии кнопки один, какого чёрта. это баг или я чего-то не понимаю?
Ты отправляешь пакет на сервер, а диалог остаётся открыт на стороне клиента. Соответственно, тебе нужно его закрыть.
 
  • Нравится
Реакции: maestto

Salik_Davince

Известный
37
3
Кстати где скачать ранние версии мунлоадера, т.e 2,5 и тд, а не последнюю.
 

S0ft1we

Новичок
3
0
Не работает плагин language-luajit от фупа, не работает автокомпиляция да и при перезагрузке плагина выскакивает ошибка.
-ТЫЫЫК-
 

ELTacoBanido

Новичок
29
1
Iam using this function to drive staight to a coordinate. but any vehicle or player on the way stops the vehicle forever.
I Tryed tweaking the taskCarDriveToCoord last 3 args but dindnt worked.
heres the function:
Код:
local function drive_car_to_coord (ped, x, y, z, speed)
    taskCarDriveToCoord (ped, -1, x, y, z, speed, 2, null, 0)
    if isKeyJustPressed (0x4B) then
        i = false
    end
    while checkChar (ped) do
        if locateCharInCar3d (ped, x, y, z, 3.0,3.0,3.0, false) then
            return true
        end
        wait (0)
    end
    return false
end
 [/ CODE]
 

imring

Ride the Lightning
Всефорумный модератор
2,355
2,516
Iam using this function to drive staight to a coordinate. but any vehicle or player on the way stops the vehicle forever.
I Tryed tweaking the taskCarDriveToCoord last 3 args but dindnt worked.
heres the function:
Код:
local function drive_car_to_coord (ped, x, y, z, speed)
    taskCarDriveToCoord (ped, -1, x, y, z, speed, 2, null, 0)
    if isKeyJustPressed (0x4B) then
        i = false
    end
    while checkChar (ped) do
        if locateCharInCar3d (ped, x, y, z, 3.0,3.0,3.0, false) then
            return true
        end
        wait (0)
    end
    return false
end
[/ CODE]
last 3 args are: mode, model (maybe nil?), drivetype
Ways to ride (mode):
0 - rides usually keeping to the lane
2 - not directly folding
3 - rides all the way
4 - just gets in the car
Driving Types (drivetype):
0 - stops at traffic lights and in front of cars
5 - stops at traffic lights and circling cars
2 - passing traffic lights and circling cars
4 - driving traffic lights and stopping in front of cars
7 - rides strictly on the road passing traffic lights and does not stop rides “through” cars
 

ELTacoBanido

Новичок
29
1
[USER = 106094] @imring [/ USER] @FYP
That does not help, 7 is the only one who ignores vehicles, but then my vehicle will only drive on road paths, wich is not what i want.
none of the other modes seems to work properly, i need to make it drive straight to a coordinate, ignoring cars and players.
 
Последнее редактирование:

ishi

Известный
493
110
Lua:
local font = renderCreateFont("Arial", 11, font_flag.BOLD)
...
drawRect(300,300,220,220,255,0,0,100)
renderFontDrawText(font,"text starts 300:300",300,300,0xFF1200FF)
renderFontDrawText(font,"text starts 520:520",300 + 220,300 + 200,0xFF1200FF)

ebaniyrot.png

Пытаясь разобраться в деталях работы функций рендера, столкнулся с тем, перед чем абсолютно бессилен.
Экранный рендер, имеющий лишь две координаты, рисует на самих координатах экрана, или в крайнем случае -- окна, правильно?
было бы логично сказать 'да', но почему-то эти координаты необъяснимым образом визуально не совпадают в таком простом коде, где даже аргументы константны. Для наглядности я вывел отображение.
Ведь квадрат начинающийся на 300 имеющий ширину 220 должен кончаться на 520, правильно? Ну, наверное. Как ещё? Не знаю, тут я уже серьёзно сомневаюсь.
Суть в том, что текст рисуется совсем не на тех же координатах, что рисуется квадрат, причём если в начале погрешность не такая уж большая, хотя по идее всё должно быть пиксель в пиксель, то под конец рисует текст на две трети раньше по широте и на половину по долготе. Ведь в редакторе. где обрезал скрин, я проверил - квадрат размера как раз нужного. А что со строчками не так, почему их так разбросало?

Пишу сюда, потому что я тут не вижу вообще ничего, что могло бы сказать - да это ты говнокодер, какую-то херню сделал, всё забагалось. Ведь это чистые константы и тут моего влияния буквально 0, мне просто не в чем ошибаться
 

FYP

Известный
Автор темы
Администратор
1,758
5,722
@ishi тебе нужна функция renderDrawBox. та, которую ты используешь, является опкодом игры и использует относительные координаты, область которых при любом размере окна всегда 640x480.
 

ELTacoBanido

Новичок
29
1
How can i disable vehicle collision, but iam not talking about
setCarCollision, as it is kinda buggy, also how can i disable collision with players and peds?
 

ishi

Известный
493
110
Почему string.format ищет неуказанные аргументы?
Воспроизводя эту ошибку, пришёл к теории: если не последний после шаблона (строки) аргумент в вызове string.format возвращает более одного значения (return 1,2), то функция упадёт, поскольку начнёт искать аргументов на 1 больше, чем (назовём их кейвордами, я нуб), кейвордов указано в строке (%d, %f и т.д.)

И вот простейший пример:
Lua:
function return11()
    return 1,1
end

function return2()
    return 2
end

function return33()
    return 3
end

local str = string.format("%d %d\n%d\n%d",return11(),return2(),return33())

Данный сценарий форматирования упадёт, но если убрать один из кейвордов, то выведет лишь 3 из 4 цифр, и всё будет окей.
При этом, если не удалять, а перенести одну из возвращаемых цифр так, что бы она попала в последний аргумент - то опять же, падения не будет.
Так, собственно, почему? Почему оно ищет больше аргументов, чем кейвордов для аргументов заявлено в шаблоне?
 

itsLegend

Фонд борьбы за жуков 🐞
Администратор
2,695
1,448
Почему оно ищет больше аргументов, чем кейвордов для аргументов заявлено в шаблоне?
Оно ищет ровно столько, сколько ты указал в шаблоне. Ни больше, ни меньше.
То, что return11() как-бы возвращает только первое значение, если была вызвана первой, то это такое поведение языка.
Выведи print(return11(), return2()) и print(return2(), return11()).
 

ishi

Известный
493
110
Оно ищет ровно столько, сколько ты указал в шаблоне. Ни больше, ни меньше.
То, что return11() как-бы возвращает только первое значение, если была вызвана первой, то это такое поведение языка.
Выведи print(return11(), return2()) и print(return2(), return11()).
Таки беда в том, что у меня bad argument#6 (no value), при том что обе функции возвращающие по 3 аргумента по одиночке возвращают их нормально. Вот и взялся тут строить теории заговора. Ошибка возникла только на шестом, и было бы логично только если оно считает аргументы с нуля и ищет седьмой, которого в двух функциях по три возврата быть не может. И само шестое значение из шести тоже отображается нормально - что проверил, то-есть функция работает. Так что, каким образом-то быть с данной ошибкой?
 

ufdhbi

Известный
Проверенный
1,455
861
Таки беда в том, что у меня bad argument#6 (no value), при том что обе функции возвращающие по 3 аргумента по одиночке возвращают их нормально. Вот и взялся тут строить теории заговора. Ошибка возникла только на шестом, и было бы логично только если оно считает аргументы с нуля и ищет седьмой, которого в двух функциях по три возврата быть не может. И само шестое значение из шести тоже отображается нормально - что проверил, то-есть функция работает. Так что, каким образом-то быть с данной ошибкой?
local x, y, z = ////
и вызывай эти х у з в стринг формате