#include "CustomizationRenderer.hpp" #include #include "engine/events/Event.hpp" #include #include #include namespace moonwell::customization { namespace ev = wxl::events; const WXL_Api* g_api = nullptr; std::unique_ptr g_renderer; void __cdecl OnWorldEnter(void*, const void*) { g_renderer->OnWorldEnter(); } void __cdecl OnWorldLeave(void*, const void*) { g_renderer->OnWorldLeave(); } void __cdecl OnUpdate(void*, const void* raw) { const auto* args = static_cast(raw); g_renderer->OnUpdate(args ? args->dt : 0.0f); } void __cdecl OnItemSlotChange(void*, const void* raw) { const auto* args = static_cast(raw); if (args) g_renderer->OnEquipmentChanged(args->charModelObj); } void __cdecl OnItemSlotClear(void*, const void* raw) { const auto* args = static_cast(raw); if (args) g_renderer->OnEquipmentChanged(args->charModelObj); } void __cdecl OnSkinFinalize(void*, const void* raw) { const auto* args = static_cast(raw); if (args) g_renderer->OnSkinFinalize(args->model); } void __cdecl OnBuildBonePalette(void*, const void* raw) { const auto* args = static_cast(raw); if (args) g_renderer->OnBuildBonePalette(args->renderCtx); } void DrawPanel(void*) { char line[128]{}; if (!g_renderer->PlayerDetected()) { g_api->UiText("Player: detecting..."); g_api->UiText(g_renderer->LastError()); return; } std::snprintf(line, sizeof(line), "Race ID: %u%s", g_renderer->Race(), g_renderer->Race() == kBloodElfRace ? " (Blood Elf)" : ""); g_api->UiText(line); std::snprintf(line, sizeof(line), "Gender ID: %u%s", g_renderer->Gender(), g_renderer->Gender() == kFemaleGender ? " (Female)" : ""); g_api->UiText(line); g_api->UiSeparator(); if (!g_renderer->Supported()) { g_api->UiText("Prototype supports Blood Elf Female only."); return; } g_api->UiText("Option: Head Decorations (WotLK fallback)"); for (const auto& choice : kHornsOption.choices) { std::snprintf(line, sizeof(line), "%s%s", choice.name, g_renderer->CurrentChoice() == choice.id ? " [selected]" : ""); if (g_api->UiButton(line)) g_renderer->Apply(kHornsOption.id, choice.id); } g_api->UiSeparator(); g_api->UiText(g_renderer->LastError()); } } const WXL_PluginInfo* __cdecl WXL_Query(void) { static const WXL_PluginInfo info = { sizeof(WXL_PluginInfo), WXL_API_VERSION, "MoonwellCustomization", 1, WXL_CLIENT_BUILD, }; return &info; } int __cdecl WXL_Load(const WXL_Api* api) { using namespace moonwell::customization; if (!api || api->apiVersion != WXL_API_VERSION || api->structSize < sizeof(WXL_Api) || !api->Subscribe || !api->UiAddPanel) return 0; g_api = api; g_renderer = std::make_unique(api); api->Subscribe(uint32_t(ev::Event::OnWorldEnter), &OnWorldEnter, nullptr); api->Subscribe(uint32_t(ev::Event::OnWorldLeave), &OnWorldLeave, nullptr); api->Subscribe(uint32_t(ev::Event::OnUpdate), &OnUpdate, nullptr); api->Subscribe(uint32_t(ev::Event::OnItemSlotChange), &OnItemSlotChange, nullptr); api->Subscribe(uint32_t(ev::Event::OnItemSlotClear), &OnItemSlotClear, nullptr); api->Subscribe(uint32_t(ev::Event::OnM2SkinFinalize), &OnSkinFinalize, nullptr); api->Subscribe(uint32_t(ev::Event::OnBuildBonePalette), &OnBuildBonePalette, nullptr); api->UiAddPanel("MoonWell Customization", &DrawPanel, nullptr); api->Log(WXL_LOG_INFO, "MoonwellCustomization", "loaded"); return 1; }