Remove em dashes from the README
This commit is contained in:
@@ -20,25 +20,25 @@ protecting you, and one priest levitating nearby can drop you out of the game.
|
||||
## What it fixes
|
||||
|
||||
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,
|
||||
shoulders, cape, weapon — are separate small models, and the client keeps them in
|
||||
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
|
||||
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
|
||||
long.
|
||||
|
||||
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
|
||||
in memory belonging to something else entirely, and reading whatever happens to be
|
||||
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
|
||||
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
|
||||
that does not exist, and Windows kills the game.
|
||||
|
||||
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,
|
||||
- depends on what the levitating player is **wearing**,
|
||||
- happens **sometimes** rather than every time,
|
||||
@@ -56,7 +56,7 @@ in game.
|
||||
## Requirements
|
||||
|
||||
- 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
|
||||
already and `dlls.txt` exists.
|
||||
@@ -95,11 +95,11 @@ prevented=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.
|
||||
- **`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.
|
||||
- **`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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
another mod that got there first — **it patches nothing at all** and records the reason
|
||||
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
|
||||
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**,
|
||||
@@ -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
|
||||
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
|
||||
crash appears, check `status` in `levifix.txt` first, and disable the DLL to rule it
|
||||
out.
|
||||
@@ -156,13 +156,13 @@ If the hash does not match, do not use the file.
|
||||
## Technical detail
|
||||
|
||||
- Faulting instruction: `0x00713DFF`, `mov ebx, [ecx+edx*4]`, inside `sub_00713D50`.
|
||||
That function receives an M2 animation track — confirmed by the
|
||||
`word [track+2] == 0xFFFF` global-sequence test at `0x713D96` — plus an animation
|
||||
That function receives an M2 animation track (confirmed by the
|
||||
`word [track+2] == 0xFFFF` global-sequence test at `0x713D96`) plus an animation
|
||||
index.
|
||||
- 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
|
||||
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.
|
||||
- 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
|
||||
@@ -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
|
||||
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`
|
||||
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.
|
||||
- The hook refuses the lookup and returns `{0, 0, 0.0f}`, matching the client's own
|
||||
degenerate-range path at `0x00713D7F`.
|
||||
|
||||
Reference in New Issue
Block a user