Remove em dashes from the README

This commit is contained in:
OctoWoW
2026-08-08 13:24:07 -07:00
parent f0001f1005
commit c84fc4bdb5
+17 -17
View File
@@ -20,25 +20,25 @@ protecting you, and one priest levitating nearby can drop you out of the game.
## What it fixes ## What it fixes
Every character animation has a number. Running is 0, walking 1, standing 2, Every character animation has a number. Running is 0, walking 1, standing 2,
falling 35 hovering is 137. falling 35, and hovering is 137.
Your character model has around 150 animations. The things you *wear* helm, Your character model has around 150 animations. The things you *wear* (helm,
shoulders, cape, weapon are separate small models, and the client keeps them in shoulders, cape, weapon) are separate small models, and the client keeps them in
sync by telling each one: *play the same animation number as your wearer.* sync by telling each one: *play the same animation number as your wearer.*
A helm does not have 150 animations. Most have exactly one. Its table is one entry A helm does not have 150 animations. Most have exactly one. Its table is one entry
long. long.
Nobody checks whether the number fits the table. The helm is told "play number 137", Nobody checks whether the number fits the table. The helm is told "play number 137",
and the client counts 137 entries forward from a table that ended after one landing and the client counts 137 entries forward from a table that ended after one, landing
in memory belonging to something else entirely, and reading whatever happens to be in memory belonging to something else entirely and reading whatever happens to be
there. That value is then used as a position. Usually it is obvious nonsense and gets there. That value is then used as a position. Usually it is obvious nonsense and gets
rejected. Sometimes it is a huge number, the client reads an address a gigabyte away rejected. Sometimes it is a huge number, the client reads an address a gigabyte away
that does not exist, and Windows kills the game. that does not exist, and Windows kills the game.
This is why the crash: This is why the crash:
- hits **bystanders**, never the person who cast the spell — their own model has all - hits **bystanders**, never the person who cast the spell, whose own model has all
the animations, the animations,
- depends on what the levitating player is **wearing**, - depends on what the levitating player is **wearing**,
- happens **sometimes** rather than every time, - happens **sometimes** rather than every time,
@@ -56,7 +56,7 @@ in game.
## Requirements ## Requirements
- WoW **1.12.1**, client build **5875** - WoW **1.12.1**, client build **5875**
- A `dlls.txt` loader **VanillaFixes** - A `dlls.txt` loader: **VanillaFixes**
If you already use nampower, SuperWoW, UnitXP or transmogFix, you have VanillaFixes If you already use nampower, SuperWoW, UnitXP or transmogFix, you have VanillaFixes
already and `dlls.txt` exists. already and `dlls.txt` exists.
@@ -95,11 +95,11 @@ prevented=0
worst_index=0 worst_index=0
``` ```
- **`status`** `installed ` means the fix is active. Anything starting with - **`status`**: `installed at ...` means the fix is active. Anything starting with
`refused:` means it patched nothing; see Safety below. `refused:` means it patched nothing; see Safety below.
- **`prevented`** how many out-of-range lookups it has refused. Each one is a read - **`prevented`**: how many out-of-range lookups it has refused. Each one is a read
that would otherwise have gone past the end of a table. that would otherwise have gone past the end of a table.
- **`worst_index`** the largest out-of-range animation number seen so far. Expect - **`worst_index`**: the largest out-of-range animation number seen so far. Expect
**137** to appear after someone levitates near you. **137** to appear after someone levitates near you.
The file is rewritten every few seconds while the count changes. The file is rewritten every few seconds while the count changes.
@@ -109,8 +109,8 @@ The file is rewritten every few seconds while the count changes.
## Safety ## Safety
Before patching anything, LeviFix compares the six bytes at the target address against Before patching anything, LeviFix compares the six bytes at the target address against
what it expects to find. If they differ a different client build, a game update, or what it expects to find. If they differ (a different client build, a game update, or
another mod that got there first **it patches nothing at all** and records the reason another mod that got there first) **it patches nothing at all** and records the reason
in `levifix.txt`. It cannot corrupt a client it does not recognise. in `levifix.txt`. It cannot corrupt a client it does not recognise.
It hooks exactly one function, changes six bytes **in memory only, never on disk**, It hooks exactly one function, changes six bytes **in memory only, never on disk**,
@@ -118,7 +118,7 @@ touches no game files, sends nothing anywhere, and has no effect on gameplay. Th
observable change is that an attached model can hold a single animation frame instead observable change is that an attached model can hold a single animation frame instead
of the game crashing. of the game crashing.
It does **not** fix the underlying bug — that is in the client, and only the client It does **not** fix the underlying bug. That is in the client, and only the client
authors can fix it properly. It stops the crash at the last moment. If a different authors can fix it properly. It stops the crash at the last moment. If a different
crash appears, check `status` in `levifix.txt` first, and disable the DLL to rule it crash appears, check `status` in `levifix.txt` first, and disable the DLL to rule it
out. out.
@@ -156,13 +156,13 @@ If the hash does not match, do not use the file.
## Technical detail ## Technical detail
- Faulting instruction: `0x00713DFF`, `mov ebx, [ecx+edx*4]`, inside `sub_00713D50`. - Faulting instruction: `0x00713DFF`, `mov ebx, [ecx+edx*4]`, inside `sub_00713D50`.
That function receives an M2 animation track confirmed by the That function receives an M2 animation track (confirmed by the
`word [track+2] == 0xFFFF` global-sequence test at `0x713D96` plus an animation `word [track+2] == 0xFFFF` global-sequence test at `0x713D96`) plus an animation
index. index.
- It loads the track's entry count from `[track+4]`, tests it **only against zero**, - It loads the track's entry count from `[track+4]`, tests it **only against zero**,
and then indexes an 8-byte-stride range table at `[track+8]` with the animation and then indexes an 8-byte-stride range table at `[track+8]` with the animation
index, without ever comparing the two. The only follow-up check is `start < end`, index, without ever comparing the two. The only follow-up check is `start < end`,
and both of those come from the same, possibly out-of-bounds entry two garbage and both of those come from the same, possibly out-of-bounds entry, so two garbage
values in ascending order pass it. values in ascending order pass it.
- The index arrives from the model instance's field `+0x9C`, which at `0x00714650` is - The index arrives from the model instance's field `+0x9C`, which at `0x00714650` is
copied verbatim from another model instance: an attachment inherits its wearer's copied verbatim from another model instance: an attachment inherits its wearer's
@@ -170,7 +170,7 @@ If the hash does not match, do not use the file.
- Measured across one installation: of 4502 attachment models, 3837 have exactly one - Measured across one installation: of 4502 attachment models, 3837 have exactly one
animation, and 305 have at least one animation track shorter than index 137. Of the animation, and 305 have at least one animation track shorter than index 137. Of the
1239 short tracks, reading at index 137 yields a value that passes the `start < end` 1239 short tracks, reading at index 137 yields a value that passes the `start < end`
check and is large enough to fault in about 17% of cases which is why the crash is check and is large enough to fault in about 17% of cases, which is why the crash is
occasional rather than constant. occasional rather than constant.
- The hook refuses the lookup and returns `{0, 0, 0.0f}`, matching the client's own - The hook refuses the lookup and returns `{0, 0, 0.0f}`, matching the client's own
degenerate-range path at `0x00713D7F`. degenerate-range path at `0x00713D7F`.