refactor: Moved the servers to their separate directories
This commit is contained in:
		@@ -1,86 +0,0 @@
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,114 +0,0 @@
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"git.nicholasnovak.io/nnovak/spatial-db/world"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const fileCacheSize = 8
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ChunkNotFoundError = errors.New("chunk was not found in storage")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SimpleServer struct {
 | 
			
		||||
	StorageDir string
 | 
			
		||||
	cache      FileCache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *SimpleServer) SetStorageRoot(path string) {
 | 
			
		||||
	s.StorageDir = path
 | 
			
		||||
	s.cache = 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 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, ChunkNotFoundError
 | 
			
		||||
		} else {
 | 
			
		||||
			return chunkData, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 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)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
import "git.nicholasnovak.io/nnovak/spatial-db/world"
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"git.nicholasnovak.io/nnovak/spatial-db/world"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type StorageServer interface {
 | 
			
		||||
	// Individual operations
 | 
			
		||||
@@ -16,3 +20,7 @@ type StorageServer interface {
 | 
			
		||||
	// Network-level operations
 | 
			
		||||
	ReadChunkAt(pos world.ChunkPos) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ChunkNotFoundError = errors.New("chunk was not found in storage")
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user