mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-10 20:07:37 +00:00
feat(unit): softenemy and softfriend fire unit events
Unit::TokenEvents already redirects the 38 broadcast and 4 combat feedback call sites so a unit holding focus / nameplateN / markN gets every engine unit event under that token. softenemy and softfriend join that token list, read through SoftUnit::Current (the last pick, no scan) because TokensOf runs on every unit event. The registration bit (UNIT_SCRIPT_REG_TOKENS) is what makes the engine watch a unit, so SoftUnit::Refresh re-runs FUN_UNIT_SCRIPT_RECOMPUTE through TokenEvents::Refresh for the old and new guid before the PLAYER_SOFT_*_CHANGED event fires. The frame tick now picks every frame rather than only while that event has a listener: a UNIT_HEALTH listener never registers for it, and the pick is cached per scene drain anyway.
This commit is contained in:
+14
-12
@@ -39,8 +39,9 @@
|
||||
// SoftTargetWithLocked 1. The arcs are not: Classic Era's 2 picks the
|
||||
// nearest unit wherever the camera looks, so both default to 0, the
|
||||
// interact arc's (the unit in front of the camera).
|
||||
// Picked when something asks (a read of a token) and on the UI frame tick
|
||||
// only while a frame is registered for the side's event.
|
||||
// Picked on the UI frame tick and when something asks (a read of a token).
|
||||
// The softenemy / softfriend unit events (UNIT_HEALTH, …) follow the pick via
|
||||
// Unit::TokenEvents, as they do for focus.
|
||||
|
||||
#include "target/SoftUnit.h"
|
||||
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "target/Nearest.h"
|
||||
#include "target/SoftTarget.h"
|
||||
#include "tick/FrameTick.h"
|
||||
#include "unit/TokenEvents.h"
|
||||
|
||||
namespace Target::SoftUnit {
|
||||
|
||||
@@ -124,8 +126,6 @@ uint64_t Pick(State &st) {
|
||||
return SoftTarget::Nearest(area, Offsets::TYPEMASK_UNIT, &Accept, &st);
|
||||
}
|
||||
|
||||
bool Watched(const State &st) { return Event::Custom::HasListeners(st.changed->Slot()); }
|
||||
|
||||
// One pick per side per scene drain. The scan reads what the last drain drew,
|
||||
// which changes only when the next one does, so every read until then — the
|
||||
// circles, the icons, Lua's token reads — shares the first one's answer. The
|
||||
@@ -142,7 +142,12 @@ void Refresh(State &st) {
|
||||
const uint64_t guid = Pick(st);
|
||||
if (guid == st.soft)
|
||||
return;
|
||||
const uint64_t old = st.soft;
|
||||
st.soft = guid;
|
||||
// The token's unit events follow the pick (the engine watches a unit
|
||||
// that holds a token), so the registration moves before the event fires.
|
||||
Unit::TokenEvents::Refresh(old);
|
||||
Unit::TokenEvents::Refresh(guid);
|
||||
Event::Custom::Fire(st.changed->Slot(), "");
|
||||
}
|
||||
|
||||
@@ -152,10 +157,8 @@ void OnFrameTick() {
|
||||
g_friend.soft = 0;
|
||||
return;
|
||||
}
|
||||
if (Watched(g_enemy))
|
||||
Refresh(g_enemy);
|
||||
if (Watched(g_friend))
|
||||
Refresh(g_friend);
|
||||
Refresh(g_enemy);
|
||||
Refresh(g_friend);
|
||||
}
|
||||
|
||||
const Tick::FrameTick::AutoSubscribe _tick{&OnFrameTick};
|
||||
@@ -193,17 +196,16 @@ const Game::ModuleAutoRegister _autoreg{&Register};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Fresh when nothing watches; the frame tick's pick (this frame's) when a
|
||||
// listener does.
|
||||
uint64_t Get(Side side) {
|
||||
if (!Object::RegistryReady())
|
||||
return 0;
|
||||
State &st = Of(side);
|
||||
if (!Watched(st))
|
||||
Refresh(st);
|
||||
Refresh(st);
|
||||
return st.soft;
|
||||
}
|
||||
|
||||
uint64_t Current(Side side) { return Of(side).soft; }
|
||||
|
||||
// Classic Era 1.15 probes, `anyfriend`: a target that qualifies, else
|
||||
// `softfriend`, else the target whatever its reaction (a hostile one, or a
|
||||
// friendly NPC the friend test rejects), else `softenemy` (no target, no
|
||||
|
||||
@@ -23,6 +23,10 @@ enum class Side { Enemy, Friend };
|
||||
// `unit/TokenExtensions.cpp`.
|
||||
uint64_t Get(Side side);
|
||||
|
||||
// The last pick, with no scan. For the unit-event hot path
|
||||
// (`unit/TokenEvents.cpp`); the frame tick keeps it current.
|
||||
uint64_t Current(Side side);
|
||||
|
||||
// SoftTargetEnemy / SoftTargetFriend turns the side on.
|
||||
bool Enabled(Side side);
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Every unit event the engine fires reaches ClassicAPI's unit tokens —
|
||||
// `focus`, `nameplateN`, `markN` — as it reaches `target`.
|
||||
// `focus`, `nameplateN`, `markN`, `softenemy`, `softfriend` — as it reaches
|
||||
// `target`.
|
||||
//
|
||||
// This is how 4.3.4 makes its focus a full unit token (decomp: GameUI.cpp
|
||||
// SetFocusTarget, ScriptEvents.cpp token maps), in two steps: the unit gets a
|
||||
@@ -56,6 +57,7 @@
|
||||
#include "debug/Log.h"
|
||||
#include "nameplate/Walk.h"
|
||||
#include "object/Resolve.h"
|
||||
#include "target/SoftUnit.h"
|
||||
#include "unit/Focus.h"
|
||||
#include "unit/Identity.h"
|
||||
#include "unit/RaidTarget.h"
|
||||
@@ -76,8 +78,8 @@ using Broadcast_t = void(__fastcall *)(const uint64_t *guid, uint32_t eventId);
|
||||
using CombatFeedback_t = void(__fastcall *)(const uint64_t *guid, const char *action, int amount,
|
||||
int school, uint32_t hitInfo);
|
||||
|
||||
// At most one focus, one nameplate and one mark per unit.
|
||||
constexpr int kMaxTokens = 3;
|
||||
// At most one focus, nameplate, mark, softenemy and softfriend per unit.
|
||||
constexpr int kMaxTokens = 5;
|
||||
using TokenList = char[kMaxTokens][24];
|
||||
|
||||
// The ClassicAPI tokens `guid` has right now, in UnitTokenFromGUID's order.
|
||||
@@ -97,6 +99,10 @@ int TokensOf(uint64_t guid, TokenList &out) {
|
||||
std::snprintf(out[n++], sizeof out[0], "mark%d", m);
|
||||
break;
|
||||
}
|
||||
if (guid == Target::SoftUnit::Current(Target::SoftUnit::Side::Enemy))
|
||||
std::snprintf(out[n++], sizeof out[0], "softenemy");
|
||||
if (guid == Target::SoftUnit::Current(Target::SoftUnit::Side::Friend))
|
||||
std::snprintf(out[n++], sizeof out[0], "softfriend");
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user