summaryrefslogtreecommitdiff
path: root/server/level.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/level.go')
-rw-r--r--server/level.go194
1 files changed, 97 insertions, 97 deletions
diff --git a/server/level.go b/server/level.go
index 95f04ff..17f8eb8 100644
--- a/server/level.go
+++ b/server/level.go
@@ -4,15 +4,12 @@ import (
"io"
"os"
"fmt"
- "bytes"
+ "math"
"bufio"
- "compress/gzip"
- "encoding/binary"
"git.citrons.xyz/metronode/phony"
)
type levelId int32
-type blockType byte
type levelPlayerId int8
type levelInfo struct {
Id levelId
@@ -25,7 +22,7 @@ type level struct {
levelInfo
loadingState int
server *Server
- blocks []byte
+ mapM *mapManager // is accessed without synchronization
ids map[levelPlayerId]*player
players map[*player]levelPlayerId
}
@@ -36,32 +33,30 @@ const (
levelLoaded
)
-func newLevel(s *Server, info levelInfo) *level {
+func initLevel(s *Server, info levelInfo) *level {
return &level {
levelInfo: info,
server: s,
- loadingState: levelLoading,
- blocks: make([]byte, info.Size.X * info.Size.Y * info.Size.Z),
+ loadingState: levelUnloaded,
+ mapM: newMapManager(info.Size),
ids: make(map[levelPlayerId]*player),
players: make(map[*player]levelPlayerId),
}
}
-func loadLevel(s *Server, id levelId, isSpawn bool) *level {
- l := &level {
- levelInfo: levelInfo {Id: id, IsSpawn: isSpawn},
- server: s,
- ids: make(map[levelPlayerId]*player),
- players: make(map[*player]levelPlayerId),
- }
- l.load()
+func createNewLevel(s *Server, info levelInfo) *level {
+ l := initLevel(s, info)
+ l.loadingState = levelLoading
return l
}
func (l *level) load() {
if l.loadingState == levelUnloaded {
l.loadingState = levelLoading
- id := l.Id
+ var (
+ id = l.Id
+ v = l.mapM.Blocks
+ )
dataManager.Act(l, func() {
f, err := os.Open(fmt.Sprintf("world/level/%d.bin", id))
if l.handleLoadError(err) != nil {
@@ -71,31 +66,34 @@ func (l *level) load() {
var (
rd = bufio.NewReader(f)
info levelInfo
- blocks []byte
)
readDataField(rd, &info)
- z, err := gzip.NewReader(rd)
- if l.handleLoadError(err) != nil {
- return
- }
- z.Read(make([]byte, 4))
- blocks, err = io.ReadAll(z)
+ v.init(info.Size)
+ err = v.syncDecompressFromStorage(rd)
if l.handleLoadError(err) != nil {
return
}
l.Act(&dataManager, func() {
- l.loadingState = levelLoaded
l.levelInfo = info
l.Id = id
- l.blocks = blocks
- for player := range l.players {
- player.OnLevelData(l, l.levelInfo, l.compressLevelData())
- }
+ l.loadDone()
})
})
}
}
+func (l *level) loadDone() {
+ if l.loadingState == levelLoaded {
+ return
+ }
+ l.loadingState = levelLoaded
+ for player := range l.players {
+ player.OnLevelData(
+ l, l.levelInfo, l.mapM.Blocks.syncCompressForNetwork(),
+ )
+ }
+}
+
func (l *level) handleLoadError(err error) error {
if err == nil {
return err
@@ -133,87 +131,87 @@ func (l *level) save(done func()) {
dataManager.errHand.OnSaveError(l, err)
return
}
- defer f.Close()
-
- wr := bufio.NewWriter(f)
- writeDataField(wr, l.levelInfo)
- data := l.compressLevelData()
- defer data.Close()
- io.Copy(wr, data)
- if wr.Flush() != nil {
- dataManager.errHand.OnSaveError(l, err)
- return
- }
-}
-
-func (l *level) blockIndex(pos blockPos) int {
- return int(pos.X + pos.Z*l.Size.X + pos.Y*l.Size.X*l.Size.Z)
-}
-
-func (l *level) setBlock(pos blockPos, block blockType) {
- l.blocks[l.blockIndex(pos)] = byte(block)
-}
-
-func (l *level) getBlock(pos blockPos) blockType {
- return blockType(l.blocks[l.blockIndex(pos)])
-}
-
-func (l *level) compressLevelData() io.ReadCloser {
- rd, wr := io.Pipe()
- data := bytes.NewReader(bytes.Clone(l.blocks))
+ data := l.mapM.Blocks.syncCompressForStorage()
go func() {
- defer wr.Close()
- z := gzip.NewWriter(wr)
- defer z.Close()
- binary.Write(z, binary.BigEndian, uint32(len(l.blocks)))
- io.Copy(z, data)
+ defer f.Close()
+ defer data.Close()
+ wr := bufio.NewWriter(f)
+ writeDataField(wr, l.levelInfo)
+ io.Copy(wr, data)
+ if wr.Flush() != nil {
+ dataManager.errHand.OnSaveError(l, err)
+ return
+ }
}()
- return rd
}
func (l *level) generateFlat() {
- var p blockPos
- for p.Z = 0; p.Z < l.levelInfo.Size.Z; p.Z++ {
- for p.Y = 0; p.Y < l.levelInfo.Size.Y / 2; p.Y++ {
- for p.X = 0; p.X < l.levelInfo.Size.X; p.X++ {
- var block blockType
- if p.Y == 0 {
- block = 7
- } else if p.Y == l.levelInfo.Size.Y/2 - 1 {
- block = 2
- } else if p.Y > l.levelInfo.Size.Y/2 - 15 {
- block = 3
- } else {
- block = 1
+ v := l.mapM.Blocks
+ v.syncSetAll(func(yield func(blockType) bool) {
+ var p blockPos
+ for p.Y = 0; p.Y < v.size.Y / 2; p.Y++ {
+ for p.X = 0; p.X < v.size.X; p.X++ {
+ for p.Z = 0; p.Z < v.size.Z; p.Z++ {
+ var block blockType
+ if p.Y == 0 {
+ block = 7
+ } else if p.Y == v.size.Y/2 - 1 {
+ block = 2
+ } else if p.Y > v.size.Y/2 - 15 {
+ block = 3
+ } else if p.Y < v.size.Y/2 {
+ block = 1
+ }
+ if !yield(block) {
+ return
+ }
}
- l.setBlock(p, block)
}
}
- }
- l.save(nil)
- l.loadingState = levelLoaded
+ })
+ l.Act(nil, l.loadDone)
}
func (l *level) generateEmpty() {
- l.save(nil)
- l.loadingState = levelLoaded
+ l.Act(nil, l.loadDone)
+}
+
+func (l *level) generateSphere() {
+ v := l.mapM.Blocks
+ v.syncSetAll(func(yield func(blockType) bool) {
+ var (p blockPos; radius = float64(v.size.X) / 2)
+ for p.Y = 0; p.Y < v.size.Y; p.Y++ {
+ for p.X = 0; p.X < v.size.X; p.X++ {
+ for p.Z = 0; p.Z < v.size.Z; p.Z++ {
+ var block blockType
+ dist := math.Sqrt(
+ float64(v.size.X/2 - p.X)*float64(v.size.X/2 - p.X) +
+ float64(v.size.Y/2 - p.Y)*float64(v.size.Y/2 - p.Y) +
+ float64(v.size.Z/2 - p.Z)*float64(v.size.Z/2 - p.Z),
+ )
+ if dist > radius - 2 && dist <= radius {
+ block = 25
+ }
+ if !yield(block) {
+ return
+ }
+ }
+ }
+ }
+ })
+ l.Act(nil, l.loadDone)
}
func (l *level) generateDebug() {
- if l.levelInfo.Size.X < 16 || l.levelInfo.Size.Z < 16 {
- return
- }
- if l.levelInfo.Size.Y < 1 {
- return
- }
- var p blockPos
- for p.Z = 0; p.Z < 16; p.Z++ {
- for p.X = 0; p.X < 16; p.X++ {
- l.setBlock(p, blockType(p.X + p.Z * 16))
+ v := l.mapM.Blocks
+ v.syncSetAll(func(yield func(blockType) bool) {
+ for i := 0; i < 256; i++ {
+ if !yield(blockType(i)) {
+ return
+ }
}
- }
- l.save(nil)
- l.loadingState = levelLoaded
+ })
+ l.Act(nil, l.loadDone)
}
func (l *level) Save(from phony.Actor, done func()) {
@@ -230,8 +228,8 @@ func (l *level) SetBlock(from phony.Actor, pos blockPos, block blockType) {
if l.loadingState != levelLoaded {
return
}
+ l.mapM.SetBlock(from, pos, block)
l.Act(from, func() {
- l.setBlock(pos, block)
for player := range l.players {
player.OnSetBlock(l, pos, block)
}
@@ -242,7 +240,9 @@ func (l *level) OnAddPlayer(from *player, name string, pos entityPos) {
l.Act(from, func() {
l.load()
if l.loadingState == levelLoaded {
- from.OnLevelData(l, l.levelInfo, l.compressLevelData())
+ from.OnLevelData(
+ l, l.levelInfo, l.mapM.Blocks.syncCompressForNetwork(),
+ )
}
var newId levelPlayerId
for newId = 0; newId <= 127; newId++ {