Files
benilla-octo/crates/benilla-app/Cargo.toml
T
gromandClaude Opus 5 4974326381 Bring the nampower, UnitXP_SP3 and ClassicAPI ports up to the installed builds
The three DLLs beside the client were updated; re-measured each against the
thing with evidence behind it rather than against a wiki.

nampower's own string pool is exact — `^NP_[A-Za-z0-9]+$` is the CVar list and
`Usage:` the arity of every function — and both came back identical to this
tree: 49/49 CVars, 63/63 functions. The gap was events. Four built:

  BUFF_ADDED_OTHER / BUFF_REMOVED_OTHER   ui_aura.rs, AuraEdge::OtherBuff
  KEY_DOWN / KEY_UP                       bindings.rs, key_event_code

The buff pair was argued against here before, on the cost of diffing the
helpful half of every streamed unit for events nothing registered. Answered
rather than overruled: both are gated on `has_listener`, which is the test
upstream now recommends over its own deprecated NP_Enable*Events CVars. The key
pair uses the client's own code table, which `chord::key_code` already held with
a comment saying it was the fact these events were blocked on.

UnitXP_SP3 is packed, so its contract comes from the wiki plus the call sites in
the installed addons — and those call sites exposed a live bug. Every
`UnitXP("target", …)` queued a SelectionRequest, but the mod selects INSIDE the
call and SuperCleveRoidMacros steps the cycle and reads `"target"` back on the
next line, fifty times in one Lua frame. Queued, every pass read the same unit
and the scan reported one enemy however many were there — truthy return, no
error. The pick now resolves in-call from a pool the app publishes
(`feed_unitxp_scan`), exactly the bargain TargetByName already strikes. All nine
target modes are built where four were; `behindThreshold` is real (the reach
feed publishes the angle now, not a verdict); `timer` rides the one timer queue;
`notify` reaches winit's user-attention request; `version`,
`performanceProfile` and a non-raising `debug` answer.

ClassicAPI carries its whole Lua addon gzipped in `.rsrc` — 173 files, a length
header then the bodies, keyed by the paths in its string pool — so the spec for
the installed build is on disk. `scripts/dll-surface.py --unpack` writes it out.
Read against a LIVE VM (not `UiScript::new()`, which is engine-only), the gap is
898 globals, and almost all of it is either a locale string or a subsystem this
client models differently. What is between those is now in
`compat/classic_api/shared_xml.rs`: the pure Blizzard_SharedXML helpers, in
1.12's grammar, from the shipped addon's own source. `tostringall` stays absent
on `tests/stdlib.rs`'s own rule.

The native half is mostly widget methods; intersected with what the corpus
actually calls it is four, of which three are built (`SetResizeBounds` over
1.12's own resize pair, `GetNormalFontObject` — which needed 1.12's missing
`GetTextFontObject` implemented first — and a bare `IsEquippedItem`) and
`SetMotionScriptsWhileDisabled` deliberately is not, because both its call sites
guard on it and the behaviour behind it does not exist here.

Also measured and recorded: every addon-load warning in grom's own logs is a
third-party optional dependency he has not installed or an addon's own packaging
bug, not a defect on this side. docs/ADDON_COMPAT.md has the table.

Ambiguity ceiling 4,956 -> 4,966, measured: nine for `feed_unitxp_scan` against
transform writers on non-networked lanes, one for the attention drain against a
system that also reads WinitWindows and neither writes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
2026-11-06 09:28:56 -07:00

129 lines
6.1 KiB
TOML

