5.0 KiB
MoonwellCustomization vertical slice
Scope
MoonwellCustomization.dll is a runtime-only WarcraftXL 1.1 extension for WoW 3.3.5a build
12340. It changes only an active Blood Elf Female player. State is kept in memory and is deliberately
separate from rendering; there are no server packets, database changes, AzerothCore changes, or new
Wow.exe offsets.
The data flow is:
CustomizationOption (126) -> CustomizationChoice -> CustomizationElement (Geoset) -> collection M2
The explicit prototype state is None plus three retail choices. The renderer owns one independent
collection render context at a time. Reapplying the same choice is a no-op; replacing a choice releases
the old context first. The overlay copies the active character's placement and bone palette without
joining the stock attachment readiness chain. OnWorldLeave always releases it and drops all borrowed
player pointers.
Verified WarcraftXL API
The repository pins vendor/warcraftxl to v1.1.220 (4895cef) on the v1.1 branch. Source code,
not README assumptions, establishes the following behavior:
WXL_Query/WXL_Loadare the extension entry points; the runtime loads DLLs found belowExtensions/<name>/.WXL_Api::UiAddPanelregisters an immediate-mode overlay panel. WarcraftXL v1.1 hard-codesF9as its overlay toggle; press it and select MoonWell Customization.world::ActivePlayerGuidandworld::ResolveObject(..., kTypeMaskPlayer)find the active player;unit::Modelreturns its body-model/scene-node binding.- The upstream typed
SceneNodeandCharModelObjectviews provide owner, race, gender, and root scene node. The extension adds no offsets. m2::GetRenderCtxalways creates a new scene model;AttachToScene(..., slot 19, true)attaches a collection M2. Core explicitly documents 19 as the collection-M2 attachment point.OnM2SkinFinalizeis the safe pre-finalize window to filter collection geosets. Runtime changes callFinalizeSkinonce; a recursion guard prevents its event from re-entering the filter.OnBuildBonePaletteis post-engine and therefore the safe point to copy the parent character bone palette into the collection model immediately before upload.OnItemSlotChangeandOnItemSlotClearschedule a replacement on the next logic tick, after native equipment work. Native equipment is never overridden.OnWorldLeaveis the cleanup event. Events and UI run on WarcraftXL's main/render paths; no worker thread calls client model bindings.
Build
From a Visual Studio 2022 developer environment or PowerShell:
.\build-warcraftxl.ps1 -Configuration Release
The required artifact is:
build\warcraftxl-win32\Release\MoonwellCustomization.dll
The target is Win32. The top-level CMake build compiles the extension together with the existing WarcraftXL SDK sources; there is no second CMake project.
Install and run
- Install the asset files described in
docs/wow-export-assets.mdinto a client MPQ. - Copy the DLL to
Extensions\MoonwellCustomization\MoonwellCustomization.dllunder the client directory. The build script does this automatically when invoked with-Deploy -ClientPath <client>. - Start the stock build-12340 client through the installed WarcraftXL
d3d9.dllproxy. - Press
F9to open the WarcraftXL overlay and select MoonWell Customization. - On Blood Elf Female, press None / Betrayer / Beast / Dreadlord. None must remove the collection; repeated selections must not stack it. Equip and remove a helmet, then log out and back in.
- On every other race or gender, the panel reports that the prototype is unsupported and exposes no choice controls.
Expected log lines are tagged [MoonwellCustomization]: loaded, player detected, race/gender,
apply, model load, attach, detach, unsupported player, and actionable failure text.
Known limits
- The repository intentionally excludes Blizzard assets. Without the collection M2 and sibling skin, the client loader can fall back to its placeholder model; that is an asset-install failure, not a successful visual test.
- Retail collection model 7760202 is a modern MD21 asset. It requires the existing
wxl-modern-m2,wxl-modern-blp,wxl-db2, and FDID extensions in this repository. - Bone copying assumes the retail Blood Elf Female collection uses the same ordered skeleton as its parent model. The code clamps to the smaller palette, but a retail build changing bone order would need an explicit bone map.
FinalizeSkinin WXL 1.1 has small internal re-finalize leaks. The implementation therefore performs it only on an actual choice change/equipment refresh, never per frame.- This source-level build proves compilation and packaging. A successful visual result and crash-free logout still require an interactive client session with the external assets installed.
The next minimal step toward a broader retail-like system is to move the static option table to an
external, versioned catalog and add renderers for Texture and independent M2Attachment elements while
keeping the same optionID -> choiceID state boundary.