From 562836ac5e554c3abe0da00ce4f61669e1a1865f Mon Sep 17 00:00:00 2001 From: Tnze Date: Sun, 22 May 2022 09:58:41 +0800 Subject: [PATCH] dim manager test 1 --- save/chunk.go | 17 ++++++++ server/dimension/loadmanager.go | 53 +++++++++++++++++++++++ server/dimension/pool.go | 74 +++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 server/dimension/loadmanager.go create mode 100644 server/dimension/pool.go diff --git a/save/chunk.go b/save/chunk.go index 83a72ca..9975f2e 100644 --- a/save/chunk.go +++ b/save/chunk.go @@ -74,3 +74,20 @@ func (c *Chunk) Load(data []byte) (err error) { _, err = nbt.NewDecoder(r).Decode(c) return } + +func (c *Chunk) Data(compressingType byte) ([]byte, error) { + var buff bytes.Buffer + + buff.WriteByte(compressingType) + var w io.Writer + switch compressingType { + default: + return nil, errors.New("unknown compression") + case 1: + w = gzip.NewWriter(&buff) + case 2: + w = zlib.NewWriter(&buff) + } + err := nbt.NewEncoder(w).Encode(c, "") + return buff.Bytes(), err +} diff --git a/server/dimension/loadmanager.go b/server/dimension/loadmanager.go new file mode 100644 index 0000000..37c3640 --- /dev/null +++ b/server/dimension/loadmanager.go @@ -0,0 +1,53 @@ +package dimension + +import ( + "container/list" + + "github.com/Tnze/go-mc/level" +) + +type manager struct { + storage + elements map[level.ChunkPos]*list.Element + activeChunks *list.List + + chunkLoadQueue []level.ChunkPos + chunkUnloadQueue []level.ChunkPos +} + +type chunkHandler struct { + level.ChunkPos + *level.Chunk +} + +func (m *manager) refresh(players [][2]int) { + m.chunkLoadQueue = m.chunkLoadQueue[:0] + m.chunkUnloadQueue = m.chunkUnloadQueue[:0] + + newActives := list.New() + const N = 16 + for _, p := range players { + for i := 1 - N; i < N; i++ { + for j := 1 - N; j < N; j++ { + pos := level.ChunkPos{ + X: p[0] + i, + Z: p[1] + j, + } + if e := m.elements[pos]; e != nil { + // chunk exist, move into newActives + v := m.activeChunks.Remove(e) + m.elements[pos] = newActives.PushBack(v) + } else { + // not exist, load from storage + m.chunkLoadQueue = append(m.chunkLoadQueue, pos) + } + } + } + } + for e := m.activeChunks.Front(); e != nil; e = e.Next() { + pos := e.Value.(chunkHandler).ChunkPos + m.chunkUnloadQueue = append(m.chunkUnloadQueue, pos) + m.elements[pos] = newActives.PushBack(e.Value) + } + m.activeChunks = newActives +} diff --git a/server/dimension/pool.go b/server/dimension/pool.go new file mode 100644 index 0000000..b435fc8 --- /dev/null +++ b/server/dimension/pool.go @@ -0,0 +1,74 @@ +package dimension + +import ( + "fmt" + "path/filepath" + + "github.com/Tnze/go-mc/level" + "github.com/Tnze/go-mc/save" + "github.com/Tnze/go-mc/save/region" +) + +// TODO: Cache regions and chunks +type storage struct { + regionDir string +} + +func (s *storage) GetChunk(pos level.ChunkPos) (lc *level.Chunk, err error) { + filename := fmt.Sprintf("r.%d.%d.mca", pos.X>>5, pos.Z>>5) + + var r *region.Region + r, err = region.Open(filepath.Join(s.regionDir, filename)) + if err != nil { + return nil, err + } + defer func() { + err2 := r.Close() + if err == nil && err2 != nil { + err = err2 + } + }() + + sector, err := r.ReadSector(region.In(pos.X, pos.Z)) + if err != nil { + return nil, err + } + + var sc save.Chunk + err = sc.Load(sector) + if err != nil { + return nil, err + } + + return level.ChunkFromSave(&sc) +} + +func (s *storage) PutChunk(pos level.ChunkPos, c *level.Chunk) (err error) { + var sc save.Chunk + err = level.ChunkToSave(c, &sc) + if err != nil { + return + } + + var data []byte + data, err = sc.Data(1) + if err != nil { + return + } + + filename := fmt.Sprintf("r.%d.%d.mca", pos.X>>5, pos.Z>>5) + var r *region.Region + r, err = region.Open(filepath.Join(s.regionDir, filename)) + if err != nil { + return err + } + defer func() { + err2 := r.Close() + if err == nil && err2 != nil { + err = err2 + } + }() + x, z := region.In(pos.X, pos.Z) + err = r.WriteSector(x, z, data) + return +}