From 4c2510565d56250b6bdea2da2a8ee271bbb1707a Mon Sep 17 00:00:00 2001 From: Tnze Date: Sun, 20 Mar 2022 01:17:25 +0800 Subject: [PATCH] pk.Ary and pk.Array using generic now --- bot/basic/info.go | 4 +- bot/screen/screen.go | 4 +- examples/simpleServer1.17.1/main.go | 11 ++--- level/bitstorage.go | 5 +- level/chunk.go | 36 +++++++-------- level/palette.go | 16 +++---- net/packet/packet_test.go | 5 +- net/packet/util.go | 72 +++++++++++------------------ net/packet/util_test.go | 53 ++++++++------------- save/chunk.go | 14 ------ server/dimension.go | 3 -- server/entities.go | 1 + server/internal/bvh/bvh.go | 2 +- server/internal/bvh/bvh_test.go | 6 +-- server/playerinfo.go | 18 ++++---- 15 files changed, 95 insertions(+), 155 deletions(-) create mode 100644 server/entities.go diff --git a/bot/basic/info.go b/bot/basic/info.go index cf2b9c4..81bcec7 100644 --- a/bot/basic/info.go +++ b/bot/basic/info.go @@ -56,15 +56,13 @@ type ServInfo struct { } func (p *Player) handleLoginPacket(packet pk.Packet) error { - var WorldCount pk.VarInt var WorldNames = make([]pk.Identifier, 0) err := packet.Scan( (*pk.Int)(&p.EID), (*pk.Boolean)(&p.Hardcore), (*pk.UnsignedByte)(&p.Gamemode), (*pk.Byte)(&p.PrevGamemode), - &WorldCount, - pk.Ary{Len: &WorldCount, Ary: &WorldNames}, + pk.Ary[pk.VarInt, *pk.VarInt]{Ary: &WorldNames}, pk.NBT(&p.WorldInfo.DimensionCodec), pk.NBT(&p.WorldInfo.Dimension), (*pk.Identifier)(&p.WorldName), diff --git a/bot/screen/screen.go b/bot/screen/screen.go index bab6fdc..f4ab062 100644 --- a/bot/screen/screen.go +++ b/bot/screen/screen.go @@ -96,15 +96,13 @@ func (m *Manager) onSetContentPacket(p pk.Packet) error { var ( ContainerID pk.UnsignedByte StateID pk.VarInt - Count pk.VarInt SlotData []Slot CarriedItem Slot ) if err := p.Scan( &ContainerID, &StateID, - &Count, pk.Ary{ - Len: &Count, + pk.Ary[pk.VarInt, *pk.VarInt]{ Ary: &SlotData, }, &CarriedItem, diff --git a/examples/simpleServer1.17.1/main.go b/examples/simpleServer1.17.1/main.go index c6fe7a6..b2d9bc1 100644 --- a/examples/simpleServer1.17.1/main.go +++ b/examples/simpleServer1.17.1/main.go @@ -162,12 +162,11 @@ var dimensionSNBT string func joinGame(conn net.Conn) error { return conn.WritePacket(pk.Marshal(JoinGame, - pk.Int(0), // EntityID - pk.Boolean(false), // Is hardcore - pk.UnsignedByte(1), // Gamemode - pk.Byte(1), // Previous Gamemode - pk.VarInt(1), // World Count - pk.Ary{Len: 1, Ary: []pk.Identifier{"world"}}, // World Names + pk.Int(0), // EntityID + pk.Boolean(false), // Is hardcore + pk.UnsignedByte(1), // Gamemode + pk.Byte(1), // Previous Gamemode + pk.Array([]pk.Identifier{"world"}), // World Names pk.NBT(nbt.StringifiedMessage(dimensionCodecSNBT)), // Dimension codec pk.NBT(nbt.StringifiedMessage(dimensionSNBT)), // Dimension pk.Identifier("world"), // World Name diff --git a/level/bitstorage.go b/level/bitstorage.go index dd6c29e..6cbef93 100644 --- a/level/bitstorage.go +++ b/level/bitstorage.go @@ -40,9 +40,8 @@ func NewBitStorage(bits, length int, data []uint64) (b *BitStorage) { } b = &BitStorage{ - mask: 1<= 0 && stateID < len(block.StateList) { - b = block.StateList[stateID] - } - if isAir(b) { + if isAir(s.States.Get(i)) { s.blockCount-- } if v != 0 { @@ -367,8 +363,8 @@ func (l *lightData) ReadFrom(r io.Reader) (int64, error) { }.ReadFrom(r) } -func isAir(b block.Block) bool { - switch b.(type) { +func isAir(s int) bool { + switch block.StateList[s].(type) { case block.Air, block.CaveAir, block.VoidAir: return true default: diff --git a/level/palette.go b/level/palette.go index 186897a..b16ef63 100644 --- a/level/palette.go +++ b/level/palette.go @@ -140,6 +140,14 @@ func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) { return n, nil } +func (p *PaletteContainer) WriteTo(w io.Writer) (n int64, err error) { + return pk.Tuple{ + pk.UnsignedByte(p.bits), + p.palette, + p.data, + }.WriteTo(w) +} + type paletteCfg interface { bits(int) int create(bits int) palette @@ -197,14 +205,6 @@ func (b biomesCfg) create(bits int) palette { } } -func (p *PaletteContainer) WriteTo(w io.Writer) (n int64, err error) { - return pk.Tuple{ - pk.UnsignedByte(p.bits), - p.palette, - p.data, - }.WriteTo(w) -} - type palette interface { pk.Field id(v state) (int, bool) diff --git a/net/packet/packet_test.go b/net/packet/packet_test.go index 96ceff5..afe9500 100644 --- a/net/packet/packet_test.go +++ b/net/packet/packet_test.go @@ -109,7 +109,6 @@ func ExamplePacket_Scan_joinGame() { Hardcore pk.Boolean Gamemode pk.UnsignedByte PreGamemode pk.Byte - WorldCount pk.VarInt WorldNames = make([]pk.Identifier, 0) // This cannot replace with "var WorldNames []pk.Identifier" because "nil" has no type information DimensionCodec struct { DimensionType interface{} `nbt:"minecraft:dimension_type"` @@ -127,9 +126,7 @@ func ExamplePacket_Scan_joinGame() { &Hardcore, &Gamemode, &PreGamemode, - &WorldCount, - pk.Ary{ - Len: &WorldCount, + pk.Ary[pk.VarInt, *pk.VarInt]{ Ary: &WorldNames, }, pk.NBT(&DimensionCodec), diff --git a/net/packet/util.go b/net/packet/util.go index 801b3ef..69f6d82 100644 --- a/net/packet/util.go +++ b/net/packet/util.go @@ -17,20 +17,29 @@ import ( // In some special cases, you might want to read an "Array of X" with a fix length. // So it's allowed to directly set an integer type Len, but not a pointer. // -// Note that Ary DO NOT read or write the Len. You are controlling it manually. -type Ary struct { - Len interface{} // Value or Pointer of any integer type, only needed in ReadFrom +// Note that Ary DO read or write the Len. You aren't need to do so by your self. +type Ary[T VarInt | VarLong | Byte | UnsignedByte | Short | UnsignedShort | Int | Long, L interface { + *T + ReadFrom(r io.Reader) (n int64, err error) + WriteTo(w io.Writer) (n int64, err error) +}] struct { Ary interface{} // Slice or Pointer of Slice of FieldEncoder, FieldDecoder or both (Field) } -func (a Ary) WriteTo(r io.Writer) (n int64, err error) { +func (a Ary[T, L]) WriteTo(w io.Writer) (n int64, err error) { array := reflect.ValueOf(a.Ary) for array.Kind() == reflect.Ptr { array = array.Elem() } + Len := T(array.Len()) + if nn, err := L(&Len).WriteTo(w); err != nil { + return n, err + } else { + n += nn + } for i := 0; i < array.Len(); i++ { elem := array.Index(i) - nn, err := elem.Interface().(FieldEncoder).WriteTo(r) + nn, err := elem.Interface().(FieldEncoder).WriteTo(w) n += nn if err != nil { return n, err @@ -39,24 +48,14 @@ func (a Ary) WriteTo(r io.Writer) (n int64, err error) { return n, nil } -func (a Ary) length() int { - v := reflect.ValueOf(a.Len) - for { - switch v.Kind() { - case reflect.Ptr: - v = v.Elem() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return int(v.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return int(v.Uint()) - default: - panic(errors.New("unsupported Len value: " + v.Type().String())) - } +func (a Ary[T, L]) ReadFrom(r io.Reader) (n int64, err error) { + var Len T + if nn, err := L(&Len).ReadFrom(r); err != nil { + return nn, err + } else { + n += nn } -} -func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { - length := a.length() array := reflect.ValueOf(a.Ary) for array.Kind() == reflect.Ptr { array = array.Elem() @@ -64,10 +63,12 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { if !array.CanAddr() { panic(errors.New("the contents of the Ary are not addressable")) } - if array.Cap() < length { - array.Set(reflect.MakeSlice(array.Type(), length, length)) + if array.Cap() < int(Len) { + array.Set(reflect.MakeSlice(array.Type(), int(Len), int(Len))) + } else { + array.Slice(0, int(Len)) } - for i := 0; i < length; i++ { + for i := 0; i < int(Len); i++ { elem := array.Index(i) nn, err := elem.Addr().Interface().(FieldDecoder).ReadFrom(r) n += nn @@ -78,27 +79,8 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { return n, err } -// Array return an Ary but handled the previous Length field -// -// Warning: unstable API, may change in later version -func Array(array interface{}) Field { - var length VarInt - - value := reflect.ValueOf(array) - for value.Kind() == reflect.Ptr { - value = value.Elem() - } - - if array != nil { - length = VarInt(value.Len()) - } - return Tuple{ - &length, - Ary{ - Len: &length, - Ary: array, - }, - } +func Array(ary interface{}) Field { + return Ary[VarInt, *VarInt]{Ary: ary} } type Opt struct { diff --git a/net/packet/util_test.go b/net/packet/util_test.go index 0d0f8d2..20fe573 100644 --- a/net/packet/util_test.go +++ b/net/packet/util_test.go @@ -13,28 +13,18 @@ func ExampleAry_WriteTo() { // The length is inferred from the length of Ary. pk.Marshal( 0x00, - // It's important to remember that - // typically the responsibility of - // sending the length field - // is on you. - pk.VarInt(len(data)), - pk.Ary{ - Len: len(data), // this line can be removed + pk.Ary[pk.VarInt, *pk.VarInt]{ Ary: data, }, ) } func ExampleAry_ReadFrom() { - var length pk.VarInt var data []pk.String var p pk.Packet // = conn.ReadPacket() if err := p.Scan( - - &length, // decode length first - pk.Ary{ // then decode Ary according to length - Len: &length, + pk.Ary[pk.VarInt, *pk.VarInt]{ // then decode Ary according to length Ary: &data, }, ); err != nil { @@ -43,18 +33,18 @@ func ExampleAry_ReadFrom() { } func TestAry_ReadFrom(t *testing.T) { - var num pk.Int = 2 var ary []pk.String var bin = []byte{ + 0, 0, 0, 2, 4, 'T', 'n', 'z', 'e', 0, } - var data = pk.Ary{Len: &num, Ary: &ary} + var data = pk.Ary[pk.Int, *pk.Int]{Ary: &ary} if _, err := data.ReadFrom(bytes.NewReader(bin)); err != nil { t.Fatal(err) } - if len(ary) != int(num) { - t.Fatalf("length not match: %d != %d", len(ary), num) + if len(ary) != 2 { + t.Fatalf("length not match: %d != %d", len(ary), 2) } for i, v := range []string{"Tnze", ""} { if string(ary[i]) != v { @@ -70,23 +60,22 @@ func TestAry_WriteTo(t *testing.T) { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, } - int3, long3, varint3, varlong3 := pk.Int(3), pk.Long(3), pk.VarInt(3), pk.VarLong(3) - for _, item := range [...]pk.Ary{ - {Len: 3, Ary: []pk.Int{1, 2, 3}}, - {Len: int3, Ary: []pk.Int{1, 2, 3}}, - {Len: long3, Ary: []pk.Int{1, 2, 3}}, - {Len: varint3, Ary: []pk.Int{1, 2, 3}}, - {Len: varlong3, Ary: []pk.Int{1, 2, 3}}, - {Len: &int3, Ary: []pk.Int{1, 2, 3}}, - {Len: &long3, Ary: []pk.Int{1, 2, 3}}, - {Len: &varint3, Ary: []pk.Int{1, 2, 3}}, - {Len: &varlong3, Ary: []pk.Int{1, 2, 3}}, + for _, item := range [...]pk.FieldEncoder{ + pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.Long, *pk.Long]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.VarInt, *pk.VarInt]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.VarLong, *pk.VarLong]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.Long, *pk.Long]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.VarInt, *pk.VarInt]{Ary: []pk.Int{1, 2, 3}}, + pk.Ary[pk.VarLong, *pk.VarLong]{Ary: []pk.Int{1, 2, 3}}, } { _, err := item.WriteTo(&buf) if err != nil { t.Fatal(err) } - if !bytes.Equal(buf.Bytes(), want) { + if !bytes.Equal(buf.Bytes()[buf.Len()-3*4:], want) { t.Fatalf("Ary encoding error: got %#v, want %#v", buf.Bytes(), want) } buf.Reset() @@ -96,11 +85,12 @@ func TestAry_WriteTo(t *testing.T) { func TestAry_WriteTo_pointer(t *testing.T) { var buf bytes.Buffer want := []byte{ + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, } - data := pk.Ary{Ary: &[]pk.Int{1, 2, 3}} + data := pk.Ary[pk.Int, *pk.Int]{Ary: &[]pk.Int{1, 2, 3}} _, err := data.WriteTo(&buf) if err != nil { @@ -184,7 +174,6 @@ func ExampleOpt_ReadFrom_func() { func ExampleTuple_ReadFrom() { // When you need to read an "Optional Array of X": var has pk.Boolean - var arylen pk.Int var ary []pk.String var p pk.Packet // = conn.ReadPacket() @@ -193,9 +182,7 @@ func ExampleTuple_ReadFrom() { pk.Opt{ Has: &has, Field: pk.Tuple{ - &arylen, - pk.Ary{ - Len: &arylen, + pk.Ary[pk.Int, *pk.Int]{ Ary: &ary, }, }, diff --git a/save/chunk.go b/save/chunk.go index 86cb10a..0355b78 100644 --- a/save/chunk.go +++ b/save/chunk.go @@ -7,7 +7,6 @@ import ( "errors" "io" - "github.com/Tnze/go-mc/level/block" "github.com/Tnze/go-mc/nbt" ) @@ -47,19 +46,6 @@ type BlockState struct { Properties nbt.RawMessage } -func (s *BlockState) Block() block.Block { - b, ok := block.FromID[s.Name] - if !ok { - return nil - } - if s.Properties.Type != nbt.TagEnd { - if err := s.Properties.Unmarshal(&b); err != nil { - return nil - } - } - return b -} - // Load read column data from []byte func (c *Chunk) Load(data []byte) (err error) { var r io.Reader = bytes.NewReader(data[1:]) diff --git a/server/dimension.go b/server/dimension.go index a2d2515..5b24835 100644 --- a/server/dimension.go +++ b/server/dimension.go @@ -45,13 +45,10 @@ func (s *SimpleDim) Info() LevelInfo { func (s *SimpleDim) PlayerJoin(p *Player) { for pos, column := range s.columns { - column.Lock() packet := pk.Marshal( packetid.ClientboundLevelChunkWithLight, pos, column, ) - column.Unlock() - p.WritePacket(Packet758(packet)) } } diff --git a/server/entities.go b/server/entities.go new file mode 100644 index 0000000..abb4e43 --- /dev/null +++ b/server/entities.go @@ -0,0 +1 @@ +package server diff --git a/server/internal/bvh/bvh.go b/server/internal/bvh/bvh.go index 0f436e1..e39af8d 100644 --- a/server/internal/bvh/bvh.go +++ b/server/internal/bvh/bvh.go @@ -191,7 +191,7 @@ func TouchPoint[Vec any, B interface{ WithIn(Vec) bool }](point Vec) func(bound } } -func TouchBound[Vec any, B interface{ Touch(B) bool }](other B) func(bound B) bool { +func TouchBound[B interface{ Touch(B) bool }](other B) func(bound B) bool { return func(bound B) bool { return bound.Touch(other) } diff --git a/server/internal/bvh/bvh_test.go b/server/internal/bvh/bvh_test.go index 93d5a5b..67c165b 100644 --- a/server/internal/bvh/bvh_test.go +++ b/server/internal/bvh/bvh_test.go @@ -56,9 +56,9 @@ func TestTree2_Find_vec(t *testing.T) { t.Log(find(TouchPoint[Vec2d, AABBVec2d](Vec2d{1.5, 1.5}))) t.Log(find(TouchPoint[Vec2d, AABBVec2d](Vec2d{-1.5, 0}))) - t.Log(find(TouchBound[Vec2d, AABBVec2d](AABBVec2d{Upper: Vec2d{1, 1}, Lower: Vec2d{-1, -1}}))) - t.Log(find(TouchBound[Vec2d, AABBVec2d](AABBVec2d{Upper: Vec2d{1, 1}, Lower: Vec2d{1.5, 1.5}}))) - t.Log(find(TouchBound[Vec2d, AABBVec2d](AABBVec2d{Upper: Vec2d{-1.5, 0.5}, Lower: Vec2d{-2.5, -0.5}}))) + t.Log(find(TouchBound[AABBVec2d](AABBVec2d{Upper: Vec2d{1, 1}, Lower: Vec2d{-1, -1}}))) + t.Log(find(TouchBound[AABBVec2d](AABBVec2d{Upper: Vec2d{1, 1}, Lower: Vec2d{1.5, 1.5}}))) + t.Log(find(TouchBound[AABBVec2d](AABBVec2d{Upper: Vec2d{-1.5, 0.5}, Lower: Vec2d{-2.5, -0.5}}))) } func BenchmarkTree_Insert(b *testing.B) { diff --git a/server/playerinfo.go b/server/playerinfo.go index c6f59f3..559a438 100644 --- a/server/playerinfo.go +++ b/server/playerinfo.go @@ -12,18 +12,18 @@ import ( ) type PlayerInfo struct { - updateDelay chan playerInfo + updateDelay chan playerDelayInfo join chan *Player quit chan *Player ticker *time.Ticker } -type playerInfo struct { +type playerDelayInfo struct { player *Player delay time.Duration } -func (p *playerInfo) WriteTo(w io.Writer) (n int64, err error) { +func (p *playerDelayInfo) WriteTo(w io.Writer) (n int64, err error) { return pk.Tuple{ pk.UUID(p.player.UUID), pk.String(p.player.Name), @@ -35,7 +35,7 @@ func (p *playerInfo) WriteTo(w io.Writer) (n int64, err error) { } type playerInfoList struct { - list map[uuid.UUID]playerInfo + list map[uuid.UUID]playerDelayInfo } func (p *playerInfoList) WriteTo(w io.Writer) (n int64, err error) { @@ -54,7 +54,7 @@ func (p *playerInfoList) WriteTo(w io.Writer) (n int64, err error) { return } -type playerDelayUpdate playerInfo +type playerDelayUpdate playerDelayInfo func (p playerDelayUpdate) WriteTo(w io.Writer) (n int64, err error) { return pk.Tuple{ @@ -77,7 +77,7 @@ type PlayerDelaySource interface { func NewPlayerInfo(updateFreq time.Duration, delaySource PlayerDelaySource) *PlayerInfo { p := &PlayerInfo{ - updateDelay: make(chan playerInfo), + updateDelay: make(chan playerDelayInfo), join: make(chan *Player), quit: make(chan *Player), ticker: time.NewTicker(updateFreq), @@ -91,12 +91,12 @@ func NewPlayerInfo(updateFreq time.Duration, delaySource PlayerDelaySource) *Pla func (p *PlayerInfo) Init(*Game) {} func (p *PlayerInfo) Run(ctx context.Context) { - players := &playerInfoList{list: make(map[uuid.UUID]playerInfo)} + players := &playerInfoList{list: make(map[uuid.UUID]playerDelayInfo)} var delayBuffer []playerDelayUpdate for { select { case player := <-p.join: - info := playerInfo{player: player, delay: 0} + info := playerDelayInfo{player: player, delay: 0} pack := Packet758(pk.Marshal( packetid.ClientboundPlayerInfo, pk.VarInt(actionAddPlayer), @@ -144,5 +144,5 @@ func (p *PlayerInfo) Run(ctx context.Context) { func (p *PlayerInfo) AddPlayer(player *Player) { p.join <- player } func (p *PlayerInfo) RemovePlayer(player *Player) { p.quit <- player } func (p *PlayerInfo) onPlayerDelayUpdate(player *Player, delay time.Duration) { - p.updateDelay <- playerInfo{player: player, delay: delay} + p.updateDelay <- playerDelayInfo{player: player, delay: delay} }