From a8730bc5e4bc1705099447cda8e3165733e82a9e Mon Sep 17 00:00:00 2001 From: Paal Gyula Date: Wed, 31 May 2023 13:50:34 +0200 Subject: [PATCH] Generated and added some more wow constants --- .gitignore | 2 +- pkg/summit/world/character.go | 7 +- pkg/summit/world/object/gameobject.go | 20 ++ pkg/summit/world/object/object.go | 49 +++- pkg/summit/world/object/player/fields.go | 5 - pkg/summit/world/object/player/movement.go | 25 +++ pkg/summit/world/object/player/player.go | 212 ++++++++++++++---- pkg/summit/world/object/transport.go | 4 + pkg/summit/world/object/unit.go | 40 ++++ pkg/summit/world/packets/codetable.go | 44 +--- pkg/summit/world/packets/opcodes.go | 45 ++++ pkg/summit/world/updater.go | 249 +++++++++++++++++++++ pkg/wow/dbc/converter.go | 10 - pkg/wow/dbc/reader.go | 172 -------------- pkg/wow/gameobject.go | 41 ++++ pkg/wow/guid.go | 33 +++ pkg/wow/interfaces.go | 17 +- pkg/wow/movement.go | 56 +++++ pkg/wow/object.go | 15 ++ pkg/wow/packet.go | 4 + pkg/wow/player.go | 56 +++++ pkg/wow/unit.go | 28 +++ pkg/wow/update.go | 25 +++ summit.code-workspace | 4 +- 24 files changed, 879 insertions(+), 284 deletions(-) create mode 100644 pkg/summit/world/object/gameobject.go delete mode 100644 pkg/summit/world/object/player/fields.go create mode 100644 pkg/summit/world/object/player/movement.go create mode 100644 pkg/summit/world/object/transport.go create mode 100644 pkg/summit/world/object/unit.go create mode 100644 pkg/summit/world/packets/opcodes.go create mode 100644 pkg/summit/world/updater.go delete mode 100644 pkg/wow/dbc/converter.go delete mode 100644 pkg/wow/dbc/reader.go create mode 100644 pkg/wow/gameobject.go create mode 100644 pkg/wow/movement.go create mode 100644 pkg/wow/object.go create mode 100644 pkg/wow/player.go create mode 100644 pkg/wow/unit.go create mode 100644 pkg/wow/update.go diff --git a/.gitignore b/.gitignore index 300114b..600383d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ bin/ -./dbc/* +/dbc/ lib server **/__debug_bin diff --git a/pkg/summit/world/character.go b/pkg/summit/world/character.go index 3419eee..bd7d493 100644 --- a/pkg/summit/world/character.go +++ b/pkg/summit/world/character.go @@ -51,6 +51,7 @@ func (gc *GameClient) CreateCharacter(data wow.PacketData) { // fmt.Printf("%s %+v\n", characerName, req) + // TODO: #2 when the DBC reader is ready this should be re-written loc := player.WorldLocation{ X: 10311.3, Y: 832.463, @@ -61,9 +62,9 @@ func (gc *GameClient) CreateCharacter(data wow.PacketData) { p := player.Player{ Name: characerName, - Race: player.PlayerRace(req.Race), - Class: player.PlayerClass(req.Class), - Gender: player.PlayerGender(req.Gender), + Race: wow.PlayerRace(req.Race), + Class: wow.PlayerClass(req.Class), + Gender: wow.PlayerGender(req.Gender), Skin: req.Skin, Face: req.Face, HairStyle: req.HairStyle, diff --git a/pkg/summit/world/object/gameobject.go b/pkg/summit/world/object/gameobject.go new file mode 100644 index 0000000..90f1290 --- /dev/null +++ b/pkg/summit/world/object/gameobject.go @@ -0,0 +1,20 @@ +package object + +type GameObject struct { + *Object +} + +func NewGameObject() *GameObject { + gobject := &GameObject{ + Object: NewObject(), + } + + // m_objectType |= TYPEMASK_GAMEOBJECT + // m_objectTypeId = TYPEID_GAMEOBJECT + // 2.3.2 - 0x58 + // m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION) + + // m_valuesCount = GAMEOBJECT_END + + return gobject +} diff --git a/pkg/summit/world/object/object.go b/pkg/summit/world/object/object.go index d9b68a6..c0f7c9d 100644 --- a/pkg/summit/world/object/object.go +++ b/pkg/summit/world/object/object.go @@ -1,6 +1,8 @@ package object -import "github.com/paalgyula/summit/pkg/wow" +import ( + "github.com/paalgyula/summit/pkg/wow" +) // 1973 in MoP? Seems 1326 in wotlk const dataLength int = int(wow.NumMsgTypes) @@ -10,12 +12,51 @@ type Object struct { UpdateData []wow.Packet UpdateMask *UpdateMask + + movementFlags wow.MovementFlag + + objectTypeID wow.TypeID + objectType wow.TypeMask + + isInWorld bool + isUpdated bool + + uint32Values int + valuesCount int + + updateFlags wow.ObjectUpdateFlags } -func (o *Object) GetGuid() uint64 { - return uint64(o.guid) +func NewObject() *Object { + return &Object{ + objectTypeID: wow.TypeIDObject, + objectType: wow.TypeMaskObject, + + isInWorld: false, + isUpdated: false, + uint32Values: 0, + } } -func (o *Object) Update() { +func (o *Object) AddUpdateFlags(flags ...wow.ObjectUpdateFlags) { + for _, ouf := range flags { + o.updateFlags |= ouf + } +} + +func (o *Object) UpdateFlags() wow.ObjectUpdateFlags { + return o.updateFlags +} + +func (o *Object) MovementFlags() wow.MovementFlag { + return o.movementFlags +} + +func (o *Object) GameObjectType() wow.GameObjectType { + // return wow.GameObjectTypeObject + return wow.GameObjectTypeGeneric +} +func (o *Object) Guid() wow.GUID { + return o.guid } diff --git a/pkg/summit/world/object/player/fields.go b/pkg/summit/world/object/player/fields.go deleted file mode 100644 index 4fb6bf6..0000000 --- a/pkg/summit/world/object/player/fields.go +++ /dev/null @@ -1,5 +0,0 @@ -package player - -// TODO: generate update fields from some emulator - -type UpdateField int diff --git a/pkg/summit/world/object/player/movement.go b/pkg/summit/world/object/player/movement.go new file mode 100644 index 0000000..ffeae67 --- /dev/null +++ b/pkg/summit/world/object/player/movement.go @@ -0,0 +1,25 @@ +package player + +import "github.com/paalgyula/summit/pkg/wow" + +// Movement info +type Movement struct { + MoveFlags wow.MovementFlag + MoveFlags2 uint8 + Time uint32 // time in millisecond + Position WorldLocation + + TransportGuid uint64 + TransportPos WorldLocation + TransportTime uint32 + + SwimmingPitch float32 + FallTime uint32 + + JumpVelocity float32 + JumpSinAngle float32 + JumpCosAngle float32 + JumpXyspeed float32 + + Spline float32 +} diff --git a/pkg/summit/world/object/player/player.go b/pkg/summit/world/object/player/player.go index 206f1d3..7085a4d 100644 --- a/pkg/summit/world/object/player/player.go +++ b/pkg/summit/world/object/player/player.go @@ -1,61 +1,142 @@ package player import ( + "math" + "github.com/paalgyula/summit/pkg/summit/world/object" "github.com/paalgyula/summit/pkg/wow" ) -type PlayerClass uint8 - -// TODO: generate this from dbc? -const ( - ClassWarior PlayerClass = 0x01 - ClassPaladin PlayerClass = 0x02 - ClassHunter PlayerClass = 0x03 - ClassRogue PlayerClass = 0x04 - ClassPriest PlayerClass = 0x05 - ClassDeathKnight PlayerClass = 0x06 - ClassShaman PlayerClass = 0x07 - ClassMage PlayerClass = 0x08 - ClassWarlock PlayerClass = 0x09 - ClassDruid PlayerClass = 0x0b -) +type WorldLocation struct { + X, Y, Z float32 + Map uint32 + Zone uint32 + Orientation float32 +} -type PlayerRace uint8 +// Location returns the X, Y, Z coordinates and map ID of a WorldLocation. +// +// No parameters are required. +// Returns a float32 for X, Y, and Z coordinates, and a uint32 for the map ID. +func (l WorldLocation) Location() (float32, float32, float32, uint32) { + return l.X, l.Y, l.Z, l.Map +} -const ( - RaceHuman PlayerRace = 0x01 - RaceDwarf PlayerRace = 0x03 - RaceNightElf PlayerRace = 0x04 - RaceGnome PlayerRace = 0x07 - RaceDraenei PlayerRace = 0x0b -) +// Distance calculates the distance between two locations +func (loc *WorldLocation) Distance(point *WorldLocation) float64 { + dx := loc.X - point.X + dy := loc.Y - point.Y + dz := loc.Z - point.Z -type PlayerGender uint8 + return math.Sqrt(float64(dx*dx + dy*dy + dz*dz)) +} -const ( - GenderMale PlayerGender = 0x00 - GenderFemale PlayerGender = 0x01 -) +func NewPlayer() *Player { + p := &Player{} -type WorldLocation struct { - X, Y, Z float32 - Map uint32 - Zone uint32 + return p } -func (l WorldLocation) Location() (float32, float32, float32, uint32) { - return l.X, l.Y, l.Z, l.Map +func CreatePlayer() { + p := NewPlayer() + // uint8 powertype = cEntry->powerType; + + var unitfield uint32 + powertype := wow.PowerTypeRage + + _, _, _ = p, unitfield, powertype + + // switch powertype { + // case wow.PowerTypeEnergy,wow.PowerTypeMana: + // unitfield = 0x00000000 + // case wow.PowerTypeRage: + // unitfield = 0x00110000 + // default: + // log.Warn().Msgf("Invalid default powertype %s for player (class %T)", powertype) + // return + // } + + // p.Object.SetFloatValue(object.UnitFieldBoundingradius), DEFAULT_WORLD_OBJECT_SIZE); + // p.Object.SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_COMBAT_REACH); + + // switch (gender) + // { + // case GENDER_FEMALE: + // SetDisplayId(info->displayId_f); + // SetNativeDisplayId(info->displayId_f); + // break; + // case GENDER_MALE: + // SetDisplayId(info->displayId_m); + // SetNativeDisplayId(info->displayId_m); + // break; + // default: + // sLog.outError("Invalid gender %u for player", gender); + // return false; + // break; + // } + + // setFactionForRace(race); + + // RaceClassGender uint32 = (race) | (class_ << 8) | (gender << 16); + + // p.SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24))); + // SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield); + // SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_UNK5); + // SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + // SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client + + // // -1 is default value + // SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); + + // SetUInt32Value(PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24))); + // SetUInt32Value(PLAYER_BYTES_2, (facialHair | (0x00 << 8) | (0x00 << 16) | (0x02 << 24))); + // SetByteValue(PLAYER_BYTES_3, 0, gender); + + // SetUInt32Value(PLAYER_GUILDID, 0); + // SetUInt32Value(PLAYER_GUILDRANK, 0); + // SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0); + + // for (int i = 0; i < KNOWN_TITLES_SIZE; ++i) + // SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + i, 0); // 0=disabled + // SetUInt32Value(PLAYER_CHOSEN_TITLE, 0); + + // SetUInt32Value(PLAYER_FIELD_KILLS, 0); + // SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); + // SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); + // SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); + + // // set starting level + // uint32 start_level = sWorld.getConfig(CONFIG_START_PLAYER_LEVEL); + + // if (GetSession()->GetSecurity() >= SEC_MODERATOR) + // { + // uint32 gm_level = sWorld.getConfig(CONFIG_START_GM_LEVEL); + // if (gm_level > start_level) + // start_level = gm_level; + // } + + // SetUInt32Value(UNIT_FIELD_LEVEL, start_level); + // SetUInt32Value (PLAYER_FIELD_COINAGE, sWorld.getConfig(CONFIG_START_PLAYER_MONEY)); + // SetUInt32Value (PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_START_HONOR_POINTS)); + // SetUInt32Value (PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_START_ARENA_POINTS)); + + // // start with every map explored + // if (sWorld.getConfig(CONFIG_START_ALL_EXPLORED)) + // { + // for (uint8 i = 0; i < 64; i++) + // SetFlag(PLAYER_EXPLORED_ZONES_1 + i, 0xFFFFFFFF); + // } } type Player struct { - object.Object + *object.Object + *object.Unit ID uint32 Name string - Race PlayerRace - Class PlayerClass - Gender PlayerGender + Race wow.PlayerRace + Class wow.PlayerClass + Gender wow.PlayerGender Skin uint8 Face uint8 @@ -84,8 +165,8 @@ type Player struct { Pet Pet } -func (p *Player) GetGuid() uint64 { - return p.Object.GetGuid() +func (p *Player) Guid() wow.GUID { + return p.Object.Guid() } // Initializes an empty inventory @@ -103,6 +184,10 @@ func (p *Player) InitInventory() { } } +func (p *Player) SetFloatValue() { + +} + func (p *Player) GUID() wow.GUID { return wow.NewPlayerGUID(p.ID) } @@ -111,6 +196,53 @@ func (p *Player) Init() { p.InitInventory() } +func (p *Player) Transport() *object.Transport { + return nil +} + +func (p *Player) BuildCreateUpdateForPlayer(target *Player) { + updatetype := wow.UpdateTypeCreateObject + flags := p.Object.UpdateFlags() + + _ = updatetype + + /** lower flag1 **/ + if target != nil { // building packet for oneself + flags |= wow.UpdateFlagSelf + } + + if flags&wow.UpdateFlagHasPosition != 0 { + // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses... + // if isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER) { + // updatetype = wow.UpdateTypeCreateObject2 + // } + + // UPDATETYPE_CREATE_OBJECT2 for pets... + // if target.GetPetGUID() == p.GetGUID() { + // updatetype = UPDATETYPE_CREATE_OBJECT2 + // } + + // UPDATETYPE_CREATE_OBJECT2 for some gameobject types... + // if (isType(TYPEMASK_GAMEOBJECT)) + // { + // switch (((GameObject*)this)->GetGoType()) + // { + // case GAMEOBJECT_TYPE_TRAP: + // case GAMEOBJECT_TYPE_DUEL_ARBITER: + // case GAMEOBJECT_TYPE_FLAGSTAND: + // case GAMEOBJECT_TYPE_FLAGDROP: + // updatetype = UPDATETYPE_CREATE_OBJECT2; + // break; + // case GAMEOBJECT_TYPE_TRANSPORT: + // flags |= UPDATEFLAG_TRANSPORT; + // break; + // default: + // break; + // } + // } + } +} + func (p *Player) WriteToLogin(w *wow.Packet) { w.Write(p.GUID()) w.WriteString(p.Name) diff --git a/pkg/summit/world/object/transport.go b/pkg/summit/world/object/transport.go new file mode 100644 index 0000000..9b1592a --- /dev/null +++ b/pkg/summit/world/object/transport.go @@ -0,0 +1,4 @@ +package object + +type Transport struct { +} diff --git a/pkg/summit/world/object/unit.go b/pkg/summit/world/object/unit.go new file mode 100644 index 0000000..5642c1d --- /dev/null +++ b/pkg/summit/world/object/unit.go @@ -0,0 +1,40 @@ +package object + +import "github.com/paalgyula/summit/pkg/wow" + +type Unit struct { + Object *Object + + mask wow.UnitMask + + Speed [wow.MoveTypeMax]float32 +} + +func NewUnit() *Unit { + obj := NewObject() + + obj.AddUpdateFlags( + wow.UpdateFlagHighGuid | + wow.UpdateFlagLiving | + wow.UpdateFlagHasPosition, + ) + + obj.objectType |= wow.TypeMaskUnit + + return &Unit{ + Object: obj, + mask: wow.UnitMaskNone, + } +} + +func Type() wow.TypeID { + return wow.TypeIDUnit +} + +// GetSpeed returns the speed of the Unit for the given MoveType. +// +// mt: The MoveType to get the speed for. +// float32: The speed of the Unit for the given MoveType. +func (u *Unit) GetSpeed(mt wow.MoveType) float32 { + return u.Speed[mt] +} diff --git a/pkg/summit/world/packets/codetable.go b/pkg/summit/world/packets/codetable.go index 96266a7..007af29 100644 --- a/pkg/summit/world/packets/codetable.go +++ b/pkg/summit/world/packets/codetable.go @@ -1,48 +1,6 @@ package packets -import ( - "github.com/paalgyula/summit/pkg/wow" - "github.com/rs/zerolog/log" -) - -const ( - STATUS_NEVER = "never" - STATUS_LOGGEDIN = "logged_in" - STATUS_AUTHED = "authed" - STATUS_TRANSFER_PENDING = "pending" -) - -type Opcodes []*Handler - -func (o Opcodes) Get(code wow.OpCode) *Handler { - if int(code) > len(o) { - return nil - } - - return o[code] -} - -func (o Opcodes) Handle(code wow.OpCode, handler any) { - oc := o.Get(code) - - if oc == nil { - log.Fatal().Msgf("you should define a handler first for this message: 0x%x", int(code)) - return - } - - oc.Handler = handler -} - -type Packet interface { - OpCode() int -} - -type Handler struct { - Name string - State string - // Handler func(interfaces.Packet, *system.State) - Handler any -} +// TODO: #1 this file should be generated // Correspondence between opcodes and their names var OpcodeTable = Opcodes{ diff --git a/pkg/summit/world/packets/opcodes.go b/pkg/summit/world/packets/opcodes.go new file mode 100644 index 0000000..d1ac05f --- /dev/null +++ b/pkg/summit/world/packets/opcodes.go @@ -0,0 +1,45 @@ +package packets + +import ( + "github.com/paalgyula/summit/pkg/wow" + "github.com/rs/zerolog/log" +) + +const ( + STATUS_NEVER = "never" + STATUS_LOGGEDIN = "logged_in" + STATUS_AUTHED = "authed" + STATUS_TRANSFER_PENDING = "pending" +) + +type Opcodes []*Handler + +func (o Opcodes) Get(code wow.OpCode) *Handler { + if int(code) > len(o) { + return nil + } + + return o[code] +} + +func (o Opcodes) Handle(code wow.OpCode, handler any) { + oc := o.Get(code) + + if oc == nil { + log.Fatal().Msgf("you should define a handler first for this message: 0x%x", int(code)) + return + } + + oc.Handler = handler +} + +type Packet interface { + OpCode() int +} + +type Handler struct { + Name string + State string + // Handler func(interfaces.Packet, *system.State) + Handler any +} diff --git a/pkg/summit/world/updater.go b/pkg/summit/world/updater.go new file mode 100644 index 0000000..d781010 --- /dev/null +++ b/pkg/summit/world/updater.go @@ -0,0 +1,249 @@ +package world + +import ( + "fmt" + "time" + + "github.com/paalgyula/summit/pkg/summit/world/object" + "github.com/paalgyula/summit/pkg/summit/world/object/player" + "github.com/paalgyula/summit/pkg/wow" +) + +type Updater struct { + UpdateData []any + updateFlags uint8 +} + +func (upd *Updater) buildMovementUpdate(unit any, pkt *wow.Packet) { + var o *object.Object + var u *object.Unit + var p *player.Player + + switch t := unit.(type) { + case *player.Player: + o = t.Object + p = t + case *object.Object: + o = t + default: + panic(fmt.Sprintf("unknown type: %T", unit)) + } + + pkt.Write(wow.UpdateTypeMovement) + pkt.Write(o.Guid()) + + moveFlags := wow.MovementFlagNone + + pkt.Write(upd.updateFlags) // update flags + + if upd.updateFlags&wow.UpdateFlagLiving != 0 { + switch o.Guid().TypeID() { + case wow.TypeIDUnit: + { + moveFlags = o.MovementFlags() + moveFlags &= ^wow.MovementFlagOnTransport + } + break + case wow.TypeIDPlayer: + { + moveFlags = o.MovementFlags() + + if p.Transport() != nil { + moveFlags |= wow.MovementFlagOnTransport + } else { + moveFlags &= ^wow.MovementFlagOnTransport + } + + } + break + } + + pkt.Write(moveFlags) // movement flags + pkt.WriteOne(0) // movemoveFlags + pkt.Write(uint32(time.Now().UnixMilli())) // time (in milliseconds) + } + + if upd.updateFlags&wow.UpdateFlagHasPosition != 0 { + if upd.updateFlags&wow.UpdateFlagTransport != 0 && + o.GameObjectType() == wow.GameObjectTypeMoTransport { + pkt.Write(float32(0)) + pkt.Write(float32(0)) + pkt.Write(float32(0)) + // *data << float(((WorldObject*)this)->GetOrientation()); + pkt.Write(float32(0)) // Orientation + } else { + // *data << float(((WorldObject*)this)->GetPositionX()); + pkt.Write(float32(0)) + // *data << float(((WorldObject*)this)->GetPositionY()); + pkt.Write(float32(0)) + // *data << float(((WorldObject*)this)->GetPositionZ()); + pkt.Write(float32(0)) + // *data << float(((WorldObject*)this)->GetOrientation()); + pkt.Write(float32(0)) + } + } + + // // 0x20 + if upd.updateFlags&wow.UpdateFlagLiving != 0 { + + // { + // // 0x00000200 + // if (moveFlags & MOVEMENTFLAG_ONTRANSPORT) + // { + // if (GetTypeId() == TYPEID_PLAYER) + // { + // *data << (uint64)ToPlayer()->GetTransport()->GetGUID(); + // *data << (float)ToPlayer()->GetTransOffsetX(); + // *data << (float)ToPlayer()->GetTransOffsetY(); + // *data << (float)ToPlayer()->GetTransOffsetZ(); + // *data << (float)ToPlayer()->GetTransOffsetO(); + // *data << (uint32)ToPlayer()->GetTransTime(); + // } + // //Oregon currently not have support for other than player on transport + // } + + // // 0x02200000 + // if (moveFlags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2)) + // { + // if (GetTypeId() == TYPEID_PLAYER) + // *data << (float)ToPlayer()->m_movementInfo.s_pitch; + // else + // *data << float(0); // is't part of movement packet, we must store and send it... + // } + + if o.Guid().TypeID() == wow.TypeIDPlayer { + // *data << (uint32)ToPlayer()->m_movementInfo.GetFallTime(); + // else + // *data << uint32(0); // last fall time + pkt.Write(uint32(0)) + + // // 0x00001000 + // if (moveFlags & MOVEMENTFLAG_FALLING) + // { + // if (GetTypeId() == TYPEID_PLAYER) + // { + // *data << float(ToPlayer()->m_movementInfo.j_velocity); + // *data << float(ToPlayer()->m_movementInfo.j_sinAngle); + // *data << float(ToPlayer()->m_movementInfo.j_cosAngle); + // *data << float(ToPlayer()->m_movementInfo.j_xyspeed); + // } + // else + // { + // *data << float(0); + // *data << float(0); + // *data << float(0); + // *data << float(0); + // } + // } + + // // 0x04000000 + // if (moveFlags & MOVEMENTFLAG_SPLINE_ELEVATION) + // { + // if (GetTypeId() == TYPEID_PLAYER) + // *data << float(ToPlayer()->m_movementInfo.u_unk1); + // else + // *data << float(0); + // } + + // // Unit speeds + // *data << ((Unit*)this)->GetSpeed(MOVE_WALK); + pkt.Write(u.GetSpeed(wow.MoveTypeWalk)) + // *data << ((Unit*)this)->GetSpeed(MOVE_RUN); + pkt.Write(u.GetSpeed(wow.MoveTypeRun)) + // *data << ((Unit*)this)->GetSpeed(MOVE_RUN_BACK); + pkt.Write(u.GetSpeed(wow.MoveTypeRunBack)) + // *data << ((Unit*)this)->GetSpeed(MOVE_SWIM); + pkt.Write(u.GetSpeed(wow.MoveTypeSwim)) + // *data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK); + pkt.Write(u.GetSpeed(wow.MoveTypeSwimBack)) + // *data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT); + pkt.Write(u.GetSpeed(wow.MoveTypeFlight)) + // *data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT_BACK); + pkt.Write(u.GetSpeed(wow.MoveTypeFlightBack)) + // *data << ((Unit*)this)->GetSpeed(MOVE_TURN_RATE); + pkt.Write(u.GetSpeed(wow.MoveTypeTurnRate)) + + // // 0x08000000 + // if (moveFlags & MOVEMENTFLAG_SPLINE_ENABLED) + // Movement::PacketBuilder::WriteCreate(*((Unit*)this)->movespline, *data); + } + } + + // // 0x8 + if upd.updateFlags&wow.UpdateFlagLowGuid != 0 { + switch o.Guid().TypeID() { + case wow.TypeIDObject, wow.TypeIDItem, wow.TypeIDContainer, + wow.TypeIDGameObject, wow.TypeIDDynamicoObject, wow.TypeIDCorpse: + pkt.Write(o.Guid().Entry()) // GetGUIDLow() + case wow.TypeIDUnit: + // *data << uint32(0x0000000B); // unk, can be 0xB or 0xC + pkt.WriteUint32(0x0B) + case wow.TypeIDPlayer: + if upd.updateFlags&wow.UpdateFlagSelf != 0 { + // *data << uint32(0x00000015); // unk, can be 0x15 or 0x22 + pkt.WriteUint32(0x15) + } else { + // *data << uint32(0x00000008); // unk, can be 0x7 or 0x8 + pkt.WriteUint32(0x8) + } + default: + // *data << uint32(0x00000000); // unk + pkt.WriteUint32(0x00000000) + } + } + + // // 0x10 + if upd.updateFlags&wow.UpdateFlagHighGuid != 0 { + switch o.Guid().TypeID() { + case wow.TypeIDObject, wow.TypeIDItem, wow.TypeIDContainer, + wow.TypeIDGameObject, wow.TypeIDDynamicoObject, wow.TypeIDCorpse: + pkt.Write(o.Guid().High()) // GetGUIDHigh() + default: + pkt.WriteUint32(0x00) // unk + } + } + + // // 0x4 + // if (updateFlags & UPDATEFLAG_HAS_ATTACKING_TARGET) // packed guid (probably target guid) + // { + // if (Unit const* me = ToUnit()) + // { + // if (me->GetVictim()) + // *data << me->GetVictim()->GetPackGUID(); + // else + // *data << uint8(0); + // } + // else + // *data << uint8(0); + // } + + // // 0x2 + // if (updateFlags & UPDATEFLAG_TRANSPORT) + // { + // *data << uint32(getMSTime()); // ms time + // } +} + +func (o *Updater) BuildUpdateObject(player *player.Player) *wow.Packet { + p := wow.NewPacket(wow.ServerUpdateObject) + + p.WriteUint32(len(o.UpdateData)) + p.WriteOne(0) // Has transport + + // if (!m_outOfRangeGUIDs.empty()) + // { + // buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; + // buf << (uint32) m_outOfRangeGUIDs.size(); + + // for (std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) + // { + // // buf << i->WriteAsPacked(); + // buf << (uint8)0xFF; + // buf << *i; + // } + // } + + o.buildMovementUpdate(player, p) + + return p +} diff --git a/pkg/wow/dbc/converter.go b/pkg/wow/dbc/converter.go deleted file mode 100644 index e1c7b72..0000000 --- a/pkg/wow/dbc/converter.go +++ /dev/null @@ -1,10 +0,0 @@ -package dbc - -type DBCDefinition[C any] struct { - FileName string - Format RecordFormat -} - -var definitions = []DBCDefinition[any]{{ - "", []FieldType(""), -}} diff --git a/pkg/wow/dbc/reader.go b/pkg/wow/dbc/reader.go deleted file mode 100644 index f20c7db..0000000 --- a/pkg/wow/dbc/reader.go +++ /dev/null @@ -1,172 +0,0 @@ -package dbc - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" -) - -type FieldType byte - -const ( - FieldNA FieldType = 'x' // Not used or unknown, 4 byte size - FieldNAByte FieldType = 'X' // Not used or unknown, byte - FieldString FieldType = 's' // char* - FieldFloat FieldType = 'f' // float - FieldInt FieldType = 'i' // uint32 - FieldByte FieldType = 'b' // uint8 - FieldSort FieldType = 'd' // Sorted by this field, field is not included - FieldIndex FieldType = 'n' // The same,but parsed to data - FieldLogic FieldType = 'l' // Logical (boolean) -) - -func (f FieldType) Size() int { - switch f { - case FieldNA, FieldFloat, FieldInt, FieldIndex: - return 4 - case FieldNAByte, FieldByte, FieldLogic: - return 1 - } - - return 1 // Field string? -} - -type RecordFormat []FieldType - -func (r RecordFormat) Length() (i int) { - for _, v := range r { - i += v.Size() - } - - return -} - -type DataHeader struct { - Magic [4]byte // always 'WDBC' - RecordCount uint32 // records per file - FieldCount uint32 // fields per record - RecordSize uint32 // sum (sizeof (field_type_i)) | 0 <= i < field_count. field_type_i is NOT defined in the files. - StringBlockSize uint32 // Block size of the string block at the end of file -} - -type Reader[C any] struct { - file io.ReadSeekCloser - header DataHeader - - current []byte - recordPos int - - recordFormat RecordFormat -} - -// NewReader creates a DBC file reader with a format -func NewReader[C comparable](f io.ReadSeekCloser, format string) *Reader[C] { - r := &Reader[C]{file: f} - r.readHeader() - - r.recordFormat = RecordFormat(format) - - fmt.Printf("Record len: %d\n", r.recordFormat.Length()) - - return r -} - -// Header returns the DBC file header -func (r *Reader[C]) Header() DataHeader { - return r.header -} - -func (r *Reader[C]) readHeader() { - _, _ = r.file.Seek(0, 0) - - binary.Read(r.file, binary.LittleEndian, &r.header) - fmt.Printf("Header: %+v\n", r.header) - - r.current = make([]byte, r.header.RecordSize) - r.recordPos = 0 -} - -func (r *Reader[C]) checkStringSize() { - pos, _ := r.file.Seek(0, 1) - endPos, _ := r.file.Seek(0, 2) - distance := endPos - pos - - fmt.Printf(" Pos: %d End: %d, Distance: %d\n", pos, endPos, distance) - fmt.Printf(" RecordCount: %d\n", r.header.RecordCount) -} - -// HasNext is the iterator which is iterating through the records, -// and returns false if no more record found. -func (r *Reader[C]) HasNext() bool { - return r.recordPos < int(r.header.RecordCount) -} - -// Reduce and skips bytes based on format -func (r *Reader[C]) reduceWithFormat() { - rreader := bytes.NewReader(r.current[:]) - reduced := &bytes.Buffer{} - - for _, v := range r.recordFormat { - switch v { - case FieldNA, FieldNAByte: - rreader.Seek(int64(v.Size()), 1) - default: - buf := make([]byte, v.Size()) - io.CopyBuffer(reduced, rreader, buf) - } - } -} - -func (r *Reader[C]) Next() *C { - _, err := r.file.Read(r.current) - - if err != nil { - panic(err) - } - - r.reduceWithFormat() - r.recordPos++ - - var rec C - dr := bytes.NewReader(r.current) - binary.Read(dr, binary.LittleEndian, &rec) - - return &rec -} - -func (r *Reader[C]) Current() []byte { - return r.current -} - -func (r *Reader[C]) Strings() []byte { - dest := r.header.RecordCount*r.header.RecordSize + 20 - _, err := r.file.Seek(int64(dest), 0) - if err != nil { - panic(err) - } - bb := make([]byte, r.header.StringBlockSize) - - _, err = r.file.Read(bb) - if err != nil { - panic(err) - } - - return bb -} - -func (r *Reader[C]) ReadRecord() error { - for i := 0; i < int(r.header.RecordCount); i++ { - rec := make([]byte, r.header.RecordSize) - _, err := r.file.Read(rec) - - if err != nil { - return err - } - - // fmt.Printf("readed: %d/%d\n", n, header.RecordSize) - // fmt.Printf("%s", hex.Dump(rec)) - } - - return nil -} diff --git a/pkg/wow/gameobject.go b/pkg/wow/gameobject.go new file mode 100644 index 0000000..2617f61 --- /dev/null +++ b/pkg/wow/gameobject.go @@ -0,0 +1,41 @@ +package wow + +type GameObjectType int + +const ( + GameObjectTypeDoor GameObjectType = iota + GameObjectTypeButton + GameObjectTypeQuestGiver + GameObjectTypeChest + GameObjectTypeBinder + GameObjectTypeGeneric + GameObjectTypeTrap + GameObjectTypeChair + GameObjectTypeSpellFocus + GameObjectTypeText + GameObjectTypeGoober + GameObjectTypeTransport + GameObjectTypeAreaDamage + GameObjectTypeCamera + GameObjectTypeMapObject + GameObjectTypeMoTransport + GameObjectTypeDuelArbiter + GameObjectTypeFishingNode + GameObjectTypeSummoningRitual + GameObjectTypeMailbox + GameObjectTypeAuctionHouse + GameObjectTypeGuardPost + GameObjectTypeSpellcaster + GameObjectTypeMeetingStone + GameObjectTypeFlagStand + GameObjectTypeFishingHole + GameObjectTypeFlagDrop + GameObjectTypeMiniGame + GameObjectTypeLotteryKiosk + GameObjectTypeCapturePoint + GameObjectTypeAuraGenerator + GameObjectTypeDungeonDifficulty + GameObjectTypeBarberChair + GameObjectTypeDestructibleBuilding + GameObjectTypeGuildBank +) diff --git a/pkg/wow/guid.go b/pkg/wow/guid.go index 0b880d9..8598599 100644 --- a/pkg/wow/guid.go +++ b/pkg/wow/guid.go @@ -129,3 +129,36 @@ func NewPlayerGUID(counter uint32) GUID { func NewItemGUID(counter uint32) GUID { return NewGUID(ItemGuid, counter) } + +func (g GUID) TypeID() TypeID { + switch g.High() { + case ItemGuid: + return TypeIDItem + //case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently + case UnitGuid, PetGuid: + return TypeIDUnit + case PlayerGuid: + return TypeIDPlayer + case GameObjectGuid, MoTransportGuid: + return TypeIDGameObject + case DynamicObjectGuid: + return TypeIDDynamicoObject + case CorpseGuid: + return TypeIDCorpse + default: // unknown + return TypeIDObject + } +} + +type TypeID uint8 + +const ( + TypeIDObject TypeID = iota + TypeIDItem + TypeIDContainer + TypeIDUnit + TypeIDPlayer + TypeIDGameObject + TypeIDDynamicoObject + TypeIDCorpse +) diff --git a/pkg/wow/interfaces.go b/pkg/wow/interfaces.go index 05afb3c..83fc4ef 100644 --- a/pkg/wow/interfaces.go +++ b/pkg/wow/interfaces.go @@ -1,14 +1,14 @@ package wow -type GuidHolder interface { - GetGuid() uint64 +type HasGuid interface { + Guid() uint64 } -type WorldUnit interface { - GuidHolder - HasLocation +type Updater interface { Update() +} +type HasObjectType interface { ObjectType() string } @@ -16,3 +16,10 @@ type WorldUnit interface { type HasLocation interface { Location() (float32, float32, float32, uint) } + +type WorldUnit interface { + HasGuid + HasLocation + HasObjectType + Updater +} diff --git a/pkg/wow/movement.go b/pkg/wow/movement.go new file mode 100644 index 0000000..1017939 --- /dev/null +++ b/pkg/wow/movement.go @@ -0,0 +1,56 @@ +package wow + +type MoveType int + +const ( + MoveTypeWalk MoveType = iota + MoveTypeRun + MoveTypeRunBack + MoveTypeSwim + MoveTypeSwimBack + MoveTypeTurnRate + MoveTypeFlight + MoveTypeFlightBack + MoveTypeMax +) + +// const MoveTypeMax = MoveTypeFlightBack + 1 + +type MovementFlag uint32 + +const ( + MovementFlagNone MovementFlag = 0x00000000 + MovementFlagForward MovementFlag = 0x00000001 + MovementFlagBackward MovementFlag = 0x00000002 + MovementFlagStrafeLeft MovementFlag = 0x00000004 + MovementFlagStrafeRight MovementFlag = 0x00000008 + MovementFlagTurnLeft MovementFlag = 0x00000010 + MovementFlagTurnRight MovementFlag = 0x00000020 + MovementFlagPitchUp MovementFlag = 0x00000040 + MovementFlagPitchDown MovementFlag = 0x00000080 + MovementFlagWalkMode MovementFlag = 0x00000100 // Walking + MovementFlagOnTransport MovementFlag = 0x00000200 // Used for flying on some creatures + MovementFlagLevitating MovementFlag = 0x00000400 + MovementFlagRoot MovementFlag = 0x00000800 + MovementFlagFalling MovementFlag = 0x00001000 + MovementFlagFallingFar MovementFlag = 0x00004000 + MovementFlagSwimming MovementFlag = 0x00200000 // appears with fly flag also + MovementFlagAscending MovementFlag = 0x00400000 // swim up also + MovementFlagCanFly MovementFlag = 0x00800000 + MovementFlagFlying MovementFlag = 0x01000000 + MovementFlagFlying2 MovementFlag = 0x02000000 // Actual flying mode + MovementFlagSplineElevation MovementFlag = 0x04000000 // used for flight paths + MovementFlagSplineEnabled MovementFlag = 0x08000000 // used for flight paths + MovementFlagWaterwalking MovementFlag = 0x10000000 // prevent unit from falling through water + MovementFlagSafeFall MovementFlag = 0x20000000 // Feather Fall (spell) + MovementFlagHover MovementFlag = 0x40000000 + + MovementFlagMoving MovementFlag = MovementFlagForward | MovementFlagBackward | MovementFlagStrafeLeft | MovementFlagStrafeRight | + MovementFlagPitchUp | MovementFlagPitchDown | + MovementFlagFalling | MovementFlagFallingFar | MovementFlagAscending | + MovementFlagSplineElevation + + MovementFlagTurning MovementFlag = MovementFlagTurnLeft | MovementFlagTurnRight + + MovementFlagMaskMovingFly MovementFlag = MovementFlagFlying2 | MovementFlagAscending | MovementFlagCanFly +) diff --git a/pkg/wow/object.go b/pkg/wow/object.go new file mode 100644 index 0000000..f2a72e0 --- /dev/null +++ b/pkg/wow/object.go @@ -0,0 +1,15 @@ +package wow + +type TypeMask uint16 + +const ( + TypeMaskObject TypeMask = 0x0001 + TypeMaskItem TypeMask = 0x0002 + TypeMaskContainer TypeMask = TypeMaskItem | 0x0004 + TypeMaskUnit TypeMask = 0x0008 + TypeMaskPlayer TypeMask = 0x0010 | TypeMaskUnit + TypeMaskGameObject TypeMask = 0x0020 + TypeMaskDynamicObject TypeMask = 0x0040 + TypeMaskCorpse TypeMask = 0x0080 + TypeMaskSeer TypeMask = TypeMaskUnit | TypeMaskDynamicObject +) diff --git a/pkg/wow/packet.go b/pkg/wow/packet.go index 2fd710e..9e3edac 100644 --- a/pkg/wow/packet.go +++ b/pkg/wow/packet.go @@ -66,6 +66,10 @@ func (w *Packet) WriteOne(b int) error { return w.buf.WriteByte(uint8(b)) } +func (w *Packet) WriteUint32(b int) error { + return w.Write(uint32(b)) +} + // Write writes the string into the packet terminated by a null character. // You can specify the byte order, but default its BigEndian. func (w *Packet) WriteString(v string, byteOrder ...binary.ByteOrder) { diff --git a/pkg/wow/player.go b/pkg/wow/player.go new file mode 100644 index 0000000..717bfee --- /dev/null +++ b/pkg/wow/player.go @@ -0,0 +1,56 @@ +package wow + +type PlayerClass uint8 + +// TODO: generate this from dbc? +const ( + ClassWarior PlayerClass = 0x01 + ClassPaladin PlayerClass = 0x02 + ClassHunter PlayerClass = 0x03 + ClassRogue PlayerClass = 0x04 + ClassPriest PlayerClass = 0x05 + ClassDeathKnight PlayerClass = 0x06 + ClassShaman PlayerClass = 0x07 + ClassMage PlayerClass = 0x08 + ClassWarlock PlayerClass = 0x09 + ClassDruid PlayerClass = 0x0b +) + +type PlayerRace uint8 + +const ( + RaceHuman PlayerRace = 0x01 + RaceDwarf PlayerRace = 0x03 + RaceNightElf PlayerRace = 0x04 + RaceGnome PlayerRace = 0x07 + RaceDraenei PlayerRace = 0x0b +) + +type PlayerGender uint8 + +const ( + GenderMale PlayerGender = 0x00 + GenderFemale PlayerGender = 0x01 +) + +type PlayerFlag uint32 + +// PlayerFlag values. +const ( + PlayerFlagsGroupLeader PlayerFlag = 0x00001 + PlayerFlagsAFK PlayerFlag = 0x00002 + PlayerFlagsDND PlayerFlag = 0x00004 + PlayerFlagsGM PlayerFlag = 0x00008 + PlayerFlagsGhost PlayerFlag = 0x00010 + PlayerFlagsResting PlayerFlag = 0x00020 + PlayerFlagsFFAPVP PlayerFlag = 0x00080 + PlayerFlagsContestedPVP PlayerFlag = 0x00100 + PlayerFlagsInPVP PlayerFlag = 0x00200 + PlayerFlagsHideHelm PlayerFlag = 0x00400 + PlayerFlagsHideCloak PlayerFlag = 0x00800 + PlayerFlagsPartialPlayTime PlayerFlag = 0x01000 + PlayerFlagsNoPlayTime PlayerFlag = 0x02000 + PlayerFlagsSanctuary PlayerFlag = 0x10000 + PlayerFlagsTaxiBenchmark PlayerFlag = 0x20000 + PlayerFlagsPVPTimer PlayerFlag = 0x40000 +) diff --git a/pkg/wow/unit.go b/pkg/wow/unit.go new file mode 100644 index 0000000..f9203e6 --- /dev/null +++ b/pkg/wow/unit.go @@ -0,0 +1,28 @@ +package wow + +type PowerType int32 + +const ( + PowerTypeMana PowerType = 0 + PowerTypeRage PowerType = 1 + PowerTypeFocus PowerType = 2 + PowerTypeEnergy PowerType = 3 + PowerTypeHappiness PowerType = 4 + PowerTypeHealth PowerType = -2 // 0xFFFFFFFE as a signed value +) + +const MaxPowerTypes = 5 + +type UnitMask uint32 + +const ( + UnitMaskNone UnitMask = 0x00000000 + UnitMaskSummon UnitMask = 0x00000001 + UnitMaskMinion UnitMask = 0x00000002 + UnitMaskGuardian UnitMask = 0x00000004 + UnitMaskTotem UnitMask = 0x00000008 + UnitMaskPet UnitMask = 0x00000010 + UnitMaskPuppet UnitMask = 0x00000040 + UnitMaskHunterPet UnitMask = 0x00000080 + UnitMaskControlableGuardian UnitMask = 0x00000100 +) diff --git a/pkg/wow/update.go b/pkg/wow/update.go new file mode 100644 index 0000000..eb91b24 --- /dev/null +++ b/pkg/wow/update.go @@ -0,0 +1,25 @@ +package wow + +type ObjectUpdateType uint8 + +const ( + UpdateTypeValues = 0 + UpdateTypeMovement = 1 + UpdateTypeCreateObject = 2 + UpdateTypeCreateObject2 = 3 + UpdateTypeOutOfRangeObjects = 4 + UpdateTypeNearObjects = 5 +) + +type ObjectUpdateFlags uint8 + +const ( + UpdateFlagNone = 0x00 + UpdateFlagSelf = 0x01 + UpdateFlagTransport = 0x02 + UpdateFlagHasAttackingTarget = 0x04 + UpdateFlagLowGuid = 0x08 + UpdateFlagHighGuid = 0x10 + UpdateFlagLiving = 0x20 + UpdateFlagHasPosition = 0x40 +) diff --git a/summit.code-workspace b/summit.code-workspace index 9a7226f..74c620a 100644 --- a/summit.code-workspace +++ b/summit.code-workspace @@ -9,7 +9,9 @@ // "path": "../summit-baby" // } ], - "extensions": {}, + "extensions": { + "recommendations": ["ms-vscode.hexeditor"] + }, "settings": { "workbench.colorCustomizations": { "statusBar.background" : "#1A1A1A",