Caution
Do not use this on Warmane. Their anti-cheat flags performance injectors and memory optimization tools as illegal software regardless of intent, and the result is a permanent ban on your account.
Warning
On WoW Circle the DLL gets you disconnected - Turning on No Client Patches in the launcher stops it, and
also turns every optimization off.
Or use the !LuaBoost addon without the DLL.
Performance optimization DLL for World of Warcraft 3.3.5a (WotLK) Author: SUPREMATIST
Download Latest Pre-compiled Release
wow_optimize improves WoW 3.3.5a at the engine and runtime level: memory allocation, Lua VM behavior, Lua library fast paths, timers, file I/O, networking, heap fragmentation, lock contention, the 16-year combat log bug fix, and other low-level bottlenecks.
The current public build is focused on real frametime stability, long-session smoothness, addon-heavy gameplay, and lower Lua/runtime overhead while keeping historically unsafe features disabled.
Disclaimer: This project is provided as-is for educational purposes. DLL injection may violate the Terms of Service of private servers. Use at your own risk.
- What's New in v3.19.1
- Send me your log
- Reviews & Acknowledgments
- Current Feature Set
- Installation
- Compatibility & Setup
- Multi-client Support
- macOS / Apple Silicon (WoWSilicon)
- Building
- Core Architecture
- Troubleshooting & Diagnostics
- A/B Test a Feature turns one feature on and off in stints while you play and compares the two halves. Press SET UP A MEASUREMENT RUN in the launcher and it does the setup for you.
- Flight Recorder keeps the last 512 frames. Press Scroll Lock when you see something wrong and they go into the log. On by default; writes nothing until something marks it.
- Every log now opens with what went wrong this session: freezes, long loads, disconnects, address space running out, bad SavedVariables filenames.
- Bone Matrix Upload (SSE2) replaces the bone matrix transpose in the draw path. 3.35% of main-thread time in the profile; measured 8.6% faster per frame in one session, on too few samples to call it settled. Off by default.
- Object Tick Prefetch prefetches the two fields the object tick reads. 1.39% of main-thread time in a measured session. Off by default.
- No Client Patches stops the DLL writing anything into WoW.exe. See the warning at the top of this file. Off by default.
- Table Emptiness Census and Leave Lua Garbage Collection Alone are diagnostics for the Lua collector. Off by default.
- Garbled SavedVariables filenames, reported by
txtsd -
ElvUI.luawritten as)_.lua. The client had run out of contiguous memory below 2GB and nothing here reacted, because the two things watching it were reading the wrong half of the address space. - WoWCircle disconnects, reported by Flokj and confirmed by asslol. Fixed by the new No Client Patches option, which turns the optimizations off - a trade, not a fix.
- Glowing characters, weapons and shoulder pads, reported by txtsd. Spread Model Animation skipped material and attachment animation along with the bones.
- Crash in the game's error formatter with Reuse Compiled Scripts on.
- Combat Log Filter did nothing unless a second, unrelated option was on. Reported by Anarom.
- Freezes of eight to fifteen seconds were never captured. The watchdog only fired past 45 seconds.
- The DLL needed the Visual C++ Redistributable. It does not now.
- Steadier Shadows did nothing unless the diagnostic probe was also on. It still does not fix the flicker; leave it off.
- Stalls of 40ms every five minutes caused by this tool's own reporting.
- Roughly 120 locked instructions removed from hot paths.
- Several options were gated behind unrelated ones and are now separate, each keeping your existing setting: Render Hooks, Async Worker Pool, Thread Affinity, SSE2 Frustum Cull and Quaternion Normalize, Cache Script Handlers, Unit API Fast Path.
- Wrong numbers in the log: feature counts, draw calls per frame, the CVar watchdog reporting a corrupted client in every log ever collected, and short sessions printing no report at all.
This is the single most useful thing anyone does for this project, and it costs you about thirty seconds.
After playing, attach Logs\wow_optimize_<date>_<time>.log to an
issue or drop it in
Discussions. Nothing
needs to be wrong for a log to be worth sending — a session where everything
worked is just as informative as one where it did not.
What is in it and why it matters. The log ends with a frame-time distribution, a note on whether your client was actually CPU-bound or waiting on the GPU, a profile of where time went, and which features did work rather than merely being switched on. Together those answer questions that cannot be answered from here:
- Which optimizations pay off on hardware and addon sets I do not have. Several features have been removed after logs showed they did nothing, and a few were fixed after a log showed them doing the wrong thing.
- Where the remaining time actually goes. One log turned out to be 94% idle, which meant no CPU-side work could have helped that player at all; another was genuinely CPU-bound and pointed straight at the hot code.
- Whether a bug is mine. A log carries the exact build hash, so a report can be matched to source instead of guessed at.
Please send the whole file rather than an excerpt, and do not trim the first lines — that is where the build hash and your settings are. If you are reporting a bug, say what you saw and roughly when; the log has timestamps and the two together usually locate it.
If you would rather not share it publicly, that is fine — say so in an issue.
Every optimization here is off by default because none of them had a measured gain, and until recently none could be measured: comparing two sessions compares two different evenings, not two settings. One session that alternates a feature on and off compares the same zone, the same addons and the same machine against itself.
In the launcher, press SET UP A MEASUREMENT RUN. It ticks A/B Test a Feature and the sixteen features the harness can measure, changes nothing else you have set, and tells you how long a full pass takes. Press SAVE and play.
That button exists because the harness can only measure features that are switched on - a feature registers with it at the moment it installs - and on a default install that is two of the sixteen, so the rest of the report would be empty. To pick them by hand instead, these are the ones it can measure:
UI Layout Relink Shortcut, Model Draw Order Key Cache, Lua Pool Shortcuts, Table Lookup Dispatch (SSE2), Bone Rotation Maths (SSE2), Bone Rotation Unpack (SSE2), Bone Movement Track (SSE2), Visibility Box Test (SSE2), Box Overlap Test (SSE2), Line-of-Sight Box Test (SSE2), SSE2 Frustum Cull and Quaternion Normalize, Fast SSE2 Memory Clear, SSE2 String Compare, Lua VM: stop the automatic GC, Bone Matrix Upload (SSE2), and Matrix-Vector SSE2.
Each is alternated on its own, so turning several on does not mix them up.
Each subject gets four on/off pairs of twenty seconds, so it spends about two minutes and forty seconds on one before moving to the next: all sixteen take about forty-three minutes. Play for at least that, longer if you can, and send the log. Every feature that was switched on will have been measured against the client doing the same work, and the report says per feature when there were too few turns for the number to mean anything.
To spend the whole session on one feature instead, open WTF\wow_opt.ini and
put its ini key under [General]:
AbTestSubject=LayoutRelinkFastand make sure that feature is switched on too. The switch decides whether it installs; this decides when it does its work. If the name is wrong the report lists the ones it would have accepted.
One of them is there to check the instrument rather than the feature:
MatrixVectorSse2 is already known to be slower than the code it replaces, so
if a report calls that one faster, the measurement is what is wrong.
Click to expand community reviews and stability testers list
See what other players say: Reviews and Testimonials
This project wouldn't exist without the community. Every crash report, every bisection test, every "hey this broke my addon" message directly shaped the release.
Special thanks to:
Morbent, Darkmoore, Ethodeus, Billy Hoyle, tuan, NoGoodLife, feh_dois, David (_oldq), Keoo, UNOB, DarkRockDemon, Raymond, Vandal, Mantork, Falcon, Muus, szopachink17, Shandrax, pathetic-lynx, txtsd, Signalborn Soulweaver, Sicsoo, kojekude, Houmbro
- athei (Alexander Theissen) — the macOS cross-compile
toolchain (
clang-cl+lld-link+xwin, #20), reliable!LuaBoostdetection acrosslua_Stateswaps and fast logins (#19), and the filter that stopsClientExtensions.dll's anti-tamper probe from being reported as a crash (#21). - anzz1 — VS2019 build fix (#2) and closing dangling thread handles (#7).
- POKOch — selective rendering, spell visual blocking and API caching (#12).
Every measured item in these notes came out of a log somebody sent in.
- prince — Chinese client under DXVK; the WeakAuras talent-switch bug, the loading-screen stall, and the crash report that finally pinned an access violation to one instruction.
- txtsd — raids on ChromieCraft; the memory growth and freeze reports, and the request for per-addon profiling that turned into the addon CPU profiler and the Lua compile census.
- Signalborn Soulweaver, Morbent, Sicsoo — early 3.18 logs.
- Doc.James — the zone-change stall, with three sessions that made it reproducible.
- kojekude — boss voice lines going missing in raids and dungeons while every other sound kept working, which turned out to be the sound coalescer returning "played fine" for sounds it had dropped.
- nobus — three sessions with warrior stance-swap crashes, carrying a second independent reproduction of a null-callback crash in the client's device callback list.
- biship — read the timing switch's code and reported that it gated twelve unrelated things and described none of them.
Click to expand full optimized feature list (Memory, Lua VM, Math, Network, Async, I/O)
- Large-allocation mimalloc redirect (opt-in, default off) — only main-thread allocations
>= 1 MBare routed to mimalloc, and only if the returned pointer sits below 2 GB; everything smaller (including all network buffers) and every background-thread allocation stays on WoW's CRT. This is the conservative replacement for the old redirect-everything version, which was removed in v3.16.3 for destabilizing Winsock and breaking connections. Enable in the launcher and confirm you can still connect.free/realloc/_msize/_recallocroute mimalloc-owned blocks by region check so nothing is freed on the wrong heap. - Adaptive purge delay + memory-pressure governor — purge aggression scales with VA pressure; forced
mi_collectunder critical pressure (now driven from the main-thread maintenance tick, not a background thread) - Direct mimalloc use — subsystems (aligned-alloc cache, async I/O buffers, prefetch, etc.) call mimalloc directly regardless of the redirect toggle
- Lua allocator replacement (disabled — corrupted pointers during login)
- WoW
free-wrapper fast path (calls WoW's ownfree, skips a redundant_msizeheap-walk) - Lua string table pre-sizing to reduce hash resize spikes
- Low Fragmentation Heap (LFH) enabled for process heap and new heaps
- Deferred Heap Compactor — defers process heap compaction during loading screens to run once upon screen closure, preventing character login freezes.
- adaptive manual Lua GC
- 4-tier GC stepping:
- normal
- combat
- idle
- loading
- GC step sync with !LuaBoost
- safe Lua stats export to addon
- Lua reload detection and clean reinitialization
- Reuse Compiled Scripts (off by default, experimental) — keeps the compiled form of a Lua chunk and hands it back when the client compiles the same source under the same name again, so the parse does not run. The client still builds the function object, its environment and its addon ownership. Nothing is kept until a chunk has been compiled twice.
UI_Lua/LuaProtoCache
GetItemInfo- 8192-slot cache, Direct Memory Access (disabled - breaks Aux / WCollections / ElvUI)GetSpellInfo- disabled (icon corruption, crashes on relog)
luaH_getstr- generation-guarded table string-key lookup cache (8192-slot, SEH-protected)luaH_getstrinline v2 - safe bucket-index cache with SSE2 prefetch (16384 entries)lua_rawgetiinline v2 - safe array direct + bucket-index cache (8192 entries)
- Phase 1:
string.format
- Phase 2 (safe, Lua API based) - ENABLED:
string.find(plain mode)string.match(safe partial fast path)string.repstring.gsub(plain-literal fast path)typemath.floormath.ceilmath.absmath.max(2 args)math.min(2 args)math.randommath.sqrtmath.fmodmath.modfstring.lenstring.bytestring.chartostringtonumberselectrawequalstring.substring.lowerstring.uppertable.concat(disabled - direct RawTValue* stack writes caused hangs)unpack(disabled - direct RawTValue* stack writes caused hangs)ipairs(disabled - closure factory incompatible with WoW iterator pattern)
- C-global fast paths - ENABLED:
strjoinstrtrimstrsplit
- UI Method Object Lookup (off by default, experimental) — the object fetch that starts every one of 674 Lua calls into a frame (
sub_4A81B0). Four script-engine calls and a push/pop replaced by direct reads; the addon-ownership propagationlua_rawgetiperforms is reproduced rather than skipped, and anything unusual is handed back to the client.UI_Lua/LuaThisFast luaV_concatandluaS_newlstrhooks disabled for public stability- baseline-safe VM operation with zero overhead
- string table pre-sizing remains active to prevent rehash freezes
- PreciseSleep on the main thread
- automatic single-client / multi-client timing behavior
GetTickCountredirected to QPC-based timingtimeGetTimeredirected to the same QPC timeline- QueryPerformanceCounter coalescing cache
- adaptive timer resolution
- hardcoded FPS cap raised from 200 to 999
- MPQ handle tracking
- retroactive MPQ handle scanner
- sequential-scan hints for MPQ access
- adaptive MPQ read-ahead cache
- skip
FlushFileBuffersfor tracked MPQ handles GetFileAttributesAcacheSetFilePointerredirected toSetFilePointerEx
- SRWLOCK-based file cache locking
- main thread priority ABOVE_NORMAL
- ideal processor assignment
- process priority ABOVE_NORMAL
- CriticalSection spin count and spin-first entry path
- TLS-cached
GetCurrentThreadIdand pseudo-handle fast path
TCP_NODELAY- immediate ACK frequency
- socket buffer tuning
- low-delay TOS
- keepalive (30s idle / 5s interval — tuned to keep NAT warm without dropping the connection on transient network jitter)
Features that use worker threads and lock-free queues. Status reflects the current public-safe configuration; individual toggles live in src/version.h.
- Async spell data prefetching - predictive spell data loading before cast completes, reduces spell cast lag, worker thread with lock-free queue (4096 entries) and cache (4096 entries) (disabled — placeholder worker with no producers)
- Multithreaded addon dispatcher - parallelizes addon OnUpdate callbacks across worker thread pool (4 threads), reduces main thread CPU in addon-heavy setups, batch processing with lock-free queue (8192 entries) (disabled - unsynchronized writes to WoW game state)
- Predictive MPQ prefetching - tracks zone transitions and predicts next zone, prefetches textures/models/WMOs into OS cache before teleport, reduces zone loading stutters, worker thread pool (2 threads) with lock-free queue (2048 entries) (enabled)
- Multithreaded combat log parser - offloads combat log parsing to worker thread, reduces main thread CPU in raids, lock-free queue with async processing (disabled — placeholder worker with no producers)
- Sound prefetching - predicts and prefetches sound files based on spell casts, zone transitions, combat state, worker thread pool (2 threads) with lock-free queue (1024 entries) (disabled — placeholder worker with no producers)
- Async quest/achievement loading - async quest log and achievement data loading, worker thread with lock-free queue (512 entries) (disabled — placeholder worker with no producers)
- Multithreaded nameplate renderer - offloads nameplate rendering to worker threads, reduces main thread CPU in 25-man raids, priority system (Target > Focus > Nearby > Distant) (disabled - unsynchronized writes to WoW game state)
- Model/M2 caching - synchronous LRU cache (1024 entries) for loaded models, eliminates redundant model loading (enabled)
- Asynchronous Texture Hot-Swapping & Storm VFS (enabled) — detours TexCreateBLP to immediately return a placeholder white texture, background loads the real BLP data, and hot-swaps the underlying Direct3D 9 texture pointer and properties during frame boundaries (OnFrame) without visual stutters.
- Asynchronous Terrain Mesh Loader & Collision Decoupler (enabled) — offloads ADT terrain file loading and geometry compiling to background threads, decoupling collision checks via player Z height fallback, and detouring CMapGrid::Update to prevent character-select crashes.
- RCU Client Object Manager Traverser (enabled) — replaces linear linked-list entity traversals with lock-free atomic pointer flat mirror arrays updated on link/unlink events.
- Addon dispatcher - lightweight event-driven addon update dispatch (enabled)
- Spread Model Animation (off by default, experimental) — posing model skeletons measured at 3.68 ms of a 24.5 ms frame in raid content. Below 96 models on screen nothing changes; above it each model's pose refreshes every 2nd to 4th frame, never slower than a quarter of the frame rate, and never before its first pose. Cannot make animations run slow: the client derives animation time from a clock rather than by counting frames.
Graphics_Sound/AnimLod - combat log optimizer - fixes the 16-year combat log bug (log retention increased from 300s to 1800s, events no longer lost during extended sessions)
CompareStringAfast ASCII pathMultiByteToWideChar/WideCharToMultiByte- SSE2 ASCII fast path (bypasses NLS for pure-ASCII strings on ASCII-compatible codepages)lstrlenA/lstrlenWfast pathOutputDebugStringAno-op when no debugger- fast
IsBadReadPtr/IsBadWritePtr - periodic stats dump
- CRT
pow()integer fast-path (x^2=x*x, sqrt, etc.) - CRT
strstrSSE2 Boyer-Moore-Horspool
Replacements for WoW's own statically-linked CRT routines at verified addresses:
- WoW
strlen(sub_76EE30) - 16-byte-aligned SSE2 scan, page-safe - WoW
memset(0x40BB80, 1108 callers) - full SSE2 + non-temporal ≥2 MB - WoW
memcpy(0x40CB10, 719 callers) - SSE2 16–255 B + non-temporal ≥256 KB, overlap-safe - WoW
_strnicmp(0x76E780, 1013 callers) - SSE2 ASCII case-insensitive compare strstr- SSE2 Boyer–Moore–HorspoolMultiByteToWideChar/WideCharToMultiByte- SSE2 ASCII fast path
- SSE2 4×4 matrix multiply —
CMatrix::operator*(0x4C1F00) - SSE2 matrix-vector transforms — 3D point × 4x4 matrix (0x4C21B0), 4D vector × 4x4 matrix (0x4C2270), in-place point × 4x4 (0x4C2300)
- SSE2
C3Vector::Normalize— 0x4C3420 + 0x4C3600 (full-precisionsqrtss/divss, engine guards replicated) - SSE2
CMatrix::Transpose— 0x4C23D0 (_MM_TRANSPOSE4_PS, bit-identical) - SSE2 collision box test (off by default, experimental) — the AABB outcode classification in
sub_7C7230, 3.8% of main-thread time in a corrected profile. Six x87 comparisons per vertex become six packed comparisons per four vertices. Bit-exact, not approximate: the bounds are plain floats with no arithmetic applied.Graphics_Sound/CollisionOutcode - SSE2 frustum point culling —
CFrustum::IsPointVisible(0x983D70) - SSE2 Möller-Trumbore ray-triangle intersection — 32-bit indices (0x9836B0), 16-bit indices (0x983490)
- SSE2 frustum AABB-vs-4-planes cull
- SSE2 BGRA↔ARGB batch swap, premultiplied alpha
- Network GUID SSE2 unpacking —
CDataStore::GetWowGUID(0x76DC20) - SSE2 quaternion normalize (enabled — normalizes in double precision)
- Particle simulation throttling —
CParticleEmitter::SimulateParticle(0x981D40) (disabled — 0x981D40 is the particle spawn/init routine, not a skippable advance; throttling it left particles uninitialized, rendering as colored flashes)
The generic msvcrt CRT mem/char SSE2 paths (
crt_mem_fastpath,crt_char_fast) are disabled — WoW links its CRT statically, so hooking msvcrt exports had little effect and risked VA exhaustion.
- Buffers and deduplicates high-frequency UI events per frame
- Disabled: suppressing and re-emitting events a frame later changes event timing/ordering and was unvalidated across the in-world → glue teardown where char-switch crashes occur. Stability outranks the dedup win until it can be confirmed in-game.
- The
FrameScript_SignalEvent(0x81AC90) detour it used to own now belongs to the loading/combat state detector, which is always installed. The dedup queue is a consumer of that detour, so it stays switched off without taking the state tracking down with it.
Batch 1-8: GetSystemTimeAsFileTime (QPC-based 1ms refresh), GetACP, GetUserDefaultLangID, GetProcessHeap, CharUpperA/W, CharLowerA/W, MapVirtualKeyA, GetThreadPriority
Batch 11-20: GetOEMCP, GetDoubleClickTime, GetCursorPos, GetSysColor, GetCaretBlinkTime, IsWindow, GetDesktopWindow, GetFocus
Batch 21-26: GetTickCount64 (QPC-backed), ShowCursor, GetVersionExA, GetSystemMetrics, IsDebuggerPresent (no-op), GetSystemInfo, RegQueryValueExA
Batch 31-38: GetCurrentProcess, GetCurrentThread, GetCPInfo and related kernel caches
- Loading state is detected natively from the client's own event stream (
PLAYER_LEAVING_WORLD→PLAYER_ENTERING_WORLD), so it works with or without the!LuaBoostaddon. Many subsystems use it as a "bypass this while the world is loading" gate: deferred field updates, the DBC lookup cache, the Lua opcache and the texture unload queue - Dynamic VA arena: reserves 256MB during loading, releases after. The reservation is skipped on HD clients (>500MB working set), but the loading state itself is always published
- A watchdog force-exits the loading state after 30s, so a missed end event can never pin the process in loading mode
- Sleep hook: bulk Sleep for waits >16ms (less CPU during idle)
- 512MB high-address reserved arena with
MEM_TOP_DOWN - Wow.exe caller filtering - only services allocations from WoW executable code
- span tracking for correct multi-page allocation/deallocation
- proper
MEM_DECOMMIT/MEM_RELEASEbehavior - reduces 32-bit address space fragmentation from large WoW allocations
- smoother frametimes
- fewer random microstutters
- better long-session smoothness
- lower Lua overhead in addon-heavy gameplay
- less allocator fragmentation over time
- better responsiveness during heavy UI and addon workloads
- faster zone transitions and teleports
- reduced spell cast lag
- smoother addon-heavy gameplay
- slightly better minimum FPS in cities and raids
- less "client gets heavier after long play"
- smoother loading transitions
- faster Lua-heavy addon behavior
- a giant average FPS increase from one hook alone
- visual changes
- magical fixes for broken addons
- gameplay automation
This is an engine and runtime optimization DLL, not a UI overhaul.
For best results, use wow_optimize together with !LuaBoost.
| Layer | Tool | Purpose |
|---|---|---|
| Engine / C / Win32 | wow_optimize.dll |
allocator, Lua VM, timers, file I/O, networking, runtime overhead reduction |
| Lua / Addons | !LuaBoost |
GC control, loading helpers, table pool, update dispatcher, diagnostics |
Copy into your WoW folder:
wow_optimize_launcher.exeversion.dllwow_optimize.dll
Then run wow_optimize_launcher.exe to configure settings, load/save profiles, and click LAUNCH WOW.
Copy into your WoW folder:
version.dllwow_optimize.dll
Then launch WoW normally. The proxy DLL will automatically load the optimizer with default settings.
Copy:
wow_optimize.dll- your injector
Then inject after WoW starts.
The optimization suite is compatible with any standard or customized WotLK 3.3.5a client (build 12340), including private servers using custom executables:
- Warmane (Icecrown, Lordaeron, Onyxia) — STRICTLY PROHIBITED (WILL RESULT IN A PERMANENT BAN)
- Project Ascension (supporting custom
Ascension.exelaunches) - WoW Circle - On WoW Circle the DLL gets you disconnected - Turning on No Client Patches in the launcher stops it, and
also turns every optimization off.
Or use the!LuaBoostaddon without the DLL. - EZ WoW
- WoW Sirus (supporting
Sirus.exeor customrun.exelaunches) - UWow / Firestorm (supporting
run.exelaunches) - ChromieCraft 3.3.5a
- Install the
!LuaBoostaddon intoInterface\AddOns\. - Disable conflicting addons: Remove or disable any third-party GC optimizers (
GarbageProtector,GarbageCollector,SmartGC, etc.) and combat log fixes (CombatLogFix, etc.). The DLL handles these natively; running both causes duplicate hooks, memory corruption, or crashes. - Adjust damage meter settings: Disable built-in garbage collection / memory optimization in your meter addons to prevent double-stepping the Lua GC.
wow_optimize automatically detects when multiple WoW instances are running.
- Single client:
- precise sleep
- 0.5 ms timer
- Multi-client:
- yield-based sleep
- 1.0 ms timer
- reduced working set targets
This reduces CPU pressure compared to forcing aggressive single-client timing on all clients.
wow_optimize works on macOS via WoWSilicon, which runs WoW 3.3.5a natively on Apple Silicon using Wine + rosettax87 translation.
In dlls.txt, winerosetta.dll must be loaded before libSiliconPatch.dll:
mods/winerosetta.dll
mods/libSiliconPatch.dll
mods/wow_optimize.dll
Swapping the first two causes a rosetta error. Without wow_optimize the order does not matter, but with it loaded the translation layer must initialize before any hooks are installed.
macOS/WoWSilicon compatibility was tested by David (_oldq).
The build target is always Win32 i386, but you can produce it from either a Windows host (native MSVC) or a macOS host (cross-compile). Both paths drive the same CMakeLists.txt and ship binary-equivalent DLLs to within ~30 KB.
Requirements:
- Windows 10 or 11
- Visual Studio with the C++ desktop workload
- CMake
- Win32 / 32-bit build configuration
git clone https://github.com/suprepupre/wow-optimize.git
cd wow-optimize
build.batOutput:
build\Release\wow_optimize.dllbuild\Release\version.dllbuild\Release\wow_loader.exebuild\Release\wow_optimize_launcher.exe
Requirements:
- macOS (Apple Silicon or Intel)
- Homebrew
- xwin for the Windows SDK / MSVC CRT
One-time setup:
brew install llvm lld cmake ninja
xwin splat --output /opt/xwinBuild:
git clone https://github.com/suprepupre/wow-optimize.git
cd wow-optimize
makeOutput:
build/wow_optimize.dllbuild/version.dllbuild/wow_loader.exe
The Makefile drives clang-cl (Homebrew llvm) and lld-link (Homebrew lld) through the toolchain file in cmake/toolchain-clang-msvc-x86.cmake. make verify prints PE headers; make clean / make rebuild work as expected. Override LLVM_DIR, LLD_DIR, or XWIN on the command line if your paths differ.
Click to expand full modules listing
dllmain.cpp- Win32 hooks, allocator, timers, file I/O, networking, threading, VA Arenalua_optimize.cpp- Lua VM allocator, adaptive GC (with frame-time scaling and VA-pressure override), Lua globals bridgeasync_terrain_loader.cpp/async_terrain_loader.h- Asynchronous ADT terrain loader, CMapGrid update safety, Z-coordinate collision fallback query.rcu_obj_mgr.cpp/rcu_obj_mgr.h- RCU client object manager traverser for lock-free entity enumeration.lua_fastpath.cpp-string.formatand runtime-discovered Phase 2 hooks (24/27 functions)lua_vm_engine.cpp- Direct-threaded Lua VM interpreter with inline cachelua_getstr_inline.cpp- Safe bucket-index cache for luaH_getstr (16384 entries)lua_rawgeti_inline.cpp- Safe array-direct + bucket-index cache for lua_rawgeti (8192)lua_pushnumber_fast.cpp- Direct TValue stack write for lua_pushnumberlua_gettable_safety.cpp- TValue type validation crash fixhooks_render.cpp- 3-tier off-screen animation throttle, backbuffer LockRect skiphooks_simd.cpp- SSE2 matrix multiply, 4×4 matrix multiply, quaternion normalize, frustum AABB/point cull, ray-triangle intersection, matrix-vector transforms, particle simulation throttle, BGRA↔ARGB, premultiplied alphahooks_logic.cpp- Combat text batching, UI layout cache, heartbeat filter, script cachehooks_memory.cpp- 64B-aligned slab allocator, 16384-entry GUID hash-tablehooks_async.cpp- 2-thread worker pool, particle SSE2, ADT prefetchevent_coalescer.cpp- Lua event coalescing via FrameScript_SignalEvent hook, per-frame deduplicationnetwork_guid_sse2.cpp- SSE2 branchless GUID unpacking for CDataStore::GetWowGUIDd3d9_state_manager.cpp- 15-hook D3D9 vtable patcher + device-reset lifecycle tracker and DXVK implicit-resize handler (active)dxvk_bridge.cpp- DXVK / Vulkan-translation-layer detection (module, d3d9.dll metadata, env)hot_patch.cpp- 20 runtime hot-patch optimizationsinfra_patch.cpp- 50 infrastructure APIs (pools, caches, dedup, perfmon)hook_prefetch.cpp- 3 SSE2 prefetch hooks for cleanup/delete/reset pathsdata_caches.cpp- 10 game-data lookup caches (spell, M2, FMOD, DBC, etc.)compute_caches.cpp- 10 compute/transform caches (BZ2, vertex SSE2, regex ext, etc.)crash_dumper.cpp- Enhanced crash reporter with feature tracking + hook tracelua_internals.cpp- stable VM baseline (disabled unsafe hooks)combatlog_optimize.cpp- combat log retention and cleanup behaviorcombatlog_mt.cpp- multithreaded combat log parsertexture_async.cpp- async texture loading with worker thread poolspell_prefetch.cpp- async spell data prefetchingaddon_dispatcher.cpp- multithreaded addon update dispatchermodel_async.cpp- model/M2 cachingmpq_prefetch.cpp- predictive MPQ prefetchingapi_cache.cpp-GetItemInfocacheui_cache.cpp- disabled in public-safe buildversion_proxy.cpp- proxy loaderwow_loader.cpp- standalone loader executable
Two things make a report actionable, and both are easy to get wrong:
- Send
Logs\wow_optimize_<date>_<time>.log, notLogs\wow_optimize.log. The second one is overwritten on every launch. - Quit the game normally — not
alt+F4— after reproducing the problem, so the end of the log reaches disk.
If the game crashed, attach Crashes\wow_crash_*.dmp (or the text report written next to it under Wine) as well.
Every crash report, Lua error dump and stutter dump starts with an event trace — the state transitions leading up to the problem, newest first — which is usually the part that explains it:
Recent events:
- 23ms TID=900 LUA state swap (UI reload) - new VM settling
- 27810ms TID=900 LOADING begin (PLAYER_LEAVING_WORLD)
-110351ms TID=900 D3D9 device Reset (dev=0x0EB1AA90)
The startup banner reports the exact build the log came from (v3.19.1 (build abc1234)), so please don't trim the first lines.
If the complaint is stuttering rather than a crash, look for slow frame lines — each one names how far past your session's own median that frame ran, and what was happening during it:
[FrameBench] slow frame: 102.9 ms (16.3x the 6.30 ms median) - recent events:
| Problem | Solution |
|---|---|
| Proxy DLL doesn't load (no log file) | Use wow_loader.exe, or uncheck "Disable fullscreen optimizations" in Wow.exe properties:![]() |
| Antivirus flags the DLL | Hooking/injection tools often trigger false positives. Source is open for review. |
FATAL: MinHook initialization failed |
Another hook DLL is conflicting. Disable other injectors/overlays. |
ERROR: No CRT DLL found |
Non-standard WoW build detected. |
Socket shows fail |
Normal on some Windows versions - some network options require admin. |
| Damage meters still broken | Remove CombatLogFix or similar addons. Two fixers conflict. |
| No noticeable difference | Expected on high-end PCs with few addons. |
[UICache] DISABLED |
Non-standard WoW build - method table not found. |
| High CPU usage with multiple clients | Expected. Each client runs full optimization. Remove version.dll from secondary clients if needed. |
| "I use DXVK or Vulkan" | Fully supported. No D3D9 state-cache dependencies. |
Large pages: no permission |
Informational only — not a crash cause. Large pages are an optional TLB optimization (mimalloc 2 MB OS pages); the DLL runs fine on normal 4 KB pages without them. To enable them, see Fixing Large pages: no permission below. |
Click to expand step-by-step setup guide
This log line means your Windows account does not hold the Lock pages in memory privilege. The DLL can only use the privilege if the account already has it — it cannot grant it for you. Granting it is optional and only enables the large-page TLB optimization; everything else works without it.
1. Grant the privilege
- Press
Win+R, typesecpol.msc, and run it as Administrator (Local Security Policy). - Go to Local Policies → User Rights Assignment → Lock pages in memory.
- Click Add User or Group, type your Windows username, click Check Names, then OK.
- Log off and back on (or restart) for the change to take effect.
2. Still says no permission? Use a group catch-all
If running as Administrator still produces the no permission log line, your Windows
username may not be mapping correctly inside the policy tool. Add the universal groups
instead of a specific account:
- Open
secpol.mscagain. - Go back to Local Policies → User Rights Assignment → Lock pages in memory.
- Clear out your specific account name.
- Click Add User or Group, type
Administrators(plural), click Check Names, then OK. - Click Add User or Group once more, type
Users(plural), click Check Names, then OK. - Restart your computer.
After a restart the log should read Large pages: ENABLED for mimalloc. If you would
rather not change the policy at all, the line is harmless and can be ignored — or set
TEST_ENABLE_LARGE_PAGES 0 in src/version.h to silence the attempt entirely.
wow-optimize/
├── src/
│ ├── allocators/ # mimalloc redirect, cache governor, heap compactor
│ ├── core/ # DLL entry, proxy loader, features config (version.h)
│ ├── diagnostics/ # EIP sampling profiler, crash reporter, CVar watchdog
│ ├── hooks_subsystems/ # D3D9 state manager, CRT string fast-paths, event/data caches
│ ├── launcher/ # C# WinForms configurator & launcher dashboard
│ ├── runtime_vm/ # Lua C-API detour hooks, stack query inline paths, VM engine
│ ├── simd_math/ # SSE2 4x4 matrix, frustum point culling, raycast overrides
│ └── threading/ # Multi-threaded work pool dispatcher
├── CMakeLists.txt # Build system definition
├── README.md # Project overview & documentation
└── LICENSE # Project license
MIT License - use, modify, and distribute freely.
| Project | What it does |
|---|---|
| LuaBoost | Addon-side GC control, loading-screen helpers, shared APIs for addon authors |
| WA_SafeGuard | Backs up WeakAuras so a forced disconnect cannot wipe your auras |
| DefileAlert | Instant Defile target callout for the Lich King encounter |


