VoxelServer/ServerCore/WorldManager.py

138 lines
4.5 KiB
Python

#!/usr/bin/env python3
import numpy as np
import Chunk
import random
from PerlinGenerator import PerlinGenerator
from threading import Lock
from typing import Tuple
class WorldManager(object):
def __init__(self, world_seed: int,
raw_noise_cell_size: int,
raw_noise_chunk_size: int):
self.world_seed = world_seed
# create Perlin Generator
self.pg = PerlinGenerator(raw_noise_cell_size=raw_noise_cell_size,
raw_noise_chunk_size=raw_noise_chunk_size,
world_seed=world_seed)
# dictionary of dictionaries of dictionaries --> 3D hasmap
# (assume that's more efficient than using tuples as keys,
# but future me should do further investigation into that [TODO!])
self.chunks = {}
# will be a list with locked chunks
self.chunk_locks = {}
# 2Dimensional map. Will be 3D in future [TODO]
self.perlin_maps = {}
# create initial chunk
# self.createEmptyChunk(0, 0, 0)
# create lock object
self.world_lock = Lock()
def acquireChunk(self, chunk_x: int, chunk_y: int, chunk_z: int) -> bool:
assert self.isChunkKnown(chunk_x, chunk_y, chunk_z)
return self.chunk_locks[chunk_x][chunk_y][chunk_z].acquire()
def releaseChunk(self, chunk_x: int, chunk_y: int, chunk_z: int) -> bool:
assert self.isChunkKnown(chunk_x, chunk_y, chunk_z)
lock = self.chunk_locks[chunk_x][chunk_y][chunk_z]
assert lock.locked()
return lock.release()
def isChunkKnown(self, chunk_x: int, chunk_y: int, chunk_z: int) -> bool:
# TODO: this should be done more efficient!
self.world_lock.acquire()
is_known = (chunk_x in self.chunks and
chunk_y in self.chunks[chunk_x] and
chunk_z in self.chunks[chunk_x][chunk_y])
self.world_lock.release()
return is_known
def createEmptyChunk(self,
chunk_x: int,
chunk_y: int,
chunk_z: int) -> None:
assert not self.isChunkKnown(chunk_x, chunk_y, chunk_z)
self.world_lock.acquire()
if chunk_x not in self.chunks:
self.chunks[chunk_x] = {}
self.chunk_locks[chunk_x] = {}
if chunk_y not in self.chunks[chunk_x]:
self.chunks[chunk_x][chunk_y] = {}
self.chunk_locks[chunk_x][chunk_y] = {}
self.chunks[chunk_x][chunk_y][chunk_z] = Chunk.Chunk(
chunk_x, chunk_y, chunk_z)
self.chunk_locks[chunk_x][chunk_y][chunk_z] = Lock()
self.world_lock.release()
def applyPerlinToChunk(self,
chunk_x: int,
chunk_y: int,
chunk_z: int) -> None:
pm = np.copy(self.getPerlinMap(chunk_x, chunk_z))
pm += 1
pm *= 16 # TODO, FIXME: not adjustable
self.acquireChunk(chunk_x, chunk_y, chunk_z)
c = self.chunks[chunk_x][chunk_y][chunk_z]
for x in range(Chunk.Chunk.CHUNK_SIDELENGTH):
for y in range(Chunk.Chunk.CHUNK_SIDELENGTH):
for z in range(Chunk.Chunk.CHUNK_SIDELENGTH):
c.block_data[x, y, z] = 1 if pm[x, z] > y + \
chunk_y*Chunk.Chunk.CHUNK_SIDELENGTH else 0
self.releaseChunk(chunk_x, chunk_y, chunk_z)
def hasPerlinMap(self, chunk_x: int, chunk_z: int) -> bool:
return (chunk_x in self.perlin_maps and
chunk_z in self.perlin_maps[chunk_x])
def __createPerlinMap(self, chunk_x: int, chunk_z: int) -> None:
pm = self.perlin_maps[chunk_x][chunk_z] = np.zeros(
shape=(Chunk.Chunk.CHUNK_SIDELENGTH, Chunk.Chunk.CHUNK_SIDELENGTH),
dtype=float)
x0 = chunk_x * Chunk.Chunk.CHUNK_SIDELENGTH
z0 = chunk_z * Chunk.Chunk.CHUNK_SIDELENGTH
for i, j in np.ndindex(pm.shape):
pm[i, j] = self.pg.perlin(i + x0, j + z0)
def getPerlinMap(self, x: int, z: int):
if x not in self.perlin_maps:
self.perlin_maps[x] = {}
if z in self.perlin_maps[x]:
return self.perlin_maps[x][z]
self.__createPerlinMap(x, z)
return self.perlin_maps[x][z]
def getChunkAsJson(self, chunk_x: int, chunk_y: int, chunk_z: int) -> str:
assert self.isChunkKnown(chunk_x, chunk_y, chunk_z)
self.acquireChunk(0, 0, 0)
json = repr(self.chunks[chunk_x][chunk_y][chunk_z])
self.releaseChunk(0, 0, 0)
return json