mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Implement minimap ping: parse MSG_MINIMAP_PING and render animated ping circles
Parse party member minimap pings (packed GUID + posX + posY), store with 5s lifetime, and render as expanding concentric circles on the minimap.
This commit is contained in:
parent
0562139868
commit
95e8fcb88e
3 changed files with 53 additions and 3 deletions
|
|
@ -466,6 +466,24 @@ public:
|
||||||
bool canUseWeaponSubclass(uint32_t subClass) const { return (weaponProficiency_ >> subClass) & 1u; }
|
bool canUseWeaponSubclass(uint32_t subClass) const { return (weaponProficiency_ >> subClass) & 1u; }
|
||||||
bool canUseArmorSubclass(uint32_t subClass) const { return (armorProficiency_ >> subClass) & 1u; }
|
bool canUseArmorSubclass(uint32_t subClass) const { return (armorProficiency_ >> subClass) & 1u; }
|
||||||
|
|
||||||
|
// Minimap pings from party members
|
||||||
|
struct MinimapPing {
|
||||||
|
uint64_t senderGuid = 0;
|
||||||
|
float wowX = 0.0f; // canonical WoW X (north)
|
||||||
|
float wowY = 0.0f; // canonical WoW Y (west)
|
||||||
|
float age = 0.0f; // seconds since received
|
||||||
|
static constexpr float LIFETIME = 5.0f;
|
||||||
|
bool isExpired() const { return age >= LIFETIME; }
|
||||||
|
};
|
||||||
|
const std::vector<MinimapPing>& getMinimapPings() const { return minimapPings_; }
|
||||||
|
void tickMinimapPings(float dt) {
|
||||||
|
for (auto& p : minimapPings_) p.age += dt;
|
||||||
|
minimapPings_.erase(
|
||||||
|
std::remove_if(minimapPings_.begin(), minimapPings_.end(),
|
||||||
|
[](const MinimapPing& p){ return p.isExpired(); }),
|
||||||
|
minimapPings_.end());
|
||||||
|
}
|
||||||
|
|
||||||
bool isCasting() const { return casting; }
|
bool isCasting() const { return casting; }
|
||||||
bool isGameObjectInteractionCasting() const {
|
bool isGameObjectInteractionCasting() const {
|
||||||
return casting && currentCastSpellId == 0 && pendingGameObjectInteractGuid_ != 0;
|
return casting && currentCastSpellId == 0 && pendingGameObjectInteractGuid_ != 0;
|
||||||
|
|
@ -1698,6 +1716,7 @@ private:
|
||||||
std::unordered_map<uint32_t, float> spellCooldowns; // spellId -> remaining seconds
|
std::unordered_map<uint32_t, float> spellCooldowns; // spellId -> remaining seconds
|
||||||
uint32_t weaponProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=2
|
uint32_t weaponProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=2
|
||||||
uint32_t armorProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=4
|
uint32_t armorProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=4
|
||||||
|
std::vector<MinimapPing> minimapPings_;
|
||||||
uint8_t castCount = 0;
|
uint8_t castCount = 0;
|
||||||
bool casting = false;
|
bool casting = false;
|
||||||
uint32_t currentCastSpellId = 0;
|
uint32_t currentCastSpellId = 0;
|
||||||
|
|
|
||||||
|
|
@ -779,6 +779,7 @@ void GameHandler::update(float deltaTime) {
|
||||||
|
|
||||||
// Update combat text (Phase 2)
|
// Update combat text (Phase 2)
|
||||||
updateCombatText(deltaTime);
|
updateCombatText(deltaTime);
|
||||||
|
tickMinimapPings(deltaTime);
|
||||||
|
|
||||||
// Update taxi landing cooldown
|
// Update taxi landing cooldown
|
||||||
if (taxiLandingCooldown_ > 0.0f) {
|
if (taxiLandingCooldown_ > 0.0f) {
|
||||||
|
|
@ -2588,10 +2589,21 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
case Opcode::SMSG_FISH_ESCAPED:
|
case Opcode::SMSG_FISH_ESCAPED:
|
||||||
addSystemChatMessage("Your fish escaped!");
|
addSystemChatMessage("Your fish escaped!");
|
||||||
break;
|
break;
|
||||||
case Opcode::MSG_MINIMAP_PING:
|
case Opcode::MSG_MINIMAP_PING: {
|
||||||
// Minimap ping from a party member — consume; no visual support yet.
|
// SMSG: packed_guid + float posX (canonical WoW Y=west) + float posY (canonical WoW X=north)
|
||||||
packet.setReadPos(packet.getSize());
|
if (packet.getSize() - packet.getReadPos() < 1) break;
|
||||||
|
uint64_t senderGuid = UpdateObjectParser::readPackedGuid(packet);
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 8) break;
|
||||||
|
float pingX = packet.readFloat(); // server sends map-coord X (east-west)
|
||||||
|
float pingY = packet.readFloat(); // server sends map-coord Y (north-south)
|
||||||
|
MinimapPing ping;
|
||||||
|
ping.senderGuid = senderGuid;
|
||||||
|
ping.wowX = pingY; // canonical WoW X = north = server's posY
|
||||||
|
ping.wowY = pingX; // canonical WoW Y = west = server's posX
|
||||||
|
ping.age = 0.0f;
|
||||||
|
minimapPings_.push_back(ping);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Opcode::SMSG_ZONE_UNDER_ATTACK: {
|
case Opcode::SMSG_ZONE_UNDER_ATTACK: {
|
||||||
// uint32 areaId
|
// uint32 areaId
|
||||||
if (packet.getSize() - packet.getReadPos() >= 4) {
|
if (packet.getSize() - packet.getReadPos() >= 4) {
|
||||||
|
|
|
||||||
|
|
@ -8040,6 +8040,25 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Minimap pings from party members
|
||||||
|
for (const auto& ping : gameHandler.getMinimapPings()) {
|
||||||
|
glm::vec3 pingRender = core::coords::canonicalToRender(glm::vec3(ping.wowX, ping.wowY, 0.0f));
|
||||||
|
float sx = 0.0f, sy = 0.0f;
|
||||||
|
if (!projectToMinimap(pingRender, sx, sy)) continue;
|
||||||
|
|
||||||
|
float t = ping.age / game::GameHandler::MinimapPing::LIFETIME;
|
||||||
|
float alpha = 1.0f - t;
|
||||||
|
float pulse = 1.0f + 1.5f * t; // expands outward as it fades
|
||||||
|
|
||||||
|
ImU32 col = IM_COL32(255, 220, 0, static_cast<int>(alpha * 200));
|
||||||
|
ImU32 col2 = IM_COL32(255, 150, 0, static_cast<int>(alpha * 100));
|
||||||
|
float r1 = 4.0f * pulse;
|
||||||
|
float r2 = 8.0f * pulse;
|
||||||
|
drawList->AddCircle(ImVec2(sx, sy), r1, col, 16, 2.0f);
|
||||||
|
drawList->AddCircle(ImVec2(sx, sy), r2, col2, 16, 1.0f);
|
||||||
|
drawList->AddCircleFilled(ImVec2(sx, sy), 2.5f, col);
|
||||||
|
}
|
||||||
|
|
||||||
auto applyMuteState = [&]() {
|
auto applyMuteState = [&]() {
|
||||||
auto* activeRenderer = core::Application::getInstance().getRenderer();
|
auto* activeRenderer = core::Application::getInstance().getRenderer();
|
||||||
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
|
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue