feat: 1.21.11 codecs
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
pk "git.konjactw.dev/falloutBot/go-mc/net/packet"
|
||||
)
|
||||
|
||||
type LpVec3 struct {
|
||||
X, Y, Z float64
|
||||
}
|
||||
|
||||
const (
|
||||
lpMaxVal = 1.7179869183e10
|
||||
lpMinVal = 3.051944088384301e-05
|
||||
)
|
||||
|
||||
// ReadFrom 實作 io.ReaderFrom 介面
|
||||
func (v *LpVec3) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
// 1. 讀取第一個 byte (lowest)
|
||||
var lowestBuf [1]byte
|
||||
if _, err := io.ReadFull(r, lowestBuf[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n += 1
|
||||
lowest := uint32(lowestBuf[0])
|
||||
|
||||
if lowest == 0 {
|
||||
v.X, v.Y, v.Z = 0, 0, 0
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// 2. 讀取 middle (1 byte) 與 highest (4 bytes)
|
||||
var remain [5]byte
|
||||
if _, err := io.ReadFull(r, remain[:]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += 5
|
||||
|
||||
middle := uint32(remain[0])
|
||||
highest := binary.BigEndian.Uint32(remain[1:])
|
||||
|
||||
// 重組 64-bit buffer
|
||||
buffer := uint64(highest)<<16 | uint64(middle)<<8 | uint64(lowest)
|
||||
|
||||
// 3. 處理 Scale 與 Continuation Bit
|
||||
scaleVal := uint64(lowest & 3)
|
||||
if (lowest & 4) == 4 {
|
||||
var vInt pk.VarInt
|
||||
vn, err := vInt.ReadFrom(r)
|
||||
n += vn
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
// Java: scale |= (VarInt.read(input) & 4294967295L) << 2
|
||||
scaleVal |= (uint64(int32(vInt)) & 0xFFFFFFFF) << 2
|
||||
}
|
||||
scale := float64(scaleVal)
|
||||
|
||||
// 4. 解包座標
|
||||
v.X = lpUnpack(int64(buffer>>3)) * scale
|
||||
v.Y = lpUnpack(int64(buffer>>18)) * scale
|
||||
v.Z = lpUnpack(int64(buffer>>33)) * scale
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// WriteTo 實作 io.WriterTo 介面
|
||||
func (v *LpVec3) WriteTo(w io.Writer) (n int64, err error) {
|
||||
x, y, z := lpSanitize(v.X), lpSanitize(v.Y), lpSanitize(v.Z)
|
||||
chessboard := math.Max(math.Abs(x), math.Max(math.Abs(y), math.Abs(z)))
|
||||
|
||||
if chessboard < lpMinVal {
|
||||
nn, err := w.Write([]byte{0})
|
||||
return int64(nn), err
|
||||
}
|
||||
|
||||
scale := int64(math.Ceil(chessboard))
|
||||
isPartial := (scale & 3) != scale
|
||||
|
||||
var markers int64
|
||||
if isPartial {
|
||||
markers = (scale & 3) | 4
|
||||
} else {
|
||||
markers = scale
|
||||
}
|
||||
|
||||
// 封裝位元組
|
||||
xn := lpPack(x/float64(scale)) << 3
|
||||
yn := lpPack(y/float64(scale)) << 18
|
||||
zn := lpPack(z/float64(scale)) << 33
|
||||
buffer := uint64(markers | xn | yn | zn)
|
||||
|
||||
// 寫入 6 bytes (lowest, middle, highest[4])
|
||||
out := make([]byte, 6)
|
||||
out[0] = byte(buffer)
|
||||
out[1] = byte(buffer >> 8)
|
||||
binary.BigEndian.PutUint32(out[2:], uint32(buffer>>16))
|
||||
|
||||
nn, err := w.Write(out)
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
// 處理 Partial Scale
|
||||
if isPartial {
|
||||
vn, err := pk.VarInt(scale >> 2).WriteTo(w)
|
||||
n += vn
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// 內部轉換工具
|
||||
func lpSanitize(v float64) float64 {
|
||||
if math.IsNaN(v) {
|
||||
return 0
|
||||
}
|
||||
if v > lpMaxVal {
|
||||
return lpMaxVal
|
||||
}
|
||||
if v < -lpMaxVal {
|
||||
return -lpMaxVal
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func lpPack(v float64) int64 {
|
||||
return int64(math.Round((v*0.5 + 0.5) * 32766.0))
|
||||
}
|
||||
|
||||
func lpUnpack(v int64) float64 {
|
||||
val := float64(v & 32767)
|
||||
if val > 32766.0 {
|
||||
val = 32766.0
|
||||
}
|
||||
return val*2.0/32766.0 - 1.0
|
||||
}
|
||||
Reference in New Issue
Block a user