- Версия SA-MP
-
- Любая
Описание: ремейк старого плагина от @FYP по всем хайповым канонам с красивым меню и работой на всех версиях сампа
Для меню используется WebView
Активация: /nocol
Для меню используется WebView
Активация: /nocol
C++:
#include <entry.hpp>
#include <render.hpp>
//
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <thread>
// third-party
#include "safetyhook/easy.hpp"
#include <glaze/glaze.hpp>
// samp
#include "samp/classes/game.hpp"
#include <samp/classes/input.hpp>
// web
#include <cmrc/cmrc.hpp>
#include <webcore.hpp>
CMRC_DECLARE(webui);
namespace nocol
{
namespace dest
{
constexpr std::uintptr_t hook_entry = 0x0054BCEE;
constexpr std::uintptr_t orig_jump = 0x54CEFC;
constexpr std::uintptr_t run_col = 0x0054BCF4;
constexpr std::uintptr_t skip_col = 0x54CF8D;
constexpr std::uint32_t zf_flag = 0x40;
} // namespace dest
enum class type : std::uint8_t
{
vehicle = 2,
player = 3,
object = 4
};
struct settings_t
{
bool show_menu;
//
bool active;
bool build;
bool player;
bool vehicle;
bool object;
static constexpr auto glz_obj() noexcept
{
return glz::object(settings_t{}, "show_menu", &settings_t::show_menu, "active", &settings_t::active, "build",
&settings_t::build, "player", &settings_t::player, "vehicle", &settings_t::vehicle, "object",
&settings_t::object);
}
} inline cfg;
static safetyhook::MidHook col_hook;
[[nodiscard]] inline type get_type(void *ptr) noexcept
{
return static_cast<type>(*reinterpret_cast<std::uint8_t *>(static_cast<std::byte *>(ptr) + 54) & 7);
}
[[nodiscard]] bool should_skip(void *src, void *dst) noexcept
{
if (!src || !dst)
return false;
const auto t_src = get_type(src);
const auto t_dst = get_type(dst);
switch (t_dst)
{
case type::player:
case type::vehicle:
return (t_src == type::vehicle && cfg.vehicle) || (t_src == type::player && cfg.player) ||
(t_src == type::object && cfg.object);
default:
return false;
}
}
void on_col_hook(safetyhook::Context &ctx) noexcept
{
if (!(ctx.eflags & dest::zf_flag) || (cfg.active && cfg.build))
{
ctx.eip = dest::orig_jump;
return;
}
if (cfg.active && should_skip((void *)ctx.edi, (void *)ctx.esi))
{
ctx.eip = dest::skip_col;
return;
}
ctx.eip = dest::run_col;
}
void on_js_message(webcore::CWebFrame *f, const std::wstring &message)
{
std::string json(message.begin(), message.end());
nocol::settings_t tmp{};
[[maybe_unused]] auto e = glz::read_json(tmp, json);
nocol::cfg = tmp;
if (!tmp.show_menu)
f->set_visible(false);
}
} // namespace nocol
namespace plugin
{
using namespace nocol;
using namespace samp;
entry::entry(HMODULE hmodule) : hmodule_(hmodule)
{
std::thread(
[]
{
col_hook = safetyhook::create_mid(dest::hook_entry, on_col_hook);
while (!classes::input())
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
render::init();
using namespace render;
core.execute(
[]()
{
auto width = static_cast<std::uint32_t>(*reinterpret_cast<int *>(0xC9C040) / 2);
auto height = static_cast<std::uint32_t>(*reinterpret_cast<int *>(0xC9C040 + 4) / 2);
auto frame = core.create_frame(
"main", {.width = width, .height = height, .visible = false, .transparent = true});
frame->set_anchor(webcore::Anchor::Center);
frame->on_ready(
[](webcore::CWebFrame *f)
{
f->on_message(nocol::on_js_message);
auto fs = cmrc::webui::get_filesystem();
auto file = fs.open("index.html");
f->load_html(std::string(file.begin(), file.end()));
});
});
core.on_visibility_changed(
[](bool visible)
{
classes::game()->set_cursor_mode(visible ? 2 : 0, 1);
if (visible)
((void (*)())0x53f1e0)();
});
classes::input()->add_command("nocol", []([[maybe_unused]] const char *s) { core.set_all_visible(true); });
})
.detach();
}
entry::~entry()
{
col_hook.reset();
}
} // namespace plugin
std::unique_ptr<plugin::entry> instance;
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, [[maybe_unused]] LPVOID reversed)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(module);
instance = std::make_unique<plugin::entry>(module);
}
else if (reason == DLL_PROCESS_DETACH)
{
instance.reset();
}
return TRUE;
}
Вложения
Последнее редактирование: