mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-06 05:03:52 +00:00
Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND, anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1) lookup, and flyVariant() compact 218-element ground→FLY_* resolver. Expand AnimationController into a full state machine with 20+ named states: spell cast (directed→omni→cast fallback chain, instant one-shot release), hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle, stealth animation substitution, loot, fishing channel, sit/sleep/kneel down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons (BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY, vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS), emote state variants, off-hand/pierce/dual-wield alternation, NPC birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell. Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo (12 constants) namespaces; replace all magic numbers in spell_handler.cpp. Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire GameObjectStateCallback. Add DBC cross-validation on world entry. Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and asset_pipeline_gui.py. Add tests/test_animation_ids.cpp. Bug fixes included: - Stand state 1 was animating READY_2H(27) — fixed to SITTING(97) - Spell casts ended freeze-frame — add one-shot release animation - NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff) - Chair sits (states 2/4/5/6) incorrectly played floor-sit transition - STOP(3) used for all spell casts — replaced with model-aware chain
192 lines
5 KiB
C++
192 lines
5 KiB
C++
// Packet read/write round-trip, packed GUID, bounds checks
|
|
#include <catch_amalgamated.hpp>
|
|
#include "network/packet.hpp"
|
|
|
|
using wowee::network::Packet;
|
|
|
|
TEST_CASE("Packet default constructor", "[packet]") {
|
|
Packet p;
|
|
REQUIRE(p.getOpcode() == 0);
|
|
REQUIRE(p.getSize() == 0);
|
|
REQUIRE(p.getReadPos() == 0);
|
|
REQUIRE(p.getRemainingSize() == 0);
|
|
REQUIRE_FALSE(p.hasData());
|
|
}
|
|
|
|
TEST_CASE("Packet opcode constructor", "[packet]") {
|
|
Packet p(0x1DC);
|
|
REQUIRE(p.getOpcode() == 0x1DC);
|
|
REQUIRE(p.getSize() == 0);
|
|
}
|
|
|
|
TEST_CASE("Packet write/read UInt8 round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt8(0);
|
|
p.writeUInt8(127);
|
|
p.writeUInt8(255);
|
|
REQUIRE(p.getSize() == 3);
|
|
|
|
REQUIRE(p.readUInt8() == 0);
|
|
REQUIRE(p.readUInt8() == 127);
|
|
REQUIRE(p.readUInt8() == 255);
|
|
REQUIRE_FALSE(p.hasData());
|
|
}
|
|
|
|
TEST_CASE("Packet write/read UInt16 round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt16(0);
|
|
p.writeUInt16(0xBEEF);
|
|
p.writeUInt16(0xFFFF);
|
|
REQUIRE(p.getSize() == 6);
|
|
|
|
REQUIRE(p.readUInt16() == 0);
|
|
REQUIRE(p.readUInt16() == 0xBEEF);
|
|
REQUIRE(p.readUInt16() == 0xFFFF);
|
|
}
|
|
|
|
TEST_CASE("Packet write/read UInt32 round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt32(0xDEADBEEF);
|
|
REQUIRE(p.readUInt32() == 0xDEADBEEF);
|
|
}
|
|
|
|
TEST_CASE("Packet write/read UInt64 round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt64(0x0123456789ABCDEFULL);
|
|
REQUIRE(p.readUInt64() == 0x0123456789ABCDEFULL);
|
|
}
|
|
|
|
TEST_CASE("Packet write/read float round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeFloat(3.14f);
|
|
p.writeFloat(-0.0f);
|
|
p.writeFloat(1e10f);
|
|
REQUIRE(p.readFloat() == Catch::Approx(3.14f));
|
|
REQUIRE(p.readFloat() == -0.0f);
|
|
REQUIRE(p.readFloat() == Catch::Approx(1e10f));
|
|
}
|
|
|
|
TEST_CASE("Packet write/read string round-trip", "[packet]") {
|
|
Packet p(1);
|
|
p.writeString("Hello WoW");
|
|
p.writeString(""); // empty string
|
|
REQUIRE(p.readString() == "Hello WoW");
|
|
REQUIRE(p.readString() == "");
|
|
}
|
|
|
|
TEST_CASE("Packet writeBytes / readUInt8 array", "[packet]") {
|
|
Packet p(1);
|
|
const uint8_t buf[] = {0xAA, 0xBB, 0xCC};
|
|
p.writeBytes(buf, 3);
|
|
REQUIRE(p.getSize() == 3);
|
|
REQUIRE(p.readUInt8() == 0xAA);
|
|
REQUIRE(p.readUInt8() == 0xBB);
|
|
REQUIRE(p.readUInt8() == 0xCC);
|
|
}
|
|
|
|
TEST_CASE("Packet packed GUID round-trip", "[packet]") {
|
|
SECTION("Zero GUID") {
|
|
Packet p(1);
|
|
p.writePackedGuid(0);
|
|
REQUIRE(p.hasFullPackedGuid());
|
|
REQUIRE(p.readPackedGuid() == 0);
|
|
}
|
|
|
|
SECTION("Low GUID (single byte)") {
|
|
Packet p(1);
|
|
p.writePackedGuid(0x42);
|
|
REQUIRE(p.readPackedGuid() == 0x42);
|
|
}
|
|
|
|
SECTION("Full 64-bit GUID") {
|
|
Packet p(1);
|
|
uint64_t guid = 0x0102030405060708ULL;
|
|
p.writePackedGuid(guid);
|
|
REQUIRE(p.readPackedGuid() == guid);
|
|
}
|
|
|
|
SECTION("Max GUID") {
|
|
Packet p(1);
|
|
uint64_t guid = 0xFFFFFFFFFFFFFFFFULL;
|
|
p.writePackedGuid(guid);
|
|
REQUIRE(p.readPackedGuid() == guid);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Packet getRemainingSize and hasRemaining", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt32(100);
|
|
p.writeUInt32(200);
|
|
REQUIRE(p.getRemainingSize() == 8);
|
|
REQUIRE(p.hasRemaining(8));
|
|
REQUIRE_FALSE(p.hasRemaining(9));
|
|
|
|
p.readUInt32();
|
|
REQUIRE(p.getRemainingSize() == 4);
|
|
REQUIRE(p.hasRemaining(4));
|
|
REQUIRE_FALSE(p.hasRemaining(5));
|
|
|
|
p.readUInt32();
|
|
REQUIRE(p.getRemainingSize() == 0);
|
|
REQUIRE(p.hasRemaining(0));
|
|
REQUIRE_FALSE(p.hasRemaining(1));
|
|
}
|
|
|
|
TEST_CASE("Packet setReadPos and skipAll", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt8(10);
|
|
p.writeUInt8(20);
|
|
p.writeUInt8(30);
|
|
|
|
p.readUInt8(); // pos = 1
|
|
p.setReadPos(0);
|
|
REQUIRE(p.readUInt8() == 10);
|
|
|
|
p.skipAll();
|
|
REQUIRE(p.getRemainingSize() == 0);
|
|
REQUIRE_FALSE(p.hasData());
|
|
}
|
|
|
|
TEST_CASE("Packet constructed with data vector", "[packet]") {
|
|
std::vector<uint8_t> raw = {0x01, 0x02, 0x03};
|
|
Packet p(42, raw);
|
|
REQUIRE(p.getOpcode() == 42);
|
|
REQUIRE(p.getSize() == 3);
|
|
REQUIRE(p.readUInt8() == 0x01);
|
|
}
|
|
|
|
TEST_CASE("Packet constructed with rvalue data", "[packet]") {
|
|
Packet p(99, std::vector<uint8_t>{0xFF, 0xFE});
|
|
REQUIRE(p.getSize() == 2);
|
|
REQUIRE(p.readUInt8() == 0xFF);
|
|
REQUIRE(p.readUInt8() == 0xFE);
|
|
}
|
|
|
|
TEST_CASE("Packet mixed types interleaved", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt8(0xAA);
|
|
p.writeUInt32(0xDEADBEEF);
|
|
p.writeString("test");
|
|
p.writeFloat(2.5f);
|
|
p.writeUInt16(0x1234);
|
|
|
|
REQUIRE(p.readUInt8() == 0xAA);
|
|
REQUIRE(p.readUInt32() == 0xDEADBEEF);
|
|
REQUIRE(p.readString() == "test");
|
|
REQUIRE(p.readFloat() == Catch::Approx(2.5f));
|
|
REQUIRE(p.readUInt16() == 0x1234);
|
|
REQUIRE_FALSE(p.hasData());
|
|
}
|
|
|
|
TEST_CASE("Packet hasFullPackedGuid returns false on empty", "[packet]") {
|
|
Packet p(1);
|
|
REQUIRE_FALSE(p.hasFullPackedGuid());
|
|
}
|
|
|
|
TEST_CASE("Packet getRemainingSize clamps after overshoot", "[packet]") {
|
|
Packet p(1);
|
|
p.writeUInt8(1);
|
|
p.setReadPos(999);
|
|
REQUIRE(p.getRemainingSize() == 0);
|
|
REQUIRE_FALSE(p.hasRemaining(1));
|
|
}
|