refactor: Moved the servers to their separate directories
This commit is contained in:
86
server/hashserver.go
Normal file
86
server/hashserver.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"git.nicholasnovak.io/nnovak/spatial-db/world"
|
||||
)
|
||||
|
||||
type HashServer struct {
|
||||
blocks map[world.BlockPos]world.BlockID
|
||||
}
|
||||
|
||||
func (hs *HashServer) SetStorageRoot(path string) {
|
||||
hs.blocks = make(map[world.BlockPos]world.BlockID)
|
||||
|
||||
chunkFiles, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for chunkIndex, chunkFile := range chunkFiles {
|
||||
var data world.ChunkData
|
||||
|
||||
log.Infof("Reading in chunk %d of %d", chunkIndex, len(chunkFiles))
|
||||
|
||||
f, err := os.Open(filepath.Join(path, chunkFile.Name()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Read each file from disk
|
||||
if err := json.NewDecoder(f).Decode(&data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Load in each data point from disk
|
||||
for _, section := range data.Sections {
|
||||
for blockIndex, blockState := range section.BlockStates {
|
||||
pos := data.IndexToBlockPos(blockIndex)
|
||||
hs.blocks[pos] = blockState
|
||||
}
|
||||
}
|
||||
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (hs *HashServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
panic("Unimplemented")
|
||||
}
|
||||
|
||||
func (hs *HashServer) ChangeBlock(
|
||||
worldPosition world.BlockPos,
|
||||
targetState world.BlockID,
|
||||
) error {
|
||||
hs.blocks[worldPosition] = targetState
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HashServer) ChangeBlockRange(
|
||||
targetState world.BlockID,
|
||||
start, end world.BlockPos,
|
||||
) error {
|
||||
panic("Unimplemented")
|
||||
}
|
||||
|
||||
func (hs *HashServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) {
|
||||
return hs.blocks[pos], nil
|
||||
}
|
||||
|
||||
func (hs *HashServer) ReadChunkAt(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
var data world.ChunkData
|
||||
data.Pos = pos
|
||||
for blockPos, state := range hs.blocks {
|
||||
if blockPos.ToChunkPos() == pos {
|
||||
sec := data.SectionFor(blockPos)
|
||||
sec.UpdateBlock(blockPos, state)
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
104
server/inmemory_server.go
Normal file
104
server/inmemory_server.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"git.nicholasnovak.io/nnovak/spatial-db/world"
|
||||
)
|
||||
|
||||
type InMemoryServer struct {
|
||||
StorageDir string
|
||||
Chunks map[world.ChunkPos]world.ChunkData
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) SetStorageRoot(path string) {
|
||||
s.StorageDir = path
|
||||
|
||||
chunkFiles, err := os.ReadDir(s.StorageDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s.Chunks = make(map[world.ChunkPos]world.ChunkData)
|
||||
|
||||
for _, chunkFile := range chunkFiles {
|
||||
if chunkFile.IsDir() || !strings.HasSuffix(chunkFile.Name(), ".chunk") {
|
||||
continue
|
||||
}
|
||||
file, err := os.Open(filepath.Join(s.StorageDir, chunkFile.Name()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
chunkData, err := ReadChunkFromFile(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
s.Chunks[chunkData.Pos] = chunkData
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) FetchOrCreateChunk(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
return s.Chunks[pos], nil
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName())
|
||||
|
||||
var chunkData world.ChunkData
|
||||
|
||||
chunkFile, err := os.Open(chunkFileName)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return chunkData, ChunkNotFoundError
|
||||
} else {
|
||||
return chunkData, err
|
||||
}
|
||||
}
|
||||
defer chunkFile.Close()
|
||||
|
||||
return ReadChunkFromFile(chunkFile)
|
||||
}
|
||||
|
||||
// Voxel server implementation
|
||||
|
||||
func (s *InMemoryServer) ChangeBlock(
|
||||
worldPosition world.BlockPos,
|
||||
targetState world.BlockID,
|
||||
) error {
|
||||
chunk, err := s.FetchOrCreateChunk(worldPosition.ToChunkPos())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chunk.SectionFor(worldPosition).UpdateBlock(worldPosition, targetState)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) ChangeBlockRange(
|
||||
targetState world.BlockID,
|
||||
start, end world.BlockPos,
|
||||
) error {
|
||||
panic("ChangeBlockRange is unimplemented")
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) {
|
||||
chunk, err := s.FetchOrCreateChunk(pos.ToChunkPos())
|
||||
if err != nil {
|
||||
return world.Empty, err
|
||||
}
|
||||
|
||||
return chunk.SectionFor(pos).FetchBlock(pos), nil
|
||||
}
|
||||
|
||||
func (s *InMemoryServer) ReadChunkAt(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
return s.FetchOrCreateChunk(pos)
|
||||
}
|
||||
111
server/simple_server.go
Normal file
111
server/simple_server.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.nicholasnovak.io/nnovak/spatial-db/storage"
|
||||
"git.nicholasnovak.io/nnovak/spatial-db/world"
|
||||
)
|
||||
|
||||
const fileCacheSize = 8
|
||||
|
||||
type SimpleServer struct {
|
||||
StorageDir string
|
||||
cache storage.FileCache
|
||||
}
|
||||
|
||||
func (s *SimpleServer) SetStorageRoot(path string) {
|
||||
s.StorageDir = path
|
||||
s.cache = storage.NewFileCache(256)
|
||||
}
|
||||
|
||||
// Filesystem operations
|
||||
|
||||
func (s *SimpleServer) FetchOrCreateChunk(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName())
|
||||
|
||||
var chunkData world.ChunkData
|
||||
|
||||
chunkFile, err := os.Open(chunkFileName)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
// There was no chunk that exists, create a blank one
|
||||
chunkFile, err = os.Create(chunkFileName)
|
||||
if err != nil {
|
||||
return chunkData, err
|
||||
}
|
||||
|
||||
// Initilize the file with some blank data
|
||||
if err := json.NewEncoder(chunkFile).Encode(chunkData); err != nil {
|
||||
return chunkData, err
|
||||
}
|
||||
|
||||
if _, err := chunkFile.Seek(0, 0); err != nil {
|
||||
return chunkData, err
|
||||
}
|
||||
} else {
|
||||
return chunkData, err
|
||||
}
|
||||
}
|
||||
defer chunkFile.Close()
|
||||
|
||||
return storage.ReadChunkFromFile(chunkFile)
|
||||
}
|
||||
|
||||
// `FetchChunk' fetches the chunk's data, given the chunk's position
|
||||
func (s *SimpleServer) FetchChunk(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
chunkFileName := filepath.Join(s.StorageDir, pos.ToFileName())
|
||||
|
||||
var chunkData world.ChunkData
|
||||
|
||||
chunkFile, err := s.cache.FetchFile(chunkFileName)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return chunkData, storage.ChunkNotFoundError
|
||||
} else {
|
||||
return chunkData, err
|
||||
}
|
||||
}
|
||||
|
||||
return storage.ReadChunkFromFile(chunkFile)
|
||||
}
|
||||
|
||||
// Voxel server implementation
|
||||
|
||||
func (s *SimpleServer) ChangeBlock(
|
||||
worldPosition world.BlockPos,
|
||||
targetState world.BlockID,
|
||||
) error {
|
||||
chunk, err := s.FetchOrCreateChunk(worldPosition.ToChunkPos())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chunk.SectionFor(worldPosition).UpdateBlock(worldPosition, targetState)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SimpleServer) ChangeBlockRange(
|
||||
targetState world.BlockID,
|
||||
start, end world.BlockPos,
|
||||
) error {
|
||||
panic("ChangeBlockRange is unimplemented")
|
||||
}
|
||||
|
||||
func (s *SimpleServer) ReadBlockAt(pos world.BlockPos) (world.BlockID, error) {
|
||||
chunk, err := s.FetchChunk(pos.ToChunkPos())
|
||||
if err != nil {
|
||||
return world.Empty, err
|
||||
}
|
||||
|
||||
return chunk.SectionFor(pos).FetchBlock(pos), nil
|
||||
}
|
||||
|
||||
func (s *SimpleServer) ReadChunkAt(pos world.ChunkPos) (world.ChunkData, error) {
|
||||
return s.FetchOrCreateChunk(pos)
|
||||
}
|
||||
Reference in New Issue
Block a user