Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa526303e1 | ||
|
|
c3e494b2f7 | ||
|
|
635eb62ecc | ||
|
|
4e8466033e | ||
|
|
e9d9858151 |
@@ -0,0 +1,73 @@
|
||||
name: V40 Attached Model Outline Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- test/v40-attached-model-outline
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-v40:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout V40 branch
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
with:
|
||||
version: '0.16.0'
|
||||
|
||||
- name: Build standalone variants
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
zig build all-variants -Doptimize=ReleaseSmall \
|
||||
-Dweirdperformance=false \
|
||||
-Doutline=true \
|
||||
-Dcustomassets=true \
|
||||
-Dtransmogfix=true
|
||||
|
||||
- name: Assemble V40 outline-only test package
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf package dist
|
||||
mkdir -p package/DLL
|
||||
mkdir -p package/Interface/AddOns/WeirdUtils_Outline
|
||||
mkdir -p dist
|
||||
|
||||
cp zig-out/variants/outline.dll package/DLL/outline.dll
|
||||
cp src/outline/addon/Bindings.xml package/Interface/AddOns/WeirdUtils_Outline/Bindings.xml
|
||||
cp src/outline/addon/Outline.lua package/Interface/AddOns/WeirdUtils_Outline/Outline.lua
|
||||
cp src/outline/addon/WeirdUtils_Outline.toc package/Interface/AddOns/WeirdUtils_Outline/WeirdUtils_Outline.toc
|
||||
|
||||
printf '%s\n' \
|
||||
'WeirdUtils V40 Attached Model Outline' \
|
||||
'Base: exact V38 Retail Polish + AutoTarget + AutoRehook + ExitFix.' \
|
||||
'main is untouched.' \
|
||||
'WeirdPerformance is disabled in this standalone build and not modified.' \
|
||||
'Engine-proven WoW 1.12.1 attachment layout from 0x712F70:' \
|
||||
'- child +0x1CC = parent/root CM2Model' \
|
||||
'- child +0x1D0 = attachment id' \
|
||||
'- root +0x1DC = child-list head' \
|
||||
'- child +0x1E4 = next sibling' \
|
||||
'V40 makes direct attached M2 models inherit the root target outline.' \
|
||||
'No new hook, no linked-list traversal, no game-memory writes.' \
|
||||
> package/README_TEST.txt
|
||||
|
||||
(
|
||||
cd package
|
||||
sha256sum DLL/outline.dll > SHA256SUMS.txt
|
||||
zip -r ../dist/WeirdUtils_V40_ATTACHED_MODEL_OUTLINE.zip DLL Interface README_TEST.txt SHA256SUMS.txt
|
||||
)
|
||||
|
||||
- name: Upload V40 package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: WeirdUtils-V40-ATTACHED-MODEL-OUTLINE
|
||||
path: dist/WeirdUtils_V40_ATTACHED_MODEL_OUTLINE.zip
|
||||
if-no-files-found: error
|
||||
@@ -1,7 +1,7 @@
|
||||
-- Outline addon (embedded in DLL, loaded from memory)
|
||||
-- Part of WeirdUtils - only loaded when outline module is compiled
|
||||
|
||||
OUTLINE_VERSION = 1
|
||||
OUTLINE_VERSION = 40
|
||||
|
||||
BINDING_HEADER_OUTLINE = "Outline"
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ fn renderDrawDetour(this: u32, view_matrix: u32, batch_data: u32, batch_indices:
|
||||
const idx_u: u32 = @bitCast(indices[i]);
|
||||
const model_ptr = hook.readMem(u32, batch_data +% idx_u *% 0x40 +% 4);
|
||||
if (model_ptr != 0) {
|
||||
if (tracker.findOutlineEntry(model_ptr) != null) {
|
||||
if (tracker.findOutlineEntryIncludingAttachment(model_ptr) != null) {
|
||||
outline_count += 1;
|
||||
} else if (tracker.isGameObjectModel(model_ptr)) {
|
||||
game_obj_count += 1;
|
||||
@@ -137,7 +137,7 @@ fn renderDrawDetour(this: u32, view_matrix: u32, batch_data: u32, batch_indices:
|
||||
const batch_idx = indices[i];
|
||||
const idx_u: u32 = @bitCast(batch_idx);
|
||||
const model_ptr = hook.readMem(u32, batch_data +% idx_u *% 0x40 +% 4);
|
||||
if (model_ptr != 0 and tracker.findOutlineEntry(model_ptr) != null) {
|
||||
if (model_ptr != 0 and tracker.findOutlineEntryIncludingAttachment(model_ptr) != null) {
|
||||
reordered_indices[outline_pos] = batch_idx;
|
||||
outline_pos += 1;
|
||||
} else if (model_ptr != 0 and tracker.isGameObjectModel(model_ptr)) {
|
||||
@@ -193,7 +193,7 @@ fn drawBatchProjDetour(ctx: u32) callconv(hook.cc.thiscall) void {
|
||||
else
|
||||
0;
|
||||
|
||||
const entry = if (model_ptr != 0) tracker.findOutlineEntry(model_ptr) else null;
|
||||
const entry = if (model_ptr != 0) tracker.findOutlineEntryIncludingAttachment(model_ptr) else null;
|
||||
|
||||
if (entry != null) {
|
||||
// This batch is an outline target - signal the DIP hook
|
||||
|
||||
@@ -12,6 +12,15 @@ pub const MODEL_OWNER_DIRECT: usize = 0x28;
|
||||
/// model + this → render callback owner pointer (set by SetRenderCallbacks).
|
||||
pub const MODEL_OWNER_CALLBACK: usize = 0x3C0;
|
||||
|
||||
/// V40: parent/root CM2Model for an attached model.
|
||||
/// Proven from WoW 1.12.1 build 5875 function 0x712F70:
|
||||
/// child+0x1CC = root, child+0x1D0 = attachment id,
|
||||
/// root+0x1DC = child-list head, child+0x1E4 = next sibling.
|
||||
pub const MODEL_ATTACHMENT_PARENT: usize = 0x1CC;
|
||||
pub const MODEL_ATTACHMENT_ID: usize = 0x1D0;
|
||||
pub const MODEL_CHILD_HEAD: usize = 0x1DC;
|
||||
pub const MODEL_NEXT_SIBLING: usize = 0x1E4;
|
||||
|
||||
// =============================================================================
|
||||
// Render context
|
||||
// =============================================================================
|
||||
|
||||
+26
-2
@@ -79,6 +79,19 @@ pub fn findOutlineEntry(model_ptr: u32) ?*const types.OutlineEntry {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// V40: resolve a live attached M2 to the already-tracked root model.
|
||||
/// 0x712F70 writes the root CM2Model pointer directly to child+0x1CC.
|
||||
/// We only read that fixed field and compare the value; the parent pointer is
|
||||
/// never dereferenced here.
|
||||
pub fn findOutlineEntryIncludingAttachment(model_ptr: u32) ?*const types.OutlineEntry {
|
||||
if (findOutlineEntry(model_ptr)) |entry| return entry;
|
||||
if (model_ptr == 0) return null;
|
||||
|
||||
const parent = hook.readMem(u32, model_ptr + o.MODEL_ATTACHMENT_PARENT);
|
||||
if (parent == 0 or parent == model_ptr) return null;
|
||||
return findOutlineEntry(parent);
|
||||
}
|
||||
|
||||
/// Check if any outline targets are tracked this frame.
|
||||
pub fn hasTargets() bool {
|
||||
return tracked_obj_count > 0;
|
||||
@@ -86,7 +99,7 @@ pub fn hasTargets() bool {
|
||||
|
||||
/// Get the outline colour for a model, or null if not tracked.
|
||||
pub fn getModelColor(model_ptr: u32) ?u32 {
|
||||
const entry = findOutlineEntry(model_ptr) orelse return null;
|
||||
const entry = findOutlineEntryIncludingAttachment(model_ptr) orelse return null;
|
||||
return switch (entry.category) {
|
||||
.target => types.COLOR_TARGET,
|
||||
.raid_marked => if (entry.raid_mark > 0 and entry.raid_mark <= 8)
|
||||
@@ -100,7 +113,7 @@ pub fn getModelColor(model_ptr: u32) ?u32 {
|
||||
|
||||
/// Get the outline category for a model.
|
||||
pub fn getModelCategory(model_ptr: u32) types.ModelCategory {
|
||||
const entry = findOutlineEntry(model_ptr) orelse return .none;
|
||||
const entry = findOutlineEntryIncludingAttachment(model_ptr) orelse return .none;
|
||||
return entry.category;
|
||||
}
|
||||
|
||||
@@ -136,6 +149,7 @@ pub fn classifyModel(model_ptr: u32) void {
|
||||
// Read the model's back-pointers to its owning game object.
|
||||
const owner_direct = hook.readMem(u32, model_ptr + o.MODEL_OWNER_DIRECT);
|
||||
const owner_callback = hook.readMem(u32, model_ptr + o.MODEL_OWNER_CALLBACK);
|
||||
const attachment_parent = hook.readMem(u32, model_ptr + o.MODEL_ATTACHMENT_PARENT);
|
||||
|
||||
// Match against tracked outline objects (target, raid marks, dead players).
|
||||
if (tracked_obj_count > 0 and frame_outline_count < MAX_OUTLINE_MODELS) {
|
||||
@@ -149,6 +163,16 @@ pub fn classifyModel(model_ptr: u32) void {
|
||||
}
|
||||
}
|
||||
|
||||
// V40: attached weapons, shields and other M2 children inherit the
|
||||
// selected root's outline. This is only a value comparison; no traversal.
|
||||
if (attachment_parent != 0 and attachment_parent != model_ptr and
|
||||
findOutlineEntry(model_ptr) == null and frame_outline_count < MAX_OUTLINE_MODELS)
|
||||
{
|
||||
if (findOutlineEntry(attachment_parent)) |parent_entry| {
|
||||
addOutlineEntry(model_ptr, parent_entry.category, parent_entry.raid_mark);
|
||||
}
|
||||
}
|
||||
|
||||
// Match against game object pointers (for render ordering).
|
||||
if (game_obj_ptr_count > 0 and game_obj_model_count < MAX_GAME_OBJ_MODELS) {
|
||||
for (game_obj_ptrs[0..game_obj_ptr_count]) |go_ptr| {
|
||||
|
||||
Reference in New Issue
Block a user