[package]
name = "benilla-app"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "The Bevy app as a library: everything but the build-id stamp, which lives in the `benilla` launcher so a new commit does not rebuild this crate"
[lints]
workspace = true
[features]
# `dev` compiles in the instruments; the player build (`scripts/gates.sh`) has no defaults.
default = ["dev"]
# The asset, format and world crates default `dev` on, so they come in without it, forwarded here.
dev = ["benilla-assets/dev", "benilla-formats/dev", "benilla-world/dev", "dep:bevy_egui"]
tracy = ["bevy/trace_tracy"]
# Writes every system's per-run span to `trace-<ts>.json` in the cwd.
trace_chrome = ["bevy/trace_chrome"]
[dependencies]
anyhow.workspace = true
# The EditBox clipboard, on the main thread as NSPasteboard requires; bevy_egui's 3.x.
arboard = "3"
benilla-ui = { path = "../benilla-ui" }
# The chunk cache's key: a load hashes 70 MiB of addon Lua, so the hash has to be the cheap part.
ahash = "0.8.12"
bevy.workspace = true
wgpu.workspace = true
winit.workspace = true
bevy_egui = { version = "0.39", optional = true }
bytemuck = { version = "1", features = ["derive"] }
# `f16` decode for the `WOW_BOOTH_DUMP` dump of the `Rgba16Float` booth targets.
half = "2"
# Compiles `assets/ui` into the binary, so the interface loads on a machine without the source.
include_dir = "0.7"
# The 1.12 chat filters (`text_filter`), with one `RegexSet` for the any-match pass per line.
regex = "1"
# `getrusage` for perf CPU time; the audio clock and render thread's realtime policy on macOS.
libc = "0.2"
# PNG encoding only: the macOS cursor's NSImage data and screenshots.
image = { version = "0.25", default-features = false, features = ["png"] }
# The "no WoW install" error dialog (`no_install`): AppKit, Win32 and, on Linux, `zenity`; no GTK.
# `xdg-portal` is the Linux backend that carries the message dialog; `wayland` is its file-dialog
# parent handle, which a message dialog without a parent never reads.
rfd = { version = "0.17", default-features = false, features = ["xdg-portal"] }
# Thread-to-ECS channels: crossbeam's `Receiver` is `Sync`, so it is a resource without a mutex.
crossbeam-channel = "0.5"
benilla-assets = { path = "../benilla-assets", default-features = false }
benilla-formats = { path = "../benilla-formats", default-features = false }
benilla-protocol = { path = "../benilla-protocol" }
benilla-world = { path = "../benilla-world", default-features = false }
# The CVar diff persisted in `benilla-config/config.toml`.
serde = { version = "1", features = ["derive"] }
# The item cache's on-disk form (`item_persist.rs`); already in the tree through bevy.
serde_json = "1"
toml = "0.8"
# Collision for our kinematic character controller; 0.6 targets Bevy 0.18, 0.7 moves to 0.19.
avian3d = "0.6"
# Shapes and rasterizes `FontString` text standalone (`ui_text`), at bevy_text's own 0.16.
cosmic-text = "0.16"
# `cosmic-text`'s font database, named by `ui_text`; must stay the version it depends on.
fontdb = "0.23"
# The mixer. Its `cpal` backend stays off on every target: `sound::output` is our own backend.
# `ogg`/`vorbis` are the container and the codec, and both are needed for one `.ogg`: addon audio
# on this install is full of them (75 files across BigWigs, DoiteAuras, unitscan, HCWarn,
# TWThreat and Cleanup), and `PlaySoundFile` on one decoded to an error nobody saw — the play
# site logs at `debug!` — so every one of those alerts was simply silent. Stock 1.12 plays only
# wav and mp3; the Turtle/OctoWoW client those addons are written for plays ogg, which is why
# they ship it. `docs/ADDON_COMPAT.md` carries the row.
kira = { version = "0.12", default-features = false, features = [
"mp3",
"wav",
"pcm",
"adpcm",
"ogg",
"vorbis",
] }
# Aborts a debug build on an allocation in the audio IO callback or render pass; off in release.
assert_no_alloc = "1.1"
# `MediaSource`: our source raises kira's decode thread's QoS; must stay kira's version.
symphonia = { version = "0.5", default-features = false }
# The audio threads' lock-free SPSC rings (output, mix tap); kira's version, so the graph has one.
rtrb = "0.3"
mint = "0.5"
# The gossip greeting's weighted draw, re-rolled per open as in the reference.
rand = "0.8"
# HMAC-SHA1 for `credential.rs`, the one place a password is kept as a blob rather than as
# itself. Was a dev-dependency only (the fake realmd's SRP6 half); now a real one.
sha1.workspace = true
# Wayland clipboard over the standard `wl_data_device`; arboard's speaks `wlr-data-control`,
# which GNOME does not implement.
[target.'cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))'.dependencies]
raw-window-handle = "0.6"
smithay-clipboard = "0.7"
# A native NSCursor: winit's cursor rects revert to the arrow under a continuous render loop.
[target.'cfg(target_os = "macos")'.dependencies]
# The audio device layer (`sound::output::coreaudio`), at the versions and features cpal uses.
coreaudio-rs = { version = "0.13", default-features = false, features = ["audio_unit", "core_audio"] }
objc2-core-audio = { version = "0.3", default-features = false, features = ["std", "AudioHardware"] }
objc2-core-audio-types = { version = "0.3", default-features = false, features = ["std", "CoreAudioBaseTypes"] }
objc2 = "0.5"
objc2-app-kit = { version = "0.2", features = [
"NSApplication",
"NSResponder",
"NSRunningApplication",
"NSWindow",
"NSView",
"NSImage",
"NSCursor",
"NSEvent",
] }
objc2-foundation = { version = "0.2", features = ["NSArray", "NSData", "NSGeometry"] }
# The audio device layer off macOS (`sound::output::cpal`); on macOS cpal cannot rebuild on a
# lost default device and drops the IO-cycle timestamp.
[target.'cfg(not(target_os = "macos"))'.dependencies]
cpal = "0.17"
# Windows CPU clocks for `perf::clock`.
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading"] }
# The login cycle's fake realmd runs the server half of SRP6 (`net::io::cycle_tests`).
[dev-dependencies]
benilla-srp = { path = "../benilla-srp" }
num-bigint = "0.4.6"