- 1,429
- 2020
- 733
UPDATE 13
==========================
Bug fixes — BGBuddy:
--------------
* BGBuddy/SOTA: fix AFK loop, use IsOnTransport instead of nearby
Transport GO. The previous IsOnTransport gate relied on a nearby
transport game object being present in the object manager; on
some SOTA intro phases the GO query returned null even though the
player was already mounted on the transport, so the bot stayed
stuck in the AFK/idle loop. Switched the gate to the local player
IsOnTransport flag (read once per pulse).
Bug fixes — DungeonBuddy:
--------------
* LfgManager: dynamic random dungeon lookup by level via LfgDungeons
DBC. QueueForRandomDungeon / QueueForRandomHeroic used to hardcode
IDs 261/262 (WotLK Random Normal/Heroic, level 69-80 and 80-83
respectively), so any character below level 69 queued an ID the
server would reject with "you do not meet the requirements for
the chosen dungeon" (e.g. a level 56 user enabling the bot got
the error on every queue attempt). The new implementation
iterates the already-loaded LfgDungeons DBC, filters on
IsRandomDungeon (TypeId==6) + the requested Difficulty + the
player's level, and feeds the first matching ID to
SetLFGDungeon + JoinLFG. Level 56 now matches TBC/Classic random,
level 80 still gets the WotLK random categories. API surface
(SetLFGDungeon, JoinLFG, ClearAllLFGDungeons) verified against
Wow_12340.exe string table — the same native bindings used by
the previous implementation. Pattern matches HB 6.2.3's
LfgDungeons.Dungeons.Where(...) approach; the underlying DBC
wrapper is itself a port of HB 4.3.4's LfgDungeons.dbc schema.
(commit 80a5d84)
Bug fixes — GatherBuddy:
--------------
* GatherBuddy: spirit healer auto-fallback now accepts the resurrect
properly. When the corpse has no mesh (player died in mid-air,
corpse dropped to an unreachable location) the bot triggers the
spirit healer fallback per HB 4.3.4 GatherbuddyBot.smethod_94
pattern (UseSpiritHealer || (!CanFly && !CanNavigateFully)), but
the inline spirit healer sequence at GatherbuddyBot.cs:535-552
blindly clicked StaticPopup1Button1 after a fixed 1s sleep,
regardless of whether the resurrection popup was actually visible
— when no popup was visible (or another StaticPopup1 had stolen
the slot, e.g. a loot frame), the click went to nothing, the
resurrect was never accepted, and the bot entered an infinite
loop of "interact with spirit healer + try corpse + die again".
Each click now checks `if StaticPopup1 and StaticPopup1:IsVisible()`
first and falls back to the native `AcceptResurrect()` API
(verified in Wow_12340.exe string table at 0x9fdf2c) when no
popup is showing. Same double-click + 1000/500/2000ms timing as
HB 4.3.4 (GatherbuddyBot.smethod_95), only the click target is
conditional. (commit 87115a1)
Bug fixes — GatherBuddy:
--------------
* GatherBuddy: drop (!Mounted||!Flying) gate on the [4] combat
subtree. The gate prevented the combat subtree from running while
mounted, which also blocked combat in ground-mount zones where
engaging mobs from the mount is the intended behaviour (HB 4.3.4
and 6.2.3 do not gate the combat subtree on mount state).
* GatherBuddy: rename Loot checkbox key to ChkLootMobs (ChkXxx
convention). Existing ChkLootMobs key was a leftover from a
partial rename; aligned all Loot* keys to the ChkXxx pattern.
Bug fixes — Settings:
--------------
* fix: persist enabled plugins across restarts. The plugin-enabled
state was being written to the in-memory dictionary but not
flushed to Settings.xml on shutdown, so the next launch reverted
every plugin to its compile-time default. Settings now serialise
the enabled-plugin set on BotEvents.OnBotStopped. (PR #1,
Lofbergio/fix/plugin-enabled-persistence)
Bug fixes — LevelBot:
--------------
* LevelBot: restore 1500ms sleep in OnMobKilled. The original HB
4.3.4 LevelBot.smethod_17 OnMobKilled handler waits 1500ms after
a kill so the server-side UnitDynamicFlags.Lootable update
arrives in the client before the next LootTargeting.Pulse tick.
Commit 5905052 removed this sleep based on a misread of the HB
5.4.8 / 6.2.3 reference (those versions moved the handler into
a different file with timer-reset semantics instead of a
blocking sleep, but CopilotBuddy still uses the original LevelBot
flow). The mid-Pulse emptiness of the loot flag was what was
causing loots to be skipped or to hit the WaitLuaEvent
LOOT_OPENED timeout and trigger the "blacklist for 5-10 min"
fallback. Restored to the HB 4.3.4 ground truth.
(commits 6369037 / 872ec43)
Navigation:
--------------
* Navigation C++: port HB 6.2.3 NavMesh API — 11 methods ported
as thin wrappers around dtNavMesh: GetMaxTiles(mapId),
EncodePolyId(mapId, salt, it, ip), DecodePolyId(mapId, ref, out
salt, out it, out ip), DecodePolyIdSalt/Tile/Poly(mapId, ref),
GetTileAt(mapId, x, y), GetTile(mapId, i), GetTileStateSize,
StoreTileState, RestoreTileState. Tile pointers exposed as
`const void*` for C API compatibility (cast as IntPtr on the
C# side). mapId is added to every signature to support
CopilotBuddy's multi-map context (HB 6.2.3 has a single mesh
via this._mesh). GetTileAt passes layer=0 to match HB 6.2.3's
call shape and V4 mmtiles (single layer per coord).
* Bot-side: P/Invoke declarations + Navigator public wrappers
for the same 11 methods, following the existing GetPolyArea /
GetPolyFlags pattern (no IsLoaded check, no lock) to match
HB 6.2.3's style. Tile handles are IntPtr on the C# side.
* Lib/Navigation.dll: rebuilt to include the 11 new NavMesh
methods.
Localization:
--------------
* LootKilledMobs: new resx key + Globalization.Designer.cs
accessor. Used by GatherBuddy's "Loot killed mobs" toggle label
in the settings window (distinct from the existing ChkLootMobs
"Loot Mobs" label, which is the general loot toggle).
Singular wotlk (not yet pushed to origin):
--------------
* Spell.Buff: update DoubleCastPreventionDict unconditionally.
The dict was only updated when the buff was found in the
active spell list; for passives / short-duration auras the
double-cast guard would never learn the cooldown and re-fire
on the next pulse (WotLK QC).
* Hunter/Common: cast Trueshot Aura for MM in PreCombatBuffs +
CombatBuffs. The aura was missing from the BM/MM/SV buff
rotation; MM hunters were not refreshing Trueshot Aura
during combat (WotLK QC).
* SingularRoutine: drop !IsFlying gate from the Rest wrapper.
The previous Decorator condition `!Me.IsFlying && !Me.IsOnTransport
&& !DisableNonCombatBehaviors` blocked Rest while flying. HB
6.2.3 and Singular 5.4.8 do not gate Rest on flying — the
inner behavior itself handles mount cases.
* Druid/Balance: add configurable Barkskin to Normal combat
(matches Singular 4.3.4). New setting `Druid.BalanceBarkskinHealth`
(default 40%) drives a Barkskin trigger with the same
`IsCrowdControlled() || HealthPercent <= threshold` condition
as 4.3.4 `Balance.cs:153`. Restricted to Normal combat (Instance
combat unchanged). (merge commit 710c71b / PR commit eec170a,
contributor ReiDyx, PR #9)
* Movement + Spell: off-target hostile casts now switch target
and face before the cast. Adds `Movement.NeedsOffTargetCastSetup`
(gated on `unit.IsMe`, `unit.IsFriendly`, `IsCasting`, and
`CurrentTarget != unit`) and `Movement.CreateEnsureTargetAndFaceBehavior`.
Integrated into `Spell.Cast` (string and int overloads) inside
a `DecoratorContinue` so heals, self casts, friendly targets,
and CurrentTarget casts all bypass the check. Targets the
multi-dot spread case (Balance Moonfire on a mob behind the
player, Seed of Corruption, etc.). (merge commit 215ab10 /
PR commit a9001ca, contributor ReiDyx, PR #10)
Offmesh connections (extractor-csharp):
--------------
Unstaged changes in
Navigation View3D/Extractor_projects-master/extractor-csharp/offmesh.txt.
* offmesh.txt: bump existing jump radii from 0.4y to 2.0y
(commit 9dd7e9c). New entries for Map 607 (Strand of the
Ancients) — 16 entries covering the defender-side start jumps,
the four coloured gate teleporter landings (Red Sun / Purple
Amethyst / Green Emerald / Blue Sapphire), the Yellow Moon
teleporter, and the per-gate left/right descent jumps. New
entries for Map 628 (Isle of Conquest) — 12 entries: Alliance
Right/Left/Center in-out pairs (gate crossings) and the
matching Horde Right/Center/Left in-out pairs. All new entries
use the 2.0y radius.
Extractor (Navigation View3D/Extractor_projects-master/extractor-csharp):
--------------
* DoodadExtractor: apply WMO worldspawn fix before FixCoords
(commit b930a17). Mirrors the C++ wmo.cpp worldspawn rule
(pos.x and pos.z set to 533.33333*32 when both are zero) so
ADT WMOs whose raw pos is (0, y, 0) on the X/Z axes land at
(32G, 32G, y) instead of (0, 0, y).
* BuildWmoSpawn: mirror wmo.cpp worldspawn fix for ADT WMOs
(commit e471e01). Same root cause as the DoodadExtractor fix —
applies the worldspawn transformation so non-worldspawn WMOs
on terrain maps land at the correct world coordinates.
* M2 winding flip: emit (I1,I2,I0) cyclic permutation, not the
previous (I0,I2,I1) transposition (commit 267f318). The old
order flipped the M2 winding — Recast then saw M2 top faces as
ceilings and the bot walked on the wrong side.
* AppendGameObjectGeometry: align M2 winding with the vmtile M2
path (commit ed99629). GameObjectM2 path loaded raw (A,B,C)
indices from MPQ but emitted a different winding; aligned with
the corrected cyclic permutation.
* Tests: regression for M2 winding flip ordering with a
cross-product check (commit d05c9b1). A unit triangle in Z=+5
is computed for both orders (old vs new); the cross product
must yield +Z for the new winding.
* Tests: add PathfindTest for 1- and 2-mmtile path queries
(commit 9af6341). Standalone helper that loads one or two
.mmtile files and runs TestPathfinding / TestPathfindingTwoFiles
on them. Mirrors the C++ side.
* CLI: route 'pathfind' argv to PathfindTest for ad-hoc nav
diffing (commit 1940abb). Lets a developer drop into the
Release exe with two .mmtile paths and get a side-by-side path
query without rebuilding — no flags, no GUI.
Version numbering:
--------------
Previous: v1.5.0 (Update 12).
Current: v1.5.2 (minor bump).
==========================
Bug fixes — BGBuddy:
--------------
* BGBuddy/SOTA: fix AFK loop, use IsOnTransport instead of nearby
Transport GO. The previous IsOnTransport gate relied on a nearby
transport game object being present in the object manager; on
some SOTA intro phases the GO query returned null even though the
player was already mounted on the transport, so the bot stayed
stuck in the AFK/idle loop. Switched the gate to the local player
IsOnTransport flag (read once per pulse).
Bug fixes — DungeonBuddy:
--------------
* LfgManager: dynamic random dungeon lookup by level via LfgDungeons
DBC. QueueForRandomDungeon / QueueForRandomHeroic used to hardcode
IDs 261/262 (WotLK Random Normal/Heroic, level 69-80 and 80-83
respectively), so any character below level 69 queued an ID the
server would reject with "you do not meet the requirements for
the chosen dungeon" (e.g. a level 56 user enabling the bot got
the error on every queue attempt). The new implementation
iterates the already-loaded LfgDungeons DBC, filters on
IsRandomDungeon (TypeId==6) + the requested Difficulty + the
player's level, and feeds the first matching ID to
SetLFGDungeon + JoinLFG. Level 56 now matches TBC/Classic random,
level 80 still gets the WotLK random categories. API surface
(SetLFGDungeon, JoinLFG, ClearAllLFGDungeons) verified against
Wow_12340.exe string table — the same native bindings used by
the previous implementation. Pattern matches HB 6.2.3's
LfgDungeons.Dungeons.Where(...) approach; the underlying DBC
wrapper is itself a port of HB 4.3.4's LfgDungeons.dbc schema.
(commit 80a5d84)
Bug fixes — GatherBuddy:
--------------
* GatherBuddy: spirit healer auto-fallback now accepts the resurrect
properly. When the corpse has no mesh (player died in mid-air,
corpse dropped to an unreachable location) the bot triggers the
spirit healer fallback per HB 4.3.4 GatherbuddyBot.smethod_94
pattern (UseSpiritHealer || (!CanFly && !CanNavigateFully)), but
the inline spirit healer sequence at GatherbuddyBot.cs:535-552
blindly clicked StaticPopup1Button1 after a fixed 1s sleep,
regardless of whether the resurrection popup was actually visible
— when no popup was visible (or another StaticPopup1 had stolen
the slot, e.g. a loot frame), the click went to nothing, the
resurrect was never accepted, and the bot entered an infinite
loop of "interact with spirit healer + try corpse + die again".
Each click now checks `if StaticPopup1 and StaticPopup1:IsVisible()`
first and falls back to the native `AcceptResurrect()` API
(verified in Wow_12340.exe string table at 0x9fdf2c) when no
popup is showing. Same double-click + 1000/500/2000ms timing as
HB 4.3.4 (GatherbuddyBot.smethod_95), only the click target is
conditional. (commit 87115a1)
Bug fixes — GatherBuddy:
--------------
* GatherBuddy: drop (!Mounted||!Flying) gate on the [4] combat
subtree. The gate prevented the combat subtree from running while
mounted, which also blocked combat in ground-mount zones where
engaging mobs from the mount is the intended behaviour (HB 4.3.4
and 6.2.3 do not gate the combat subtree on mount state).
* GatherBuddy: rename Loot checkbox key to ChkLootMobs (ChkXxx
convention). Existing ChkLootMobs key was a leftover from a
partial rename; aligned all Loot* keys to the ChkXxx pattern.
Bug fixes — Settings:
--------------
* fix: persist enabled plugins across restarts. The plugin-enabled
state was being written to the in-memory dictionary but not
flushed to Settings.xml on shutdown, so the next launch reverted
every plugin to its compile-time default. Settings now serialise
the enabled-plugin set on BotEvents.OnBotStopped. (PR #1,
Lofbergio/fix/plugin-enabled-persistence)
Bug fixes — LevelBot:
--------------
* LevelBot: restore 1500ms sleep in OnMobKilled. The original HB
4.3.4 LevelBot.smethod_17 OnMobKilled handler waits 1500ms after
a kill so the server-side UnitDynamicFlags.Lootable update
arrives in the client before the next LootTargeting.Pulse tick.
Commit 5905052 removed this sleep based on a misread of the HB
5.4.8 / 6.2.3 reference (those versions moved the handler into
a different file with timer-reset semantics instead of a
blocking sleep, but CopilotBuddy still uses the original LevelBot
flow). The mid-Pulse emptiness of the loot flag was what was
causing loots to be skipped or to hit the WaitLuaEvent
LOOT_OPENED timeout and trigger the "blacklist for 5-10 min"
fallback. Restored to the HB 4.3.4 ground truth.
(commits 6369037 / 872ec43)
Navigation:
--------------
* Navigation C++: port HB 6.2.3 NavMesh API — 11 methods ported
as thin wrappers around dtNavMesh: GetMaxTiles(mapId),
EncodePolyId(mapId, salt, it, ip), DecodePolyId(mapId, ref, out
salt, out it, out ip), DecodePolyIdSalt/Tile/Poly(mapId, ref),
GetTileAt(mapId, x, y), GetTile(mapId, i), GetTileStateSize,
StoreTileState, RestoreTileState. Tile pointers exposed as
`const void*` for C API compatibility (cast as IntPtr on the
C# side). mapId is added to every signature to support
CopilotBuddy's multi-map context (HB 6.2.3 has a single mesh
via this._mesh). GetTileAt passes layer=0 to match HB 6.2.3's
call shape and V4 mmtiles (single layer per coord).
* Bot-side: P/Invoke declarations + Navigator public wrappers
for the same 11 methods, following the existing GetPolyArea /
GetPolyFlags pattern (no IsLoaded check, no lock) to match
HB 6.2.3's style. Tile handles are IntPtr on the C# side.
* Lib/Navigation.dll: rebuilt to include the 11 new NavMesh
methods.
Localization:
--------------
* LootKilledMobs: new resx key + Globalization.Designer.cs
accessor. Used by GatherBuddy's "Loot killed mobs" toggle label
in the settings window (distinct from the existing ChkLootMobs
"Loot Mobs" label, which is the general loot toggle).
Singular wotlk (not yet pushed to origin):
--------------
* Spell.Buff: update DoubleCastPreventionDict unconditionally.
The dict was only updated when the buff was found in the
active spell list; for passives / short-duration auras the
double-cast guard would never learn the cooldown and re-fire
on the next pulse (WotLK QC).
* Hunter/Common: cast Trueshot Aura for MM in PreCombatBuffs +
CombatBuffs. The aura was missing from the BM/MM/SV buff
rotation; MM hunters were not refreshing Trueshot Aura
during combat (WotLK QC).
* SingularRoutine: drop !IsFlying gate from the Rest wrapper.
The previous Decorator condition `!Me.IsFlying && !Me.IsOnTransport
&& !DisableNonCombatBehaviors` blocked Rest while flying. HB
6.2.3 and Singular 5.4.8 do not gate Rest on flying — the
inner behavior itself handles mount cases.
* Druid/Balance: add configurable Barkskin to Normal combat
(matches Singular 4.3.4). New setting `Druid.BalanceBarkskinHealth`
(default 40%) drives a Barkskin trigger with the same
`IsCrowdControlled() || HealthPercent <= threshold` condition
as 4.3.4 `Balance.cs:153`. Restricted to Normal combat (Instance
combat unchanged). (merge commit 710c71b / PR commit eec170a,
contributor ReiDyx, PR #9)
* Movement + Spell: off-target hostile casts now switch target
and face before the cast. Adds `Movement.NeedsOffTargetCastSetup`
(gated on `unit.IsMe`, `unit.IsFriendly`, `IsCasting`, and
`CurrentTarget != unit`) and `Movement.CreateEnsureTargetAndFaceBehavior`.
Integrated into `Spell.Cast` (string and int overloads) inside
a `DecoratorContinue` so heals, self casts, friendly targets,
and CurrentTarget casts all bypass the check. Targets the
multi-dot spread case (Balance Moonfire on a mob behind the
player, Seed of Corruption, etc.). (merge commit 215ab10 /
PR commit a9001ca, contributor ReiDyx, PR #10)
Offmesh connections (extractor-csharp):
--------------
Unstaged changes in
Navigation View3D/Extractor_projects-master/extractor-csharp/offmesh.txt.
* offmesh.txt: bump existing jump radii from 0.4y to 2.0y
(commit 9dd7e9c). New entries for Map 607 (Strand of the
Ancients) — 16 entries covering the defender-side start jumps,
the four coloured gate teleporter landings (Red Sun / Purple
Amethyst / Green Emerald / Blue Sapphire), the Yellow Moon
teleporter, and the per-gate left/right descent jumps. New
entries for Map 628 (Isle of Conquest) — 12 entries: Alliance
Right/Left/Center in-out pairs (gate crossings) and the
matching Horde Right/Center/Left in-out pairs. All new entries
use the 2.0y radius.
Extractor (Navigation View3D/Extractor_projects-master/extractor-csharp):
--------------
* DoodadExtractor: apply WMO worldspawn fix before FixCoords
(commit b930a17). Mirrors the C++ wmo.cpp worldspawn rule
(pos.x and pos.z set to 533.33333*32 when both are zero) so
ADT WMOs whose raw pos is (0, y, 0) on the X/Z axes land at
(32G, 32G, y) instead of (0, 0, y).
* BuildWmoSpawn: mirror wmo.cpp worldspawn fix for ADT WMOs
(commit e471e01). Same root cause as the DoodadExtractor fix —
applies the worldspawn transformation so non-worldspawn WMOs
on terrain maps land at the correct world coordinates.
* M2 winding flip: emit (I1,I2,I0) cyclic permutation, not the
previous (I0,I2,I1) transposition (commit 267f318). The old
order flipped the M2 winding — Recast then saw M2 top faces as
ceilings and the bot walked on the wrong side.
* AppendGameObjectGeometry: align M2 winding with the vmtile M2
path (commit ed99629). GameObjectM2 path loaded raw (A,B,C)
indices from MPQ but emitted a different winding; aligned with
the corrected cyclic permutation.
* Tests: regression for M2 winding flip ordering with a
cross-product check (commit d05c9b1). A unit triangle in Z=+5
is computed for both orders (old vs new); the cross product
must yield +Z for the new winding.
* Tests: add PathfindTest for 1- and 2-mmtile path queries
(commit 9af6341). Standalone helper that loads one or two
.mmtile files and runs TestPathfinding / TestPathfindingTwoFiles
on them. Mirrors the C++ side.
* CLI: route 'pathfind' argv to PathfindTest for ad-hoc nav
diffing (commit 1940abb). Lets a developer drop into the
Release exe with two .mmtile paths and get a side-by-side path
query without rebuilding — no flags, no GUI.
Version numbering:
--------------
Previous: v1.5.0 (Update 12).
Current: v1.5.2 (minor bump).