diff --git a/proto_base/base_types.go b/proto_base/base_types.go index d685ae6..1587cba 100644 --- a/proto_base/base_types.go +++ b/proto_base/base_types.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "io" + "math" ) var ( @@ -284,3 +285,115 @@ func Bool2uint64(b bool) uint64 { } return 0 } + +type LpVec3d struct { + X, Y, Z float64 +} + +func (v *LpVec3d) Encode(w io.Writer) error { + return writeVelocity(w, *v) +} +func (v *LpVec3d) Decode(r io.ReadSeeker) error { + v3, err := readVelocity(r) + if err != nil { + return err + } + v.X = v3.X + v.Y = v3.Y + v.Z = v3.Z + return nil +} +func readVelocity(r io.Reader) (LpVec3d, error) { + var marker, second uint8 + if err := binary.Read(r, binary.BigEndian, &marker); err != nil { + return LpVec3d{}, err + } + if marker == 0 { + return LpVec3d{}, nil + } + if err := binary.Read(r, binary.BigEndian, &second); err != nil { + return LpVec3d{}, err + } + var packed uint32 + if err := binary.Read(r, binary.BigEndian, &packed); err != nil { + return LpVec3d{}, err + } + m := (uint64(packed) << 16) | (uint64(second) << 8) | uint64(marker) + n := int64(marker & 3) + if (marker & 4) != 0 { + // fast marker bit set, read varint for extended scale + scale, err := DecodeVarInt(r) + if err != nil { + return LpVec3d{}, err + } + n |= (int64(scale) & 0xFFFFFFFF) << 2 + } + x := fromLong(int64(m>>3), n) + y := fromLong(int64(m>>18), n) + z := fromLong(int64(m>>33), n) + return LpVec3d{X: x, Y: y, Z: z}, nil +} +func writeVelocity(w io.Writer, v LpVec3d) error { + const maxVal = 1.7179869183e10 + const scaleMax = 32766.0 + x := clamp(v.X, maxVal) + y := clamp(v.Y, maxVal) + z := clamp(v.Z, maxVal) + g := absMax(absMax(x, y), z) + if g < 3.051944088384301e-5 { + _, err := w.Write([]byte{0}) + return err + } + l := int64(math.Ceil(g)) + bl := (l & 3) != l + m := l + if bl { + m = (l & 3) | 4 + } + lf := float64(l) + n := toLong(x/lf) << 3 + o := toLong(y/lf) << 18 + p := toLong(z/lf) << 33 + q := m | n | o | p + var buf [7]byte + buf[0] = byte(q) + buf[1] = byte(q >> 8) + binary.BigEndian.PutUint32(buf[2:6], uint32(q>>16)) + if _, err := w.Write(buf[:6]); err != nil { + return err + } + if bl { + if err := EncodeVarInt(w, int32(l>>2)); err != nil { + return err + } + } + return nil +} +func clamp(v, max float64) float64 { + if math.IsNaN(v) { + return 0 + } + if v > max { + return max + } + if v < -max { + return -max + } + return v +} +func absMax(a, b float64) float64 { + if math.Abs(a) > math.Abs(b) { + return a + } + return b +} +func toLong(v float64) int64 { + return int64(math.Round((v*0.5 + 0.5) * 32766.0)) +} +func fromLong(bits int64, scale int64) float64 { + v := bits & 0x7FFF + if v > 32766 { + v = 32766 + } + return (float64(v)*2.0/32766.0 - 1.0) * float64(scale) +} diff --git a/proto_generated/v1_21_11/proto.go b/proto_generated/v1_21_11/proto.go index 47cadfe..bce6e29 100644 --- a/proto_generated/v1_21_11/proto.go +++ b/proto_generated/v1_21_11/proto.go @@ -2,10 +2,11 @@ package v1_21_11 import ( "encoding/binary" + "io" + "github.com/admin-else/strom/nbt" "github.com/admin-else/strom/proto_base" "github.com/google/uuid" - "io" ) type ArmorTrimMaterial struct { @@ -16668,15 +16669,30 @@ func (ret *PlayToClientPacketEntityUpdateAttributes) Encode(w io.Writer) (err er } type PlayToClientPacketEntityVelocity struct { - Val proto_base.ToDo + EntityId int32 + Velocity proto_base.LpVec3d } func (ret *PlayToClientPacketEntityVelocity) Decode(r io.ReadSeeker) (err error) { - err = proto_base.ToDoError + ret.EntityId, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + err = ret.Velocity.Decode(r) + if err != nil { + return + } return } func (ret *PlayToClientPacketEntityVelocity) Encode(w io.Writer) (err error) { - err = proto_base.ToDoError + err = proto_base.EncodeVarInt(w, ret.EntityId) + if err != nil { + return + } + err = ret.Velocity.Encode(w) + if err != nil { + return + } return } @@ -20453,15 +20469,111 @@ func (ret *PlayToClientPacketSoundEffect) Encode(w io.Writer) (err error) { } type PlayToClientPacketSpawnEntity struct { - Val proto_base.ToDo + EntityId int32 + ObjectUUID uuid.UUID + Type int32 + X float64 + Y float64 + Z float64 + Velocity proto_base.LpVec3d + Pitch int8 + Yaw int8 + HeadPitch int8 + ObjectData int32 } func (ret *PlayToClientPacketSpawnEntity) Decode(r io.ReadSeeker) (err error) { - err = proto_base.ToDoError + ret.EntityId, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + _, err = io.ReadFull(r, ret.ObjectUUID[:]) + if err != nil { + return + } + ret.Type, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.X) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Y) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Z) + if err != nil { + return + } + err = ret.Velocity.Decode(r) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Pitch) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Yaw) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.HeadPitch) + if err != nil { + return + } + ret.ObjectData, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } return } func (ret *PlayToClientPacketSpawnEntity) Encode(w io.Writer) (err error) { - err = proto_base.ToDoError + err = proto_base.EncodeVarInt(w, ret.EntityId) + if err != nil { + return + } + _, err = w.Write(ret.ObjectUUID[:]) + if err != nil { + return + } + err = proto_base.EncodeVarInt(w, ret.Type) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.X) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Y) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Z) + if err != nil { + return + } + err = ret.Velocity.Encode(w) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Pitch) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Yaw) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.HeadPitch) + if err != nil { + return + } + err = proto_base.EncodeVarInt(w, ret.ObjectData) + if err != nil { + return + } return } diff --git a/proto_generated/v1_21_9/proto.go b/proto_generated/v1_21_9/proto.go index 9c971be..eb7635b 100644 --- a/proto_generated/v1_21_9/proto.go +++ b/proto_generated/v1_21_9/proto.go @@ -16491,15 +16491,30 @@ func (ret *PlayToClientPacketEntityUpdateAttributes) Encode(w io.Writer) (err er } type PlayToClientPacketEntityVelocity struct { - Val proto_base.ToDo + EntityId int32 + Velocity proto_base.LpVec3d } func (ret *PlayToClientPacketEntityVelocity) Decode(r io.ReadSeeker) (err error) { - err = proto_base.ToDoError + ret.EntityId, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + err = ret.Velocity.Decode(r) + if err != nil { + return + } return } func (ret *PlayToClientPacketEntityVelocity) Encode(w io.Writer) (err error) { - err = proto_base.ToDoError + err = proto_base.EncodeVarInt(w, ret.EntityId) + if err != nil { + return + } + err = ret.Velocity.Encode(w) + if err != nil { + return + } return } @@ -20276,15 +20291,111 @@ func (ret *PlayToClientPacketSoundEffect) Encode(w io.Writer) (err error) { } type PlayToClientPacketSpawnEntity struct { - Val proto_base.ToDo + EntityId int32 + ObjectUUID uuid.UUID + Type int32 + X float64 + Y float64 + Z float64 + Velocity proto_base.LpVec3d + Pitch int8 + Yaw int8 + HeadPitch int8 + ObjectData int32 } func (ret *PlayToClientPacketSpawnEntity) Decode(r io.ReadSeeker) (err error) { - err = proto_base.ToDoError + ret.EntityId, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + _, err = io.ReadFull(r, ret.ObjectUUID[:]) + if err != nil { + return + } + ret.Type, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.X) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Y) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Z) + if err != nil { + return + } + err = ret.Velocity.Decode(r) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Pitch) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.Yaw) + if err != nil { + return + } + err = binary.Read(r, binary.BigEndian, &ret.HeadPitch) + if err != nil { + return + } + ret.ObjectData, err = proto_base.DecodeVarInt(r) + if err != nil { + return + } return } func (ret *PlayToClientPacketSpawnEntity) Encode(w io.Writer) (err error) { - err = proto_base.ToDoError + err = proto_base.EncodeVarInt(w, ret.EntityId) + if err != nil { + return + } + _, err = w.Write(ret.ObjectUUID[:]) + if err != nil { + return + } + err = proto_base.EncodeVarInt(w, ret.Type) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.X) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Y) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Z) + if err != nil { + return + } + err = ret.Velocity.Encode(w) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Pitch) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.Yaw) + if err != nil { + return + } + err = binary.Write(w, binary.BigEndian, ret.HeadPitch) + if err != nil { + return + } + err = proto_base.EncodeVarInt(w, ret.ObjectData) + if err != nil { + return + } return } diff --git a/proto_generator/native_decoder.go b/proto_generator/native_decoder.go index 8b056e0..44bcfd1 100644 --- a/proto_generator/native_decoder.go +++ b/proto_generator/native_decoder.go @@ -634,7 +634,7 @@ func (g *Generator) RegisterDecoderNatives() { "varlong": VarLongDecoder, "anonymousNbt": DefaultDecoder, "anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two - "lpVec3": ToDoDecoder, + "lpVec3": DefaultDecoder, "UUID": UUIDDecoder, "restBuffer": DefaultDecoder, diff --git a/proto_generator/native_encoder.go b/proto_generator/native_encoder.go index e85dfd7..5c71c49 100644 --- a/proto_generator/native_encoder.go +++ b/proto_generator/native_encoder.go @@ -414,7 +414,7 @@ func (g *Generator) RegisterEncoderNatives() { "anonOptionalNbt": DefaultEncoder, // I have no idea what the difference is between these two "UUID": UUIDEncoder, "restBuffer": DefaultEncoder, - "lpVec3": ToDoEncoder, + "lpVec3": DefaultEncoder, "string": StringEncoder, "f32": SimpleTypeEncoder, diff --git a/proto_generator/native_type.go b/proto_generator/native_type.go index ad5ba61..a583d35 100644 --- a/proto_generator/native_type.go +++ b/proto_generator/native_type.go @@ -225,6 +225,6 @@ func (g *Generator) RegisterNatives() { "bitflags": VisitBitFlagsType, "topBitSetTerminatedArray": VisitToDoType, "todo": VisitToDoType, - "lpVec3": VisitToDoType, + "lpVec3": MakeSelectorVisitor("proto_base", "LpVec3d"), } }