mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 11:44:21 -04:00
Refactor the Chunk, sperating the Server-specific functionality into a new struct.
Also fixes some data races and changes the default compression so it no longer includes the (redundant) chunk position.
This commit is contained in:
parent
0628c24b6c
commit
001416dde6
262
src/chunk.zig
262
src/chunk.zig
@ -100,13 +100,17 @@ fn extractZFromIndex(index: usize) i32 {
|
|||||||
|
|
||||||
var memoryPool: std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)) = undefined;
|
var memoryPool: std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)) = undefined;
|
||||||
var memoryPoolMutex: std.Thread.Mutex = .{};
|
var memoryPoolMutex: std.Thread.Mutex = .{};
|
||||||
|
var serverPool: std.heap.MemoryPoolAligned(ServerChunk, @alignOf(ServerChunk)) = undefined;
|
||||||
|
var serverPoolMutex: std.Thread.Mutex = .{};
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
memoryPool = std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)).init(main.globalAllocator.allocator);
|
memoryPool = std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)).init(main.globalAllocator.allocator);
|
||||||
|
serverPool = std.heap.MemoryPoolAligned(ServerChunk, @alignOf(ServerChunk)).init(main.globalAllocator.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
memoryPool.deinit();
|
memoryPool.deinit();
|
||||||
|
serverPool.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ChunkPosition = struct {
|
pub const ChunkPosition = struct {
|
||||||
@ -126,6 +130,8 @@ pub const ChunkPosition = struct {
|
|||||||
return self.equals(notNull);
|
return self.equals(notNull);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
} else if(@TypeOf(other.*) == ServerChunk) {
|
||||||
|
return self.wx == other.super.pos.wx and self.wy == other.super.pos.wy and self.wz == other.super.pos.wz and self.voxelSize == other.super.pos.voxelSize;
|
||||||
} else if(@typeInfo(@TypeOf(other)) == .Pointer) {
|
} else if(@typeInfo(@TypeOf(other)) == .Pointer) {
|
||||||
return self.wx == other.pos.wx and self.wy == other.pos.wy and self.wz == other.pos.wz and self.voxelSize == other.pos.voxelSize;
|
return self.wx == other.pos.wx and self.wy == other.pos.wy and self.wz == other.pos.wz and self.voxelSize == other.pos.voxelSize;
|
||||||
} else @compileError("Unsupported");
|
} else @compileError("Unsupported");
|
||||||
@ -173,17 +179,12 @@ pub const Chunk = struct {
|
|||||||
pos: ChunkPosition,
|
pos: ChunkPosition,
|
||||||
data: main.utils.PaletteCompressedRegion(Block, chunkVolume) = undefined,
|
data: main.utils.PaletteCompressedRegion(Block, chunkVolume) = undefined,
|
||||||
|
|
||||||
wasChanged: bool = false,
|
|
||||||
generated: bool = false,
|
|
||||||
|
|
||||||
width: u31,
|
width: u31,
|
||||||
voxelSizeShift: u5,
|
voxelSizeShift: u5,
|
||||||
voxelSizeMask: i32,
|
voxelSizeMask: i32,
|
||||||
widthShift: u5,
|
widthShift: u5,
|
||||||
mutex: std.Thread.Mutex,
|
|
||||||
refCount: std.atomic.Value(u16),
|
|
||||||
|
|
||||||
pub fn initAndIncreaseRefCount(pos: ChunkPosition) *Chunk {
|
pub fn init(pos: ChunkPosition) *Chunk {
|
||||||
memoryPoolMutex.lock();
|
memoryPoolMutex.lock();
|
||||||
const self = memoryPool.create() catch unreachable;
|
const self = memoryPool.create() catch unreachable;
|
||||||
memoryPoolMutex.unlock();
|
memoryPoolMutex.unlock();
|
||||||
@ -196,75 +197,18 @@ pub const Chunk = struct {
|
|||||||
.voxelSizeShift = voxelSizeShift,
|
.voxelSizeShift = voxelSizeShift,
|
||||||
.voxelSizeMask = pos.voxelSize - 1,
|
.voxelSizeMask = pos.voxelSize - 1,
|
||||||
.widthShift = voxelSizeShift + chunkShift,
|
.widthShift = voxelSizeShift + chunkShift,
|
||||||
.mutex = std.Thread.Mutex{},
|
|
||||||
.refCount = std.atomic.Value(u16).init(1),
|
|
||||||
};
|
};
|
||||||
self.data.init();
|
self.data.init();
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Chunk) void {
|
pub fn deinit(self: *Chunk) void {
|
||||||
std.debug.assert(self.refCount.raw == 0);
|
|
||||||
if(self.wasChanged) {
|
|
||||||
self.save(main.server.world.?);
|
|
||||||
}
|
|
||||||
self.data.deinit();
|
self.data.deinit();
|
||||||
memoryPoolMutex.lock();
|
memoryPoolMutex.lock();
|
||||||
memoryPool.destroy(@alignCast(self));
|
memoryPool.destroy(@alignCast(self));
|
||||||
memoryPoolMutex.unlock();
|
memoryPoolMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increaseRefCount(self: *Chunk) void {
|
|
||||||
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
|
||||||
std.debug.assert(prevVal != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decreaseRefCount(self: *Chunk) void {
|
|
||||||
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
|
||||||
std.debug.assert(prevVal != 0);
|
|
||||||
if(prevVal == 1) {
|
|
||||||
self.deinit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setChanged(self: *Chunk) void {
|
|
||||||
main.utils.assertLocked(&self.mutex);
|
|
||||||
if(!self.wasChanged) {
|
|
||||||
self.wasChanged = true;
|
|
||||||
self.increaseRefCount();
|
|
||||||
main.server.world.?.queueChunkUpdateAndDecreaseRefCount(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the given relative coordinates lie within the bounds of this chunk.
|
|
||||||
pub fn liesInChunk(self: *const Chunk, x: i32, y: i32, z: i32) bool {
|
|
||||||
return x >= 0 and x < self.width
|
|
||||||
and y >= 0 and y < self.width
|
|
||||||
and z >= 0 and z < self.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is useful to convert for loops to work for reduced resolution:
|
|
||||||
/// Instead of using
|
|
||||||
/// for(int x = start; x < end; x++)
|
|
||||||
/// for(int x = chunk.startIndex(start); x < end; x += chunk.getVoxelSize())
|
|
||||||
/// should be used to only activate those voxels that are used in Cubyz's downscaling technique.
|
|
||||||
pub fn startIndex(self: *const Chunk, start: i32) i32 {
|
|
||||||
return start+self.voxelSizeMask & ~self.voxelSizeMask; // Rounds up to the nearest valid voxel coordinate.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates a block if current value is air or the current block is degradable.
|
|
||||||
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
|
||||||
pub fn updateBlockIfDegradable(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
|
||||||
const x = _x >> self.voxelSizeShift;
|
|
||||||
const y = _y >> self.voxelSizeShift;
|
|
||||||
const z = _z >> self.voxelSizeShift;
|
|
||||||
const index = getIndex(x, y, z);
|
|
||||||
const oldBlock = self.data.getValue(index);
|
|
||||||
if(oldBlock.typ == 0 or oldBlock.degradable()) {
|
|
||||||
self.data.setValue(index, newBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates a block if it is inside this chunk.
|
/// Updates a block if it is inside this chunk.
|
||||||
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
pub fn updateBlock(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
pub fn updateBlock(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
||||||
@ -275,27 +219,6 @@ pub const Chunk = struct {
|
|||||||
self.data.setValue(index, newBlock);
|
self.data.setValue(index, newBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates a block if it is inside this chunk.
|
|
||||||
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
|
||||||
pub fn updateBlockAndSetChanged(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
|
||||||
const x = _x >> self.voxelSizeShift;
|
|
||||||
const y = _y >> self.voxelSizeShift;
|
|
||||||
const z = _z >> self.voxelSizeShift;
|
|
||||||
const index = getIndex(x, y, z);
|
|
||||||
self.data.setValue(index, newBlock);
|
|
||||||
self.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates a block if it is inside this chunk. Should be used in generation to prevent accidently storing these as changes.
|
|
||||||
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
|
||||||
pub fn updateBlockInGeneration(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
|
||||||
const x = _x >> self.voxelSizeShift;
|
|
||||||
const y = _y >> self.voxelSizeShift;
|
|
||||||
const z = _z >> self.voxelSizeShift;
|
|
||||||
const index = getIndex(x, y, z);
|
|
||||||
self.data.setValue(index, newBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a block if it is inside this chunk.
|
/// Gets a block if it is inside this chunk.
|
||||||
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
pub fn getBlock(self: *const Chunk, _x: i32, _y: i32, _z: i32) Block {
|
pub fn getBlock(self: *const Chunk, _x: i32, _y: i32, _z: i32) Block {
|
||||||
@ -305,11 +228,139 @@ pub const Chunk = struct {
|
|||||||
const index = getIndex(x, y, z);
|
const index = getIndex(x, y, z);
|
||||||
return self.data.getValue(index);
|
return self.data.getValue(index);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn updateFromLowerResolution(self: *Chunk, other: *Chunk) void {
|
pub const ServerChunk = struct {
|
||||||
const xOffset = if(other.pos.wx != self.pos.wx) chunkSize/2 else 0; // Offsets of the lower resolution chunk in this chunk.
|
super: Chunk,
|
||||||
const yOffset = if(other.pos.wy != self.pos.wy) chunkSize/2 else 0;
|
|
||||||
const zOffset = if(other.pos.wz != self.pos.wz) chunkSize/2 else 0;
|
wasChanged: bool = false,
|
||||||
|
generated: bool = false,
|
||||||
|
|
||||||
|
mutex: std.Thread.Mutex = .{},
|
||||||
|
refCount: std.atomic.Value(u16),
|
||||||
|
|
||||||
|
pub fn initAndIncreaseRefCount(pos: ChunkPosition) *ServerChunk {
|
||||||
|
serverPoolMutex.lock();
|
||||||
|
const self = serverPool.create() catch unreachable;
|
||||||
|
serverPoolMutex.unlock();
|
||||||
|
std.debug.assert((pos.voxelSize - 1 & pos.voxelSize) == 0);
|
||||||
|
std.debug.assert(@mod(pos.wx, pos.voxelSize) == 0 and @mod(pos.wy, pos.voxelSize) == 0 and @mod(pos.wz, pos.voxelSize) == 0);
|
||||||
|
const voxelSizeShift: u5 = @intCast(std.math.log2_int(u31, pos.voxelSize));
|
||||||
|
self.* = ServerChunk {
|
||||||
|
.super = .{
|
||||||
|
.pos = pos,
|
||||||
|
.width = pos.voxelSize*chunkSize,
|
||||||
|
.voxelSizeShift = voxelSizeShift,
|
||||||
|
.voxelSizeMask = pos.voxelSize - 1,
|
||||||
|
.widthShift = voxelSizeShift + chunkShift,
|
||||||
|
},
|
||||||
|
.refCount = std.atomic.Value(u16).init(1),
|
||||||
|
};
|
||||||
|
self.super.data.init();
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ServerChunk) void {
|
||||||
|
std.debug.assert(self.refCount.raw == 0);
|
||||||
|
if(self.wasChanged) {
|
||||||
|
self.save(main.server.world.?);
|
||||||
|
}
|
||||||
|
self.super.data.deinit();
|
||||||
|
serverPoolMutex.lock();
|
||||||
|
serverPool.destroy(@alignCast(self));
|
||||||
|
serverPoolMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setChanged(self: *ServerChunk) void {
|
||||||
|
main.utils.assertLocked(&self.mutex);
|
||||||
|
if(!self.wasChanged) {
|
||||||
|
self.wasChanged = true;
|
||||||
|
self.increaseRefCount();
|
||||||
|
main.server.world.?.queueChunkUpdateAndDecreaseRefCount(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increaseRefCount(self: *ServerChunk) void {
|
||||||
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decreaseRefCount(self: *ServerChunk) void {
|
||||||
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the given relative coordinates lie within the bounds of this chunk.
|
||||||
|
pub fn liesInChunk(self: *const ServerChunk, x: i32, y: i32, z: i32) bool {
|
||||||
|
return x >= 0 and x < self.super.width
|
||||||
|
and y >= 0 and y < self.super.width
|
||||||
|
and z >= 0 and z < self.super.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is useful to convert for loops to work for reduced resolution:
|
||||||
|
/// Instead of using
|
||||||
|
/// for(int x = start; x < end; x++)
|
||||||
|
/// for(int x = chunk.startIndex(start); x < end; x += chunk.getVoxelSize())
|
||||||
|
/// should be used to only activate those voxels that are used in Cubyz's downscaling technique.
|
||||||
|
pub fn startIndex(self: *const ServerChunk, start: i32) i32 {
|
||||||
|
return start+self.super.voxelSizeMask & ~self.super.voxelSizeMask; // Rounds up to the nearest valid voxel coordinate.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a block if it is inside this chunk.
|
||||||
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
|
pub fn getBlock(self: *const ServerChunk, _x: i32, _y: i32, _z: i32) Block {
|
||||||
|
main.utils.assertLocked(&self.mutex);
|
||||||
|
const x = _x >> self.super.voxelSizeShift;
|
||||||
|
const y = _y >> self.super.voxelSizeShift;
|
||||||
|
const z = _z >> self.super.voxelSizeShift;
|
||||||
|
const index = getIndex(x, y, z);
|
||||||
|
return self.super.data.getValue(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a block if it is inside this chunk.
|
||||||
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
|
pub fn updateBlockAndSetChanged(self: *ServerChunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
||||||
|
main.utils.assertLocked(&self.mutex);
|
||||||
|
const x = _x >> self.super.voxelSizeShift;
|
||||||
|
const y = _y >> self.super.voxelSizeShift;
|
||||||
|
const z = _z >> self.super.voxelSizeShift;
|
||||||
|
const index = getIndex(x, y, z);
|
||||||
|
self.super.data.setValue(index, newBlock);
|
||||||
|
self.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a block if current value is air or the current block is degradable.
|
||||||
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
|
pub fn updateBlockIfDegradable(self: *ServerChunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
||||||
|
main.utils.assertLocked(&self.mutex);
|
||||||
|
const x = _x >> self.super.voxelSizeShift;
|
||||||
|
const y = _y >> self.super.voxelSizeShift;
|
||||||
|
const z = _z >> self.super.voxelSizeShift;
|
||||||
|
const index = getIndex(x, y, z);
|
||||||
|
const oldBlock = self.super.data.getValue(index);
|
||||||
|
if(oldBlock.typ == 0 or oldBlock.degradable()) {
|
||||||
|
self.super.data.setValue(index, newBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a block if it is inside this chunk. Should be used in generation to prevent accidently storing these as changes.
|
||||||
|
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
|
||||||
|
pub fn updateBlockInGeneration(self: *ServerChunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {
|
||||||
|
main.utils.assertLocked(&self.mutex);
|
||||||
|
const x = _x >> self.super.voxelSizeShift;
|
||||||
|
const y = _y >> self.super.voxelSizeShift;
|
||||||
|
const z = _z >> self.super.voxelSizeShift;
|
||||||
|
const index = getIndex(x, y, z);
|
||||||
|
self.super.data.setValue(index, newBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateFromLowerResolution(self: *ServerChunk, other: *ServerChunk) void {
|
||||||
|
const xOffset = if(other.super.pos.wx != self.super.pos.wx) chunkSize/2 else 0; // Offsets of the lower resolution chunk in this chunk.
|
||||||
|
const yOffset = if(other.super.pos.wy != self.super.pos.wy) chunkSize/2 else 0;
|
||||||
|
const zOffset = if(other.super.pos.wz != self.super.pos.wz) chunkSize/2 else 0;
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
defer self.mutex.unlock();
|
defer self.mutex.unlock();
|
||||||
main.utils.assertLocked(&other.mutex);
|
main.utils.assertLocked(&other.mutex);
|
||||||
@ -332,7 +383,7 @@ pub const Chunk = struct {
|
|||||||
while(dz <= 1): (dz += 1) {
|
while(dz <= 1): (dz += 1) {
|
||||||
const index = getIndex(x*2 + dx, y*2 + dy, z*2 + dz);
|
const index = getIndex(x*2 + dx, y*2 + dy, z*2 + dz);
|
||||||
const i = dx*4 + dz*2 + dy;
|
const i = dx*4 + dz*2 + dy;
|
||||||
octantBlocks[i] = other.data.getValue(index);
|
octantBlocks[i] = other.super.data.getValue(index);
|
||||||
if(octantBlocks[i].typ == 0) {
|
if(octantBlocks[i].typ == 0) {
|
||||||
neighborCount[i] = 0;
|
neighborCount[i] = 0;
|
||||||
continue; // I don't care about air blocks.
|
continue; // I don't care about air blocks.
|
||||||
@ -345,7 +396,7 @@ pub const Chunk = struct {
|
|||||||
const nz = z*2 + dz + Neighbors.relZ[n];
|
const nz = z*2 + dz + Neighbors.relZ[n];
|
||||||
if((nx & chunkMask) == nx and (ny & chunkMask) == ny and (nz & chunkMask) == nz) { // If it's inside the chunk.
|
if((nx & chunkMask) == nx and (ny & chunkMask) == ny and (nz & chunkMask) == nz) { // If it's inside the chunk.
|
||||||
const neighborIndex = getIndex(nx, ny, nz);
|
const neighborIndex = getIndex(nx, ny, nz);
|
||||||
if(other.data.getValue(neighborIndex).transparent()) {
|
if(other.super.data.getValue(neighborIndex).transparent()) {
|
||||||
count += 5;
|
count += 5;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -368,7 +419,7 @@ pub const Chunk = struct {
|
|||||||
}
|
}
|
||||||
// Update the block:
|
// Update the block:
|
||||||
const thisIndex = getIndex(x + xOffset, y + yOffset, z + zOffset);
|
const thisIndex = getIndex(x + xOffset, y + yOffset, z + zOffset);
|
||||||
self.data.setValue(thisIndex, block);
|
self.super.data.setValue(thisIndex, block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,32 +427,33 @@ pub const Chunk = struct {
|
|||||||
self.setChanged();
|
self.setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(self: *Chunk, world: *main.server.ServerWorld) void {
|
pub fn save(self: *ServerChunk, world: *main.server.ServerWorld) void {
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
defer self.mutex.unlock();
|
defer self.mutex.unlock();
|
||||||
if(self.wasChanged) {
|
if(self.wasChanged) {
|
||||||
const regionSize = self.pos.voxelSize*chunkSize*main.server.storage.RegionFile.regionSize;
|
const pos = self.super.pos;
|
||||||
|
const regionSize = pos.voxelSize*chunkSize*main.server.storage.RegionFile.regionSize;
|
||||||
const regionMask: i32 = regionSize - 1;
|
const regionMask: i32 = regionSize - 1;
|
||||||
const region = main.server.storage.loadRegionFileAndIncreaseRefCount(self.pos.wx & ~regionMask, self.pos.wy & ~regionMask, self.pos.wz & ~regionMask, self.pos.voxelSize);
|
const region = main.server.storage.loadRegionFileAndIncreaseRefCount(pos.wx & ~regionMask, pos.wy & ~regionMask, pos.wz & ~regionMask, pos.voxelSize);
|
||||||
defer region.decreaseRefCount();
|
defer region.decreaseRefCount();
|
||||||
const data = main.server.storage.ChunkCompression.compressChunk(main.stackAllocator, self);
|
const data = main.server.storage.ChunkCompression.compressChunk(main.stackAllocator, &self.super);
|
||||||
defer main.stackAllocator.free(data);
|
defer main.stackAllocator.free(data);
|
||||||
region.storeChunk(
|
region.storeChunk(
|
||||||
data,
|
data,
|
||||||
@as(usize, @intCast(self.pos.wx -% region.pos.wx))/self.pos.voxelSize/chunkSize,
|
@as(usize, @intCast(pos.wx -% region.pos.wx))/pos.voxelSize/chunkSize,
|
||||||
@as(usize, @intCast(self.pos.wy -% region.pos.wy))/self.pos.voxelSize/chunkSize,
|
@as(usize, @intCast(pos.wy -% region.pos.wy))/pos.voxelSize/chunkSize,
|
||||||
@as(usize, @intCast(self.pos.wz -% region.pos.wz))/self.pos.voxelSize/chunkSize,
|
@as(usize, @intCast(pos.wz -% region.pos.wz))/pos.voxelSize/chunkSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.wasChanged = false;
|
self.wasChanged = false;
|
||||||
// Update the next lod chunk:
|
// Update the next lod chunk:
|
||||||
if(self.pos.voxelSize != 1 << settings.highestLOD) {
|
if(pos.voxelSize != 1 << settings.highestLOD) {
|
||||||
var pos = self.pos;
|
var nextPos = pos;
|
||||||
pos.wx &= ~(pos.voxelSize*chunkSize);
|
nextPos.wx &= ~(pos.voxelSize*chunkSize);
|
||||||
pos.wy &= ~(pos.voxelSize*chunkSize);
|
nextPos.wy &= ~(pos.voxelSize*chunkSize);
|
||||||
pos.wz &= ~(pos.voxelSize*chunkSize);
|
nextPos.wz &= ~(pos.voxelSize*chunkSize);
|
||||||
pos.voxelSize *= 2;
|
nextPos.voxelSize *= 2;
|
||||||
const nextHigherLod = world.getOrGenerateChunkAndIncreaseRefCount(pos);
|
const nextHigherLod = world.getOrGenerateChunkAndIncreaseRefCount(nextPos);
|
||||||
defer nextHigherLod.decreaseRefCount();
|
defer nextHigherLod.decreaseRefCount();
|
||||||
nextHigherLod.updateFromLowerResolution(self);
|
nextHigherLod.updateFromLowerResolution(self);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
|
|
||||||
const blocks = @import("blocks.zig");
|
const blocks = @import("blocks.zig");
|
||||||
const chunk_zig = @import("chunk.zig");
|
const chunk_zig = @import("chunk.zig");
|
||||||
const Chunk = chunk_zig.Chunk;
|
const ServerChunk = chunk_zig.ServerChunk;
|
||||||
const game = @import("game.zig");
|
const game = @import("game.zig");
|
||||||
const World = game.World;
|
const World = game.World;
|
||||||
const ServerWorld = main.server.ServerWorld;
|
const ServerWorld = main.server.ServerWorld;
|
||||||
@ -294,7 +294,7 @@ pub const ItemDropManager = struct {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn updateEnt(self: *ItemDropManager, chunk: *Chunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
|
fn updateEnt(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
|
||||||
main.utils.assertLocked(&self.mutex);
|
main.utils.assertLocked(&self.mutex);
|
||||||
const startedInABlock = self.checkBlocks(chunk, pos);
|
const startedInABlock = self.checkBlocks(chunk, pos);
|
||||||
if(startedInABlock) {
|
if(startedInABlock) {
|
||||||
@ -318,7 +318,7 @@ pub const ItemDropManager = struct {
|
|||||||
vel.* *= @splat(@max(0, 1 - drag*deltaTime));
|
vel.* *= @splat(@max(0, 1 - drag*deltaTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixStuckInBlock(self: *ItemDropManager, chunk: *Chunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
|
fn fixStuckInBlock(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
|
||||||
main.utils.assertLocked(&self.mutex);
|
main.utils.assertLocked(&self.mutex);
|
||||||
const centeredPos = pos.* - @as(Vec3d, @splat(0.5));
|
const centeredPos = pos.* - @as(Vec3d, @splat(0.5));
|
||||||
const pos0: Vec3i = @intFromFloat(@floor(centeredPos));
|
const pos0: Vec3i = @intFromFloat(@floor(centeredPos));
|
||||||
@ -355,7 +355,7 @@ pub const ItemDropManager = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checkBlocks(self: *ItemDropManager, chunk: *Chunk, pos: *Vec3d) bool {
|
fn checkBlocks(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d) bool {
|
||||||
const lowerCornerPos = pos.* - @as(Vec3d, @splat(radius));
|
const lowerCornerPos = pos.* - @as(Vec3d, @splat(radius));
|
||||||
const pos0f64 = @floor(lowerCornerPos);
|
const pos0f64 = @floor(lowerCornerPos);
|
||||||
const pos0: Vec3i = @intFromFloat(pos0f64);
|
const pos0: Vec3i = @intFromFloat(pos0f64);
|
||||||
@ -389,7 +389,7 @@ pub const ItemDropManager = struct {
|
|||||||
return isSolid;
|
return isSolid;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checkBlock(self: *ItemDropManager, chunk: *Chunk, pos: *Vec3d, blockPos: Vec3i) bool {
|
fn checkBlock(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, blockPos: Vec3i) bool {
|
||||||
// TODO: Check if the item drop collides with the block in the given location.
|
// TODO: Check if the item drop collides with the block in the given location.
|
||||||
_ = self;
|
_ = self;
|
||||||
_ = chunk;
|
_ = chunk;
|
||||||
|
@ -721,23 +721,36 @@ pub const Protocols = struct {
|
|||||||
pub const chunkTransmission = struct {
|
pub const chunkTransmission = struct {
|
||||||
pub const id: u8 = 3;
|
pub const id: u8 = 3;
|
||||||
fn receive(_: *Connection, data: []const u8) !void {
|
fn receive(_: *Connection, data: []const u8) !void {
|
||||||
const ch = try main.server.storage.ChunkCompression.decompressChunkAndIncreaseRefCount(data);
|
const pos = chunk.ChunkPosition{
|
||||||
renderer.mesh_storage.updateChunkMeshAndDecreaseRefCount(ch);
|
.wx = std.mem.readInt(i32, data[0..4], .big),
|
||||||
|
.wy = std.mem.readInt(i32, data[4..8], .big),
|
||||||
|
.wz = std.mem.readInt(i32, data[8..12], .big),
|
||||||
|
.voxelSize = @intCast(std.mem.readInt(i32, data[12..16], .big)),
|
||||||
|
};
|
||||||
|
const ch = chunk.Chunk.init(pos);
|
||||||
|
try main.server.storage.ChunkCompression.decompressChunk(ch, data[16..]);
|
||||||
|
renderer.mesh_storage.updateChunkMesh(ch);
|
||||||
}
|
}
|
||||||
fn sendChunkOverTheNetwork(conn: *Connection, ch: *chunk.Chunk) void {
|
fn sendChunkOverTheNetwork(conn: *Connection, ch: *chunk.ServerChunk) void {
|
||||||
ch.mutex.lock();
|
ch.mutex.lock();
|
||||||
const data = main.server.storage.ChunkCompression.compressChunk(main.stackAllocator, ch);
|
const chunkData = main.server.storage.ChunkCompression.compressChunk(main.stackAllocator, &ch.super);
|
||||||
ch.mutex.unlock();
|
ch.mutex.unlock();
|
||||||
defer main.stackAllocator.free(data);
|
defer main.stackAllocator.free(chunkData);
|
||||||
|
const data = main.stackAllocator.alloc(u8, chunkData.len + 16);
|
||||||
|
std.mem.writeInt(i32, data[0..4], ch.super.pos.wx, .big);
|
||||||
|
std.mem.writeInt(i32, data[4..8], ch.super.pos.wy, .big);
|
||||||
|
std.mem.writeInt(i32, data[8..12], ch.super.pos.wz, .big);
|
||||||
|
std.mem.writeInt(i32, data[12..16], ch.super.pos.voxelSize, .big);
|
||||||
|
@memcpy(data[16..], chunkData);
|
||||||
conn.sendImportant(id, data);
|
conn.sendImportant(id, data);
|
||||||
}
|
}
|
||||||
fn sendChunkLocally(ch: *chunk.Chunk) void {
|
fn sendChunkLocally(ch: *chunk.ServerChunk) void {
|
||||||
const chunkCopy = chunk.Chunk.initAndIncreaseRefCount(ch.pos);
|
const chunkCopy = chunk.Chunk.init(ch.super.pos);
|
||||||
chunkCopy.data.deinit();
|
chunkCopy.data.deinit();
|
||||||
chunkCopy.data.initCopy(&ch.data);
|
chunkCopy.data.initCopy(&ch.super.data);
|
||||||
renderer.mesh_storage.updateChunkMeshAndDecreaseRefCount(chunkCopy);
|
renderer.mesh_storage.updateChunkMesh(chunkCopy);
|
||||||
}
|
}
|
||||||
pub fn sendChunk(conn: *Connection, ch: *chunk.Chunk) void {
|
pub fn sendChunk(conn: *Connection, ch: *chunk.ServerChunk) void {
|
||||||
if(conn.user.?.isLocal) {
|
if(conn.user.?.isLocal) {
|
||||||
sendChunkLocally(ch);
|
sendChunkLocally(ch);
|
||||||
} else {
|
} else {
|
||||||
|
@ -515,7 +515,7 @@ pub const ChunkMesh = struct {
|
|||||||
std.debug.assert(self.refCount.load(.monotonic) == 0);
|
std.debug.assert(self.refCount.load(.monotonic) == 0);
|
||||||
self.opaqueMesh.deinit();
|
self.opaqueMesh.deinit();
|
||||||
self.transparentMesh.deinit();
|
self.transparentMesh.deinit();
|
||||||
self.chunk.decreaseRefCount();
|
self.chunk.deinit();
|
||||||
main.globalAllocator.free(self.currentSorting);
|
main.globalAllocator.free(self.currentSorting);
|
||||||
main.globalAllocator.free(self.sortingOutputBuffer);
|
main.globalAllocator.free(self.sortingOutputBuffer);
|
||||||
for(self.lightingData) |lightingChunk| {
|
for(self.lightingData) |lightingChunk| {
|
||||||
|
@ -1072,7 +1072,7 @@ pub const MeshGenerationTask = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean(self: *MeshGenerationTask) void {
|
pub fn clean(self: *MeshGenerationTask) void {
|
||||||
self.mesh.decreaseRefCount();
|
self.mesh.deinit();
|
||||||
main.globalAllocator.destroy(self);
|
main.globalAllocator.destroy(self);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1083,7 +1083,7 @@ pub fn updateBlock(x: i32, y: i32, z: i32, newBlock: blocks.Block) void {
|
|||||||
blockUpdateList.append(BlockUpdate{.x=x, .y=y, .z=z, .newBlock=newBlock});
|
blockUpdateList.append(BlockUpdate{.x=x, .y=y, .z=z, .newBlock=newBlock});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateChunkMeshAndDecreaseRefCount(mesh: *chunk.Chunk) void {
|
pub fn updateChunkMesh(mesh: *chunk.Chunk) void {
|
||||||
MeshGenerationTask.schedule(mesh);
|
MeshGenerationTask.schedule(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,54 +207,43 @@ pub fn loadRegionFileAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u
|
|||||||
|
|
||||||
pub const ChunkCompression = struct {
|
pub const ChunkCompression = struct {
|
||||||
const CompressionAlgo = enum(u32) {
|
const CompressionAlgo = enum(u32) {
|
||||||
deflate = 0, // TODO: Investigate if palette compression (or palette compression with huffman coding) is more efficient.
|
deflate_with_position = 0,
|
||||||
|
deflate = 1, // TODO: Investigate if palette compression (or palette compression with huffman coding) is more efficient.
|
||||||
_, // TODO: Add more algorithms for specific cases like uniform chunks.
|
_, // TODO: Add more algorithms for specific cases like uniform chunks.
|
||||||
};
|
};
|
||||||
pub fn compressChunk(allocator: main.utils.NeverFailingAllocator, ch: *chunk.Chunk) []const u8 {
|
pub fn compressChunk(allocator: main.utils.NeverFailingAllocator, ch: *chunk.Chunk) []const u8 {
|
||||||
main.utils.assertLocked(&ch.mutex);
|
|
||||||
var uncompressedData: [chunk.chunkVolume*@sizeOf(u32)]u8 = undefined;
|
var uncompressedData: [chunk.chunkVolume*@sizeOf(u32)]u8 = undefined;
|
||||||
for(0..chunk.chunkVolume) |i| {
|
for(0..chunk.chunkVolume) |i| {
|
||||||
std.mem.writeInt(u32, uncompressedData[4*i..][0..4], ch.data.getValue(i).toInt(), .big);
|
std.mem.writeInt(u32, uncompressedData[4*i..][0..4], ch.data.getValue(i).toInt(), .big);
|
||||||
}
|
}
|
||||||
const compressedData = main.utils.Compression.deflate(main.stackAllocator, &uncompressedData);
|
const compressedData = main.utils.Compression.deflate(main.stackAllocator, &uncompressedData);
|
||||||
defer main.stackAllocator.free(compressedData);
|
defer main.stackAllocator.free(compressedData);
|
||||||
const data = allocator.alloc(u8, 20 + compressedData.len);
|
const data = allocator.alloc(u8, 4 + compressedData.len);
|
||||||
@memcpy(data[20..], compressedData);
|
@memcpy(data[4..], compressedData);
|
||||||
std.mem.writeInt(i32, data[0..4], @intFromEnum(CompressionAlgo.deflate), .big);
|
std.mem.writeInt(i32, data[0..4], @intFromEnum(CompressionAlgo.deflate), .big);
|
||||||
std.mem.writeInt(i32, data[4..8], ch.pos.wx, .big);
|
|
||||||
std.mem.writeInt(i32, data[8..12], ch.pos.wy, .big);
|
|
||||||
std.mem.writeInt(i32, data[12..16], ch.pos.wz, .big);
|
|
||||||
std.mem.writeInt(i32, data[16..20], ch.pos.voxelSize, .big);
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decompressChunkAndIncreaseRefCount(_data: []const u8) error{corrupted}!*chunk.Chunk {
|
pub fn decompressChunk(ch: *chunk.Chunk, _data: []const u8) error{corrupted}!void {
|
||||||
var data = _data;
|
var data = _data;
|
||||||
if(data.len < 4) return error.corrupted;
|
if(data.len < 4) return error.corrupted;
|
||||||
const algo: CompressionAlgo = @enumFromInt(std.mem.readInt(u32, data[0..4], .big));
|
const algo: CompressionAlgo = @enumFromInt(std.mem.readInt(u32, data[0..4], .big));
|
||||||
data = data[4..];
|
data = data[4..];
|
||||||
|
if(algo == .deflate_with_position) data = data[16..];
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
.deflate => {
|
.deflate, .deflate_with_position => {
|
||||||
if(data.len < 16) return error.corrupted;
|
|
||||||
const pos = chunk.ChunkPosition{
|
|
||||||
.wx = std.mem.readInt(i32, data[0..4], .big),
|
|
||||||
.wy = std.mem.readInt(i32, data[4..8], .big),
|
|
||||||
.wz = std.mem.readInt(i32, data[8..12], .big),
|
|
||||||
.voxelSize = @intCast(std.mem.readInt(i32, data[12..16], .big)),
|
|
||||||
};
|
|
||||||
const _inflatedData = main.stackAllocator.alloc(u8, chunk.chunkVolume*4);
|
const _inflatedData = main.stackAllocator.alloc(u8, chunk.chunkVolume*4);
|
||||||
defer main.stackAllocator.free(_inflatedData);
|
defer main.stackAllocator.free(_inflatedData);
|
||||||
const _inflatedLen = main.utils.Compression.inflateTo(_inflatedData, data[16..]) catch return error.corrupted;
|
const _inflatedLen = main.utils.Compression.inflateTo(_inflatedData, data[0..]) catch return error.corrupted;
|
||||||
if(_inflatedLen != chunk.chunkVolume*4) {
|
if(_inflatedLen != chunk.chunkVolume*4) {
|
||||||
return error.corrupted;
|
return error.corrupted;
|
||||||
}
|
}
|
||||||
data = _inflatedData;
|
data = _inflatedData;
|
||||||
const ch = chunk.Chunk.initAndIncreaseRefCount(pos);
|
|
||||||
for(0..chunk.chunkVolume) |i| {
|
for(0..chunk.chunkVolume) |i| {
|
||||||
ch.data.setValue(i, main.blocks.Block.fromInt(std.mem.readInt(u32, data[0..4], .big)));
|
ch.data.setValue(i, main.blocks.Block.fromInt(std.mem.readInt(u32, data[0..4], .big)));
|
||||||
data = data[4..];
|
data = data[4..];
|
||||||
}
|
}
|
||||||
return ch;
|
return;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return error.corrupted;
|
return error.corrupted;
|
||||||
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||||||
const main = @import("root");
|
const main = @import("root");
|
||||||
const Array3D = main.utils.Array3D;
|
const Array3D = main.utils.Array3D;
|
||||||
const Cache = main.utils.Cache;
|
const Cache = main.utils.Cache;
|
||||||
const Chunk = main.chunk.Chunk;
|
const ServerChunk = main.chunk.ServerChunk;
|
||||||
const ChunkPosition = main.chunk.ChunkPosition;
|
const ChunkPosition = main.chunk.ChunkPosition;
|
||||||
const JsonElement = main.JsonElement;
|
const JsonElement = main.JsonElement;
|
||||||
const vec = main.vec;
|
const vec = main.vec;
|
||||||
@ -383,17 +383,19 @@ pub const CaveBiomeMapView = struct {
|
|||||||
noiseY: ?CachedFractalNoise3D = null,
|
noiseY: ?CachedFractalNoise3D = null,
|
||||||
noiseZ: ?CachedFractalNoise3D = null,
|
noiseZ: ?CachedFractalNoise3D = null,
|
||||||
|
|
||||||
pub fn init(chunk: *Chunk) CaveBiomeMapView {
|
pub fn init(chunk: *ServerChunk) CaveBiomeMapView {
|
||||||
|
const pos = chunk.super.pos;
|
||||||
|
const width = chunk.super.width;
|
||||||
var self = CaveBiomeMapView {
|
var self = CaveBiomeMapView {
|
||||||
.super = InterpolatableCaveBiomeMapView.init(chunk.pos, chunk.width),
|
.super = InterpolatableCaveBiomeMapView.init(pos, width),
|
||||||
};
|
};
|
||||||
if(chunk.pos.voxelSize < 8) {
|
if(pos.voxelSize < 8) {
|
||||||
const startX = (chunk.pos.wx -% 32) & ~@as(i32, 63);
|
const startX = (pos.wx -% 32) & ~@as(i32, 63);
|
||||||
const startY = (chunk.pos.wy -% 32) & ~@as(i32, 63);
|
const startY = (pos.wy -% 32) & ~@as(i32, 63);
|
||||||
const startZ = (chunk.pos.wz -% 32) & ~@as(i32, 63);
|
const startZ = (pos.wz -% 32) & ~@as(i32, 63);
|
||||||
self.noiseX = CachedFractalNoise3D.init(startX, startY, startZ, chunk.pos.voxelSize*4, chunk.width + 128, main.server.world.?.seed ^ 0x764923684396, 64);
|
self.noiseX = CachedFractalNoise3D.init(startX, startY, startZ, pos.voxelSize*4, width + 128, main.server.world.?.seed ^ 0x764923684396, 64);
|
||||||
self.noiseY = CachedFractalNoise3D.init(startX, startY, startZ, chunk.pos.voxelSize*4, chunk.width + 128, main.server.world.?.seed ^ 0x6547835649265429, 64);
|
self.noiseY = CachedFractalNoise3D.init(startX, startY, startZ, pos.voxelSize*4, width + 128, main.server.world.?.seed ^ 0x6547835649265429, 64);
|
||||||
self.noiseZ = CachedFractalNoise3D.init(startX, startY, startZ, chunk.pos.voxelSize*4, chunk.width + 128, main.server.world.?.seed ^ 0x56789365396783, 64);
|
self.noiseZ = CachedFractalNoise3D.init(startX, startY, startZ, pos.voxelSize*4, width + 128, main.server.world.?.seed ^ 0x56789365396783, 64);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
const Atomic = std.atomic.Value;
|
const Atomic = std.atomic.Value;
|
||||||
|
|
||||||
const main = @import("root");
|
const main = @import("root");
|
||||||
const Chunk = main.chunk.Chunk;
|
const ServerChunk = main.chunk.ServerChunk;
|
||||||
const ChunkPosition = main.chunk.ChunkPosition;
|
const ChunkPosition = main.chunk.ChunkPosition;
|
||||||
const Cache = main.utils.Cache;
|
const Cache = main.utils.Cache;
|
||||||
const JsonElement = main.JsonElement;
|
const JsonElement = main.JsonElement;
|
||||||
@ -141,21 +141,23 @@ pub const CaveGenerator = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const CaveMapView = struct {
|
pub const CaveMapView = struct {
|
||||||
reference: *Chunk,
|
reference: *ServerChunk,
|
||||||
fragments: [8]*CaveMapFragment,
|
fragments: [8]*CaveMapFragment,
|
||||||
|
|
||||||
pub fn init(chunk: *Chunk) CaveMapView {
|
pub fn init(chunk: *ServerChunk) CaveMapView {
|
||||||
|
const pos = chunk.super.pos;
|
||||||
|
const width = chunk.super.width;
|
||||||
return CaveMapView {
|
return CaveMapView {
|
||||||
.reference = chunk,
|
.reference = chunk,
|
||||||
.fragments = [_]*CaveMapFragment {
|
.fragments = [_]*CaveMapFragment {
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
|
||||||
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -167,40 +169,40 @@ pub const CaveMapView = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn isSolid(self: CaveMapView, relX: i32, relY: i32, relZ: i32) bool {
|
pub fn isSolid(self: CaveMapView, relX: i32, relY: i32, relZ: i32) bool {
|
||||||
const wx = relX +% self.reference.pos.wx;
|
const wx = relX +% self.reference.super.pos.wx;
|
||||||
const wy = relY +% self.reference.pos.wy;
|
const wy = relY +% self.reference.super.pos.wy;
|
||||||
const wz = relZ +% self.reference.pos.wz;
|
const wz = relZ +% self.reference.super.pos.wz;
|
||||||
var index: u8 = 0;
|
var index: u8 = 0;
|
||||||
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 4;
|
index += 4;
|
||||||
}
|
}
|
||||||
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 2;
|
index += 2;
|
||||||
}
|
}
|
||||||
if(wz -% self.fragments[0].pos.wz >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wz -% self.fragments[0].pos.wz >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
||||||
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
||||||
const fragmentRelZ = @divFloor(wz - self.fragments[index].pos.wz, self.reference.pos.voxelSize);
|
const fragmentRelZ = @divFloor(wz - self.fragments[index].pos.wz, self.reference.super.pos.voxelSize);
|
||||||
const height = self.fragments[index].getColumnData(fragmentRelX, fragmentRelY);
|
const height = self.fragments[index].getColumnData(fragmentRelX, fragmentRelY);
|
||||||
return (height & @as(u64, 1)<<@intCast(fragmentRelZ)) != 0;
|
return (height & @as(u64, 1)<<@intCast(fragmentRelZ)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getHeightData(self: CaveMapView, relX: i32, relY: i32) u32 {
|
pub fn getHeightData(self: CaveMapView, relX: i32, relY: i32) u32 {
|
||||||
const wx = relX +% self.reference.pos.wx;
|
const wx = relX +% self.reference.super.pos.wx;
|
||||||
const wy = relY +% self.reference.pos.wy;
|
const wy = relY +% self.reference.super.pos.wy;
|
||||||
var index: u8 = 0;
|
var index: u8 = 0;
|
||||||
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 4;
|
index += 4;
|
||||||
}
|
}
|
||||||
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 2;
|
index += 2;
|
||||||
}
|
}
|
||||||
var deltaZ = self.reference.pos.wz -% self.fragments[0].pos.wz;
|
var deltaZ = self.reference.super.pos.wz -% self.fragments[0].pos.wz;
|
||||||
if(deltaZ >= CaveMapFragment.height*self.reference.pos.voxelSize) {
|
if(deltaZ >= CaveMapFragment.height*self.reference.super.pos.voxelSize) {
|
||||||
index += 1;
|
index += 1;
|
||||||
deltaZ -= CaveMapFragment.height*self.reference.pos.voxelSize;
|
deltaZ -= CaveMapFragment.height*self.reference.super.pos.voxelSize;
|
||||||
}
|
}
|
||||||
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
||||||
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
||||||
@ -213,16 +215,16 @@ pub const CaveMapView = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn findTerrainChangeAbove(self: CaveMapView, relX: i32, relY: i32, z: i32) i32 {
|
pub fn findTerrainChangeAbove(self: CaveMapView, relX: i32, relY: i32, z: i32) i32 {
|
||||||
const wx = relX +% self.reference.pos.wx;
|
const wx = relX +% self.reference.super.pos.wx;
|
||||||
const wy = relY +% self.reference.pos.wy;
|
const wy = relY +% self.reference.super.pos.wy;
|
||||||
var index: u8 = 0;
|
var index: u8 = 0;
|
||||||
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 4;
|
index += 4;
|
||||||
}
|
}
|
||||||
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 2;
|
index += 2;
|
||||||
}
|
}
|
||||||
var relativeZ = @divFloor(z +% self.reference.pos.wz -% self.fragments[0].pos.wz, self.reference.pos.voxelSize);
|
var relativeZ = @divFloor(z +% self.reference.super.pos.wz -% self.fragments[0].pos.wz, self.reference.super.pos.voxelSize);
|
||||||
std.debug.assert(relativeZ >= 0 and relativeZ < 2*CaveMapFragment.height);
|
std.debug.assert(relativeZ >= 0 and relativeZ < 2*CaveMapFragment.height);
|
||||||
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
||||||
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
||||||
@ -250,20 +252,20 @@ pub const CaveMapView = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
result += @ctz(height);
|
result += @ctz(height);
|
||||||
return result*self.reference.pos.voxelSize +% self.fragments[0].pos.wz -% self.reference.pos.wz;
|
return result*self.reference.super.pos.voxelSize +% self.fragments[0].pos.wz -% self.reference.super.pos.wz;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn findTerrainChangeBelow(self: CaveMapView, relX: i32, relY: i32, z: i32) i32 {
|
pub fn findTerrainChangeBelow(self: CaveMapView, relX: i32, relY: i32, z: i32) i32 {
|
||||||
const wx = relX +% self.reference.pos.wx;
|
const wx = relX +% self.reference.super.pos.wx;
|
||||||
const wy = relY +% self.reference.pos.wy;
|
const wy = relY +% self.reference.super.pos.wy;
|
||||||
var index: u8 = 0;
|
var index: u8 = 0;
|
||||||
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wx -% self.fragments[0].pos.wx >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 4;
|
index += 4;
|
||||||
}
|
}
|
||||||
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.pos.voxelSize) {
|
if(wy -% self.fragments[0].pos.wy >= CaveMapFragment.width*self.reference.super.pos.voxelSize) {
|
||||||
index += 2;
|
index += 2;
|
||||||
}
|
}
|
||||||
var relativeZ = @divFloor(z +% self.reference.pos.wz -% self.fragments[0].pos.wz, self.reference.pos.voxelSize);
|
var relativeZ = @divFloor(z +% self.reference.super.pos.wz -% self.fragments[0].pos.wz, self.reference.super.pos.voxelSize);
|
||||||
std.debug.assert(relativeZ >= 0 and relativeZ < 2*CaveMapFragment.height);
|
std.debug.assert(relativeZ >= 0 and relativeZ < 2*CaveMapFragment.height);
|
||||||
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
const fragmentRelX = wx - self.fragments[index].pos.wx;
|
||||||
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
const fragmentRelY = wy - self.fragments[index].pos.wy;
|
||||||
@ -291,7 +293,7 @@ pub const CaveMapView = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
result -= @clz(height);
|
result -= @clz(height);
|
||||||
return result*self.reference.pos.voxelSize +% self.fragments[0].pos.wz -% self.reference.pos.wz;
|
return result*self.reference.super.pos.voxelSize +% self.fragments[0].pos.wz -% self.reference.super.pos.wz;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
|
|
||||||
const main = @import("root");
|
const main = @import("root");
|
||||||
const blocks = main.blocks;
|
const blocks = main.blocks;
|
||||||
const Chunk = main.chunk.Chunk;
|
const ServerChunk = main.chunk.ServerChunk;
|
||||||
const JsonElement = main.JsonElement;
|
const JsonElement = main.JsonElement;
|
||||||
const terrain = main.server.terrain;
|
const terrain = main.server.terrain;
|
||||||
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
||||||
@ -10,7 +10,7 @@ const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
|||||||
const StructureModel = struct {
|
const StructureModel = struct {
|
||||||
const VTable = struct {
|
const VTable = struct {
|
||||||
loadModel: *const fn(arenaAllocator: NeverFailingAllocator, parameters: JsonElement) *anyopaque,
|
loadModel: *const fn(arenaAllocator: NeverFailingAllocator, parameters: JsonElement) *anyopaque,
|
||||||
generate: *const fn(self: *anyopaque, x: i32, y: i32, z: i32, chunk: *Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void,
|
generate: *const fn(self: *anyopaque, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void,
|
||||||
};
|
};
|
||||||
|
|
||||||
vtable: VTable,
|
vtable: VTable,
|
||||||
@ -30,7 +30,7 @@ const StructureModel = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(self: StructureModel, x: i32, y: i32, z: i32, chunk: *Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
pub fn generate(self: StructureModel, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
||||||
self.vtable.generate(self.data, x, y, z, chunk, caveMap, seed);
|
self.vtable.generate(self.data, x, y, z, chunk, caveMap, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ pub const BlockStructure = struct {
|
|||||||
allocator.free(self.structure);
|
allocator.free(self.structure);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addSubTerranian(self: BlockStructure, chunk: *Chunk, startingDepth: i32, minDepth: i32, x: i32, y: i32, seed: *u64) i32 {
|
pub fn addSubTerranian(self: BlockStructure, chunk: *ServerChunk, startingDepth: i32, minDepth: i32, x: i32, y: i32, seed: *u64) i32 {
|
||||||
var depth = startingDepth;
|
var depth = startingDepth;
|
||||||
for(self.structure) |blockStack| {
|
for(self.structure) |blockStack| {
|
||||||
const total = blockStack.min + main.random.nextIntBounded(u32, seed, @as(u32, 1) + blockStack.max - blockStack.min);
|
const total = blockStack.min + main.random.nextIntBounded(u32, seed, @as(u32, 1) + blockStack.max - blockStack.min);
|
||||||
@ -225,12 +225,12 @@ pub const BlockStructure = struct {
|
|||||||
if(chunk.liesInChunk(x, y, depth)) {
|
if(chunk.liesInChunk(x, y, depth)) {
|
||||||
chunk.updateBlockInGeneration(x, y, depth, block);
|
chunk.updateBlockInGeneration(x, y, depth, block);
|
||||||
}
|
}
|
||||||
depth -%= chunk.pos.voxelSize;
|
depth -%= chunk.super.pos.voxelSize;
|
||||||
if(depth -% minDepth <= 0)
|
if(depth -% minDepth <= 0)
|
||||||
return depth +% chunk.pos.voxelSize;
|
return depth +% chunk.super.pos.voxelSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return depth +% chunk.pos.voxelSize;
|
return depth +% chunk.super.pos.voxelSize;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,16 +39,16 @@ pub fn deinit() void {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
||||||
if(chunk.pos.voxelSize > 2) return;
|
if(chunk.super.pos.voxelSize > 2) return;
|
||||||
const size = chunk.width;
|
const size = chunk.super.width;
|
||||||
// Generate caves from all nearby chunks:
|
// Generate caves from all nearby chunks:
|
||||||
var x = chunk.pos.wx -% main.chunk.chunkSize;
|
var x = chunk.super.pos.wx -% main.chunk.chunkSize;
|
||||||
while(x != chunk.pos.wx +% size +% main.chunk.chunkSize) : (x +%= main.chunk.chunkSize) {
|
while(x != chunk.super.pos.wx +% size +% main.chunk.chunkSize) : (x +%= main.chunk.chunkSize) {
|
||||||
var y = chunk.pos.wy -% main.chunk.chunkSize;
|
var y = chunk.super.pos.wy -% main.chunk.chunkSize;
|
||||||
while(y != chunk.pos.wy +% size +% main.chunk.chunkSize) : (y +%= main.chunk.chunkSize) {
|
while(y != chunk.super.pos.wy +% size +% main.chunk.chunkSize) : (y +%= main.chunk.chunkSize) {
|
||||||
var z = chunk.pos.wz -% main.chunk.chunkSize;
|
var z = chunk.super.pos.wz -% main.chunk.chunkSize;
|
||||||
while(z != chunk.pos.wz +% size +% main.chunk.chunkSize) : (z +%= main.chunk.chunkSize) {
|
while(z != chunk.super.pos.wz +% size +% main.chunk.chunkSize) : (z +%= main.chunk.chunkSize) {
|
||||||
var seed = random.initSeed3D(worldSeed, .{x, y, z});
|
var seed = random.initSeed3D(worldSeed, .{x, y, z});
|
||||||
considerCoordinates(x, y, z, chunk, caveMap, biomeMap, &seed);
|
considerCoordinates(x, y, z, chunk, caveMap, biomeMap, &seed);
|
||||||
}
|
}
|
||||||
@ -60,10 +60,10 @@ fn distSqr(x: f32, y: f32, z: f32) f32 {
|
|||||||
return x*x + y*y + z*z;
|
return x*x + y*y + z*z;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn considerCrystal(x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, seed: *u64, useNeedles: bool, types: []u16) void {
|
fn considerCrystal(x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, seed: *u64, useNeedles: bool, types: []u16) void {
|
||||||
const relX: f32 = @floatFromInt(x -% chunk.pos.wx);
|
const relX: f32 = @floatFromInt(x -% chunk.super.pos.wx);
|
||||||
const relY: f32 = @floatFromInt(y -% chunk.pos.wy);
|
const relY: f32 = @floatFromInt(y -% chunk.super.pos.wy);
|
||||||
const relZ: f32 = @floatFromInt(z -% chunk.pos.wz);
|
const relZ: f32 = @floatFromInt(z -% chunk.super.pos.wz);
|
||||||
const typ = types[random.nextIntBounded(u32, seed, @as(u32, @intCast(types.len)))];
|
const typ = types[random.nextIntBounded(u32, seed, @as(u32, @intCast(types.len)))];
|
||||||
// Make some crystal spikes in random directions:
|
// Make some crystal spikes in random directions:
|
||||||
var spikes: f32 = 4;
|
var spikes: f32 = 4;
|
||||||
@ -102,7 +102,7 @@ fn considerCrystal(x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, seed: *u64,
|
|||||||
while(z3 <= zMax) : (z3 += 1) {
|
while(z3 <= zMax) : (z3 += 1) {
|
||||||
const dist = distSqr(@as(f32, @floatFromInt(x3)) - x2, @as(f32, @floatFromInt(y3)) - y2, @as(f32, @floatFromInt(z3)) - z2);
|
const dist = distSqr(@as(f32, @floatFromInt(x3)) - x2, @as(f32, @floatFromInt(y3)) - y2, @as(f32, @floatFromInt(z3)) - z2);
|
||||||
if(dist < size*size) {
|
if(dist < size*size) {
|
||||||
if(x3 >= 0 and x3 < chunk.width and y3 >= 0 and y3 < chunk.width and z3 >= 0 and z3 < chunk.width) {
|
if(x3 >= 0 and x3 < chunk.super.width and y3 >= 0 and y3 < chunk.super.width and z3 >= 0 and z3 < chunk.super.width) {
|
||||||
const block: main.blocks.Block = chunk.getBlock(x3, y3, z3);
|
const block: main.blocks.Block = chunk.getBlock(x3, y3, z3);
|
||||||
if(block.typ == 0 or block.degradable() or block.blockClass() == .fluid) {
|
if(block.typ == 0 or block.degradable() or block.blockClass() == .fluid) {
|
||||||
chunk.updateBlockInGeneration(x3, y3, z3, .{.typ = typ, .data = 0}); // TODO: Use natural standard.
|
chunk.updateBlockInGeneration(x3, y3, z3, .{.typ = typ, .data = 0}); // TODO: Use natural standard.
|
||||||
@ -119,9 +119,9 @@ fn considerCrystal(x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, seed: *u64,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn considerCoordinates(x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView, seed: *u64) void {
|
fn considerCoordinates(x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView, seed: *u64) void {
|
||||||
const oldSeed = seed.*;
|
const oldSeed = seed.*;
|
||||||
const crystalSpawns = biomeMap.getBiomeAndSeed(x +% main.chunk.chunkSize/2 -% chunk.pos.wx, y +% main.chunk.chunkSize/2 -% chunk.pos.wy, z +% main.chunk.chunkSize/2 -% chunk.pos.wz, true, seed).crystals;
|
const crystalSpawns = biomeMap.getBiomeAndSeed(x +% main.chunk.chunkSize/2 -% chunk.super.pos.wx, y +% main.chunk.chunkSize/2 -% chunk.super.pos.wy, z +% main.chunk.chunkSize/2 -% chunk.super.pos.wz, true, seed).crystals;
|
||||||
random.scrambleSeed(seed);
|
random.scrambleSeed(seed);
|
||||||
var differendColors: u32 = 1;
|
var differendColors: u32 = 1;
|
||||||
if(random.nextInt(u1, seed) != 0) {
|
if(random.nextInt(u1, seed) != 0) {
|
||||||
@ -143,9 +143,9 @@ fn considerCoordinates(x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap
|
|||||||
const worldX = x + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
const worldX = x + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
||||||
const worldY = y + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
const worldY = y + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
||||||
const worldZ = z + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
const worldZ = z + random.nextIntBounded(u31, seed, main.chunk.chunkSize);
|
||||||
const relX = worldX -% chunk.pos.wx;
|
const relX = worldX -% chunk.super.pos.wx;
|
||||||
const relY = worldY -% chunk.pos.wy;
|
const relY = worldY -% chunk.super.pos.wy;
|
||||||
const relZ = worldZ -% chunk.pos.wz;
|
const relZ = worldZ -% chunk.super.pos.wz;
|
||||||
if(caveMap.isSolid(relX, relY, relZ)) { // Only start crystal in solid blocks
|
if(caveMap.isSolid(relX, relY, relZ)) { // Only start crystal in solid blocks
|
||||||
// Only start crystal when they are close to the surface (±SURFACE_DIST blocks)
|
// Only start crystal when they are close to the surface (±SURFACE_DIST blocks)
|
||||||
if(
|
if(
|
||||||
|
@ -32,13 +32,13 @@ pub fn deinit() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Works basically similar to cave generation, but considers a lot less chunks and has a few other differences.
|
// Works basically similar to cave generation, but considers a lot less chunks and has a few other differences.
|
||||||
pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
||||||
_ = caveMap;
|
_ = caveMap;
|
||||||
_ = biomeMap;
|
_ = biomeMap;
|
||||||
if(chunk.pos.voxelSize != 1) return;
|
if(chunk.super.pos.voxelSize != 1) return;
|
||||||
const cx = chunk.pos.wx >> main.chunk.chunkShift;
|
const cx = chunk.super.pos.wx >> main.chunk.chunkShift;
|
||||||
const cy = chunk.pos.wy >> main.chunk.chunkShift;
|
const cy = chunk.super.pos.wy >> main.chunk.chunkShift;
|
||||||
const cz = chunk.pos.wz >> main.chunk.chunkShift;
|
const cz = chunk.super.pos.wz >> main.chunk.chunkShift;
|
||||||
// Generate caves from all nearby chunks:
|
// Generate caves from all nearby chunks:
|
||||||
var x = cx - 1;
|
var x = cx - 1;
|
||||||
while(x < cx + 1) : (x +%= 1) {
|
while(x < cx + 1) : (x +%= 1) {
|
||||||
@ -59,7 +59,7 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn considerCoordinates(ore: *const main.blocks.Ore, relX: f32, relY: f32, relZ: f32, chunk: *main.chunk.Chunk, startSeed: u64) void {
|
fn considerCoordinates(ore: *const main.blocks.Ore, relX: f32, relY: f32, relZ: f32, chunk: *main.chunk.ServerChunk, startSeed: u64) void {
|
||||||
const chunkSizeFloat: f32 = @floatFromInt(main.chunk.chunkSize);
|
const chunkSizeFloat: f32 = @floatFromInt(main.chunk.chunkSize);
|
||||||
// Compose the seeds from some random stats of the ore. They generally shouldn't be the same for two different ores. TODO: Give each block a hash function (id based) that can be used in cases like this.
|
// Compose the seeds from some random stats of the ore. They generally shouldn't be the same for two different ores. TODO: Give each block a hash function (id based) that can be used in cases like this.
|
||||||
var seed = startSeed ^ @as(u32, @bitCast(ore.maxHeight)) ^ @as(u32, @bitCast(ore.size)) ^ @as(u32, @bitCast(main.blocks.Block.hardness(.{.typ = ore.blockType, .data = 0})));
|
var seed = startSeed ^ @as(u32, @bitCast(ore.maxHeight)) ^ @as(u32, @bitCast(ore.size)) ^ @as(u32, @bitCast(main.blocks.Block.hardness(.{.typ = ore.blockType, .data = 0})));
|
||||||
@ -80,9 +80,9 @@ fn considerCoordinates(ore: *const main.blocks.Ore, relX: f32, relY: f32, relZ:
|
|||||||
var yMin: i32 = @intFromFloat(veinRelY - radius);
|
var yMin: i32 = @intFromFloat(veinRelY - radius);
|
||||||
var yMax: i32 = @intFromFloat(@ceil(veinRelY + radius));
|
var yMax: i32 = @intFromFloat(@ceil(veinRelY + radius));
|
||||||
xMin = @max(xMin, 0);
|
xMin = @max(xMin, 0);
|
||||||
xMax = @min(xMax, chunk.width);
|
xMax = @min(xMax, chunk.super.width);
|
||||||
yMin = @max(yMin, 0);
|
yMin = @max(yMin, 0);
|
||||||
yMax = @min(yMax, chunk.width);
|
yMax = @min(yMax, chunk.super.width);
|
||||||
|
|
||||||
var veinSeed = random.nextInt(u64, &seed);
|
var veinSeed = random.nextInt(u64, &seed);
|
||||||
var curX = xMin;
|
var curX = xMin;
|
||||||
@ -97,7 +97,7 @@ fn considerCoordinates(ore: *const main.blocks.Ore, relX: f32, relY: f32, relZ:
|
|||||||
var zMin: i32 = @intFromFloat(veinRelZ - zDistance);
|
var zMin: i32 = @intFromFloat(veinRelZ - zDistance);
|
||||||
var zMax: i32 = @intFromFloat(@ceil(veinRelZ + zDistance));
|
var zMax: i32 = @intFromFloat(@ceil(veinRelZ + zDistance));
|
||||||
zMin = @max(zMin, 0);
|
zMin = @max(zMin, 0);
|
||||||
zMax = @min(zMax, chunk.width);
|
zMax = @min(zMax, chunk.super.width);
|
||||||
var curZ = zMin;
|
var curZ = zMin;
|
||||||
while(curZ < zMax) : (curZ += 1) {
|
while(curZ < zMax) : (curZ += 1) {
|
||||||
const distToCenterZ = (@as(f32, @floatFromInt(curZ)) - veinRelZ)/radius;
|
const distToCenterZ = (@as(f32, @floatFromInt(curZ)) - veinRelZ)/radius;
|
||||||
|
@ -27,26 +27,26 @@ pub fn deinit() void {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
||||||
if(chunk.pos.voxelSize < 4) {
|
if(chunk.super.pos.voxelSize < 4) {
|
||||||
// Uses a blue noise pattern for all structure that shouldn't touch.
|
// Uses a blue noise pattern for all structure that shouldn't touch.
|
||||||
const blueNoise = noise.BlueNoise.getRegionData(main.stackAllocator, chunk.pos.wx -% 8, chunk.pos.wy -% 8, chunk.width + 16, chunk.width + 16);
|
const blueNoise = noise.BlueNoise.getRegionData(main.stackAllocator, chunk.super.pos.wx -% 8, chunk.super.pos.wy -% 8, chunk.super.width + 16, chunk.super.width + 16);
|
||||||
defer main.stackAllocator.free(blueNoise);
|
defer main.stackAllocator.free(blueNoise);
|
||||||
for(blueNoise) |coordinatePair| {
|
for(blueNoise) |coordinatePair| {
|
||||||
const px = @as(i32, @intCast(coordinatePair >> 16)) - 8; // TODO: Maybe add a blue-noise iterator or something like that?
|
const px = @as(i32, @intCast(coordinatePair >> 16)) - 8; // TODO: Maybe add a blue-noise iterator or something like that?
|
||||||
const py = @as(i32, @intCast(coordinatePair & 0xffff)) - 8;
|
const py = @as(i32, @intCast(coordinatePair & 0xffff)) - 8;
|
||||||
const wpx = chunk.pos.wx +% px;
|
const wpx = chunk.super.pos.wx +% px;
|
||||||
const wpy = chunk.pos.wy +% py;
|
const wpy = chunk.super.pos.wy +% py;
|
||||||
|
|
||||||
var pz : i32 = -32;
|
var pz : i32 = -32;
|
||||||
while(pz < chunk.width) : (pz += 32) {
|
while(pz < chunk.super.width) : (pz += 32) {
|
||||||
const wpz = chunk.pos.wz +% pz;
|
const wpz = chunk.super.pos.wz +% pz;
|
||||||
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, wpz});
|
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, wpz});
|
||||||
var relZ = pz + 16;
|
var relZ = pz + 16;
|
||||||
if(caveMap.isSolid(px, py, relZ)) {
|
if(caveMap.isSolid(px, py, relZ)) {
|
||||||
relZ = caveMap.findTerrainChangeAbove(px, py, relZ);
|
relZ = caveMap.findTerrainChangeAbove(px, py, relZ);
|
||||||
} else {
|
} else {
|
||||||
relZ = caveMap.findTerrainChangeBelow(px, py, relZ) + chunk.pos.voxelSize;
|
relZ = caveMap.findTerrainChangeBelow(px, py, relZ) + chunk.super.pos.voxelSize;
|
||||||
}
|
}
|
||||||
if(relZ < pz or relZ >= pz + 32) continue;
|
if(relZ < pz or relZ >= pz + 32) continue;
|
||||||
const biome = biomeMap.getBiome(px, py, relZ);
|
const biome = biomeMap.getBiome(px, py, relZ);
|
||||||
@ -65,14 +65,14 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveM
|
|||||||
}
|
}
|
||||||
} else { // TODO: Make this case work with cave-structures. Low priority because caves aren't even generated this far out.
|
} else { // TODO: Make this case work with cave-structures. Low priority because caves aren't even generated this far out.
|
||||||
var px: i32 = 0;
|
var px: i32 = 0;
|
||||||
while(px < chunk.width + 16) : (px += chunk.pos.voxelSize) {
|
while(px < chunk.super.width + 16) : (px += chunk.super.pos.voxelSize) {
|
||||||
var py: i32 = 0;
|
var py: i32 = 0;
|
||||||
while(py < chunk.width + 16) : (py += chunk.pos.voxelSize) {
|
while(py < chunk.super.width + 16) : (py += chunk.super.pos.voxelSize) {
|
||||||
const wpx = px -% 8 +% chunk.pos.wx;
|
const wpx = px -% 8 +% chunk.super.pos.wx;
|
||||||
const wpy = py -% 8 +% chunk.pos.wy;
|
const wpy = py -% 8 +% chunk.super.pos.wy;
|
||||||
|
|
||||||
const relZ = @as(i32, @intFromFloat(biomeMap.getSurfaceHeight(wpx, wpy))) -% chunk.pos.wz;
|
const relZ = @as(i32, @intFromFloat(biomeMap.getSurfaceHeight(wpx, wpy))) -% chunk.super.pos.wz;
|
||||||
if(relZ < -32 or relZ >= chunk.width + 32) continue;
|
if(relZ < -32 or relZ >= chunk.super.width + 32) continue;
|
||||||
|
|
||||||
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, relZ});
|
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, relZ});
|
||||||
var randomValue = random.nextFloat(&seed);
|
var randomValue = random.nextFloat(&seed);
|
||||||
@ -80,7 +80,7 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveM
|
|||||||
for(biome.vegetationModels) |model| { // TODO: Could probably use an alias table here.
|
for(biome.vegetationModels) |model| { // TODO: Could probably use an alias table here.
|
||||||
var adaptedChance = model.chance;
|
var adaptedChance = model.chance;
|
||||||
// Increase chance if there are less spawn points considered. Messes up positions, but at that distance density matters more.
|
// Increase chance if there are less spawn points considered. Messes up positions, but at that distance density matters more.
|
||||||
adaptedChance = 1 - std.math.pow(f32, 1 - adaptedChance, @as(f32, @floatFromInt(chunk.pos.voxelSize*chunk.pos.voxelSize)));
|
adaptedChance = 1 - std.math.pow(f32, 1 - adaptedChance, @as(f32, @floatFromInt(chunk.super.pos.voxelSize*chunk.super.pos.voxelSize)));
|
||||||
if(randomValue < adaptedChance) {
|
if(randomValue < adaptedChance) {
|
||||||
model.generate(px - 8, py - 8, relZ, chunk, caveMap, &seed);
|
model.generate(px - 8, py - 8, relZ, chunk, caveMap, &seed);
|
||||||
break;
|
break;
|
||||||
|
@ -29,31 +29,31 @@ pub fn deinit() void {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(worldSeed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
|
||||||
const voxelSizeShift = @ctz(chunk.pos.voxelSize);
|
const voxelSizeShift = @ctz(chunk.super.pos.voxelSize);
|
||||||
var x: u31 = 0;
|
var x: u31 = 0;
|
||||||
while(x < chunk.width) : (x += chunk.pos.voxelSize) {
|
while(x < chunk.super.width) : (x += chunk.super.pos.voxelSize) {
|
||||||
var y: u31 = 0;
|
var y: u31 = 0;
|
||||||
while(y < chunk.width) : (y += chunk.pos.voxelSize) {
|
while(y < chunk.super.width) : (y += chunk.super.pos.voxelSize) {
|
||||||
const heightData = caveMap.getHeightData(x, y);
|
const heightData = caveMap.getHeightData(x, y);
|
||||||
var makeSurfaceStructure = true;
|
var makeSurfaceStructure = true;
|
||||||
var z: i32 = chunk.width - chunk.pos.voxelSize;
|
var z: i32 = chunk.super.width - chunk.super.pos.voxelSize;
|
||||||
while(z >= 0) : (z -= chunk.pos.voxelSize) {
|
while(z >= 0) : (z -= chunk.super.pos.voxelSize) {
|
||||||
const mask = @as(u64, 1) << @intCast(z >> voxelSizeShift);
|
const mask = @as(u64, 1) << @intCast(z >> voxelSizeShift);
|
||||||
if(heightData & mask != 0) {
|
if(heightData & mask != 0) {
|
||||||
const biome = biomeMap.getBiome(x, y, z);
|
const biome = biomeMap.getBiome(x, y, z);
|
||||||
|
|
||||||
if(makeSurfaceStructure) {
|
if(makeSurfaceStructure) {
|
||||||
const surfaceBlock = caveMap.findTerrainChangeAbove(x, y, z) - chunk.pos.voxelSize;
|
const surfaceBlock = caveMap.findTerrainChangeAbove(x, y, z) - chunk.super.pos.voxelSize;
|
||||||
var seed: u64 = random.initSeed3D(worldSeed, .{chunk.pos.wx + x, chunk.pos.wy + y, chunk.pos.wz + z});
|
var seed: u64 = random.initSeed3D(worldSeed, .{chunk.super.pos.wx + x, chunk.super.pos.wy + y, chunk.super.pos.wz + z});
|
||||||
// Add the biomes surface structure:
|
// Add the biomes surface structure:
|
||||||
z = @min(z + chunk.pos.voxelSize, biome.structure.addSubTerranian(chunk, surfaceBlock, caveMap.findTerrainChangeBelow(x, y, z), x, y, &seed));
|
z = @min(z + chunk.super.pos.voxelSize, biome.structure.addSubTerranian(chunk, surfaceBlock, caveMap.findTerrainChangeBelow(x, y, z), x, y, &seed));
|
||||||
makeSurfaceStructure = false;
|
makeSurfaceStructure = false;
|
||||||
} else {
|
} else {
|
||||||
chunk.updateBlockInGeneration(x, y, z, .{.typ = biome.stoneBlockType, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockInGeneration(x, y, z, .{.typ = biome.stoneBlockType, .data = 0}); // TODO: Natural standard.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(z + chunk.pos.wz < 0 and z + chunk.pos.wz >= @as(i32, @intFromFloat(biomeMap.getSurfaceHeight(x + chunk.pos.wx, y + chunk.pos.wy))) - (chunk.pos.voxelSize - 1)) {
|
if(z + chunk.super.pos.wz < 0 and z + chunk.super.pos.wz >= @as(i32, @intFromFloat(biomeMap.getSurfaceHeight(x + chunk.super.pos.wx, y + chunk.super.pos.wy))) - (chunk.super.pos.voxelSize - 1)) {
|
||||||
chunk.updateBlockInGeneration(x, y, z, .{.typ = water, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockInGeneration(x, y, z, .{.typ = water, .data = 0}); // TODO: Natural standard.
|
||||||
} else {
|
} else {
|
||||||
chunk.updateBlockInGeneration(x, y, z, .{.typ = 0, .data = 0});
|
chunk.updateBlockInGeneration(x, y, z, .{.typ = 0, .data = 0});
|
||||||
|
@ -29,7 +29,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: JsonElement)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(self: *Boulder, x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
pub fn generate(self: *Boulder, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
||||||
_ = caveMap;
|
_ = caveMap;
|
||||||
const radius = self.size + self.sizeVariation*(random.nextFloat(seed)*2 - 1);
|
const radius = self.size + self.sizeVariation*(random.nextFloat(seed)*2 - 1);
|
||||||
// My basic idea is to use a point cloud and a potential function to achieve somewhat smooth boulders without being a sphere.
|
// My basic idea is to use a point cloud and a potential function to achieve somewhat smooth boulders without being a sphere.
|
||||||
@ -46,11 +46,11 @@ pub fn generate(self: *Boulder, x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk
|
|||||||
// This ensures that the entire boulder is inside of a square with sidelength 2*radius.
|
// This ensures that the entire boulder is inside of a square with sidelength 2*radius.
|
||||||
const maxRadius: i32 = @intFromFloat(@ceil(radius));
|
const maxRadius: i32 = @intFromFloat(@ceil(radius));
|
||||||
var px = chunk.startIndex(x - maxRadius);
|
var px = chunk.startIndex(x - maxRadius);
|
||||||
while(px < x + maxRadius) : (px += chunk.pos.voxelSize) {
|
while(px < x + maxRadius) : (px += chunk.super.pos.voxelSize) {
|
||||||
var py = chunk.startIndex(y - maxRadius);
|
var py = chunk.startIndex(y - maxRadius);
|
||||||
while(py < y + maxRadius) : (py += chunk.pos.voxelSize) {
|
while(py < y + maxRadius) : (py += chunk.super.pos.voxelSize) {
|
||||||
var pz = chunk.startIndex(z - maxRadius);
|
var pz = chunk.startIndex(z - maxRadius);
|
||||||
while(pz < z + maxRadius) : (pz += chunk.pos.voxelSize) {
|
while(pz < z + maxRadius) : (pz += chunk.super.pos.voxelSize) {
|
||||||
if(!chunk.liesInChunk(px, py, pz)) continue;
|
if(!chunk.liesInChunk(px, py, pz)) continue;
|
||||||
var potential: f32 = 0;
|
var potential: f32 = 0;
|
||||||
for(&pointCloud) |point| {
|
for(&pointCloud) |point| {
|
||||||
|
@ -33,7 +33,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: JsonElement)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
||||||
const width = self.width + (random.nextFloat(seed) - 0.5)*self.variation;
|
const width = self.width + (random.nextFloat(seed) - 0.5)*self.variation;
|
||||||
const orientation = 2*std.math.pi*random.nextFloat(seed);
|
const orientation = 2*std.math.pi*random.nextFloat(seed);
|
||||||
const ellipseParam = 1 + random.nextFloat(seed);
|
const ellipseParam = 1 + random.nextFloat(seed);
|
||||||
@ -46,9 +46,9 @@ pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.C
|
|||||||
const ySecn = -ellipseParam*@sin(orientation)/width;
|
const ySecn = -ellipseParam*@sin(orientation)/width;
|
||||||
|
|
||||||
const xMin = @max(0, x - @as(i32, @intFromFloat(@ceil(width))));
|
const xMin = @max(0, x - @as(i32, @intFromFloat(@ceil(width))));
|
||||||
const xMax = @min(chunk.width, x + @as(i32, @intFromFloat(@ceil(width))));
|
const xMax = @min(chunk.super.width, x + @as(i32, @intFromFloat(@ceil(width))));
|
||||||
const yMin = @max(0, y - @as(i32, @intFromFloat(@ceil(width))));
|
const yMin = @max(0, y - @as(i32, @intFromFloat(@ceil(width))));
|
||||||
const yMax = @min(chunk.width, y + @as(i32, @intFromFloat(@ceil(width))));
|
const yMax = @min(chunk.super.width, y + @as(i32, @intFromFloat(@ceil(width))));
|
||||||
|
|
||||||
var px = chunk.startIndex(xMin);
|
var px = chunk.startIndex(xMin);
|
||||||
while(px < xMax) : (px += 1) {
|
while(px < xMax) : (px += 1) {
|
||||||
@ -66,7 +66,7 @@ pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.C
|
|||||||
startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight);
|
startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight);
|
||||||
}
|
}
|
||||||
var pz = chunk.startIndex(startHeight - self.depth + 1);
|
var pz = chunk.startIndex(startHeight - self.depth + 1);
|
||||||
while(pz <= startHeight) : (pz += chunk.pos.voxelSize) {
|
while(pz <= startHeight) : (pz += chunk.super.pos.voxelSize) {
|
||||||
if(dist <= self.smoothness or (dist - self.smoothness)/(1 - self.smoothness) < random.nextFloat(seed)) {
|
if(dist <= self.smoothness or (dist - self.smoothness)/(1 - self.smoothness) < random.nextFloat(seed)) {
|
||||||
if(chunk.liesInChunk(px, py, pz)) {
|
if(chunk.liesInChunk(px, py, pz)) {
|
||||||
chunk.updateBlockInGeneration(px, py, pz, .{.typ = self.blockType, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockInGeneration(px, py, pz, .{.typ = self.blockType, .data = 0}); // TODO: Natural standard.
|
||||||
|
@ -41,10 +41,10 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: JsonElement)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateStem(self: *SimpleTreeModel, x: i32, y: i32, z: i32, height: i32, chunk: *main.chunk.Chunk) void {
|
pub fn generateStem(self: *SimpleTreeModel, x: i32, y: i32, z: i32, height: i32, chunk: *main.chunk.ServerChunk) void {
|
||||||
if(chunk.pos.voxelSize <= 2) {
|
if(chunk.super.pos.voxelSize <= 2) {
|
||||||
var pz: i32 = chunk.startIndex(z);
|
var pz: i32 = chunk.startIndex(z);
|
||||||
while(pz < z + height) : (pz += chunk.pos.voxelSize) {
|
while(pz < z + height) : (pz += chunk.super.pos.voxelSize) {
|
||||||
if(chunk.liesInChunk(x, y, pz)) {
|
if(chunk.liesInChunk(x, y, pz)) {
|
||||||
chunk.updateBlockIfDegradable(x, y, pz, if(pz == z + height-1) .{.typ = self.topWoodBlock, .data = 0} else .{.typ = self.woodBlock, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockIfDegradable(x, y, pz, if(pz == z + height-1) .{.typ = self.topWoodBlock, .data = 0} else .{.typ = self.woodBlock, .data = 0}); // TODO: Natural standard.
|
||||||
}
|
}
|
||||||
@ -52,21 +52,21 @@ pub fn generateStem(self: *SimpleTreeModel, x: i32, y: i32, z: i32, height: i32,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
||||||
var height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight);
|
var height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight);
|
||||||
|
|
||||||
if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) // Space is too small.Allocator
|
if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) // Space is too small.Allocator
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(z > chunk.width) return;
|
if(z > chunk.super.width) return;
|
||||||
|
|
||||||
if(chunk.pos.voxelSize >= 16) {
|
if(chunk.super.pos.voxelSize >= 16) {
|
||||||
// Ensures that even at lowest resolution some leaves are rendered for smaller trees.
|
// Ensures that even at lowest resolution some leaves are rendered for smaller trees.
|
||||||
if(chunk.liesInChunk(x, y, z)) {
|
if(chunk.liesInChunk(x, y, z)) {
|
||||||
chunk.updateBlockIfDegradable(x, y, z, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard
|
chunk.updateBlockIfDegradable(x, y, z, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard
|
||||||
}
|
}
|
||||||
if(chunk.liesInChunk(x, y, z + chunk.pos.voxelSize)) {
|
if(chunk.liesInChunk(x, y, z + chunk.super.pos.voxelSize)) {
|
||||||
chunk.updateBlockIfDegradable(x, y, z + chunk.pos.voxelSize, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard
|
chunk.updateBlockIfDegradable(x, y, z + chunk.super.pos.voxelSize, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,12 +76,12 @@ pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chu
|
|||||||
// Position of the first block of leaves
|
// Position of the first block of leaves
|
||||||
height = 3*height >> 1;
|
height = 3*height >> 1;
|
||||||
var pz = chunk.startIndex(z + @divTrunc(height, 3));
|
var pz = chunk.startIndex(z + @divTrunc(height, 3));
|
||||||
while(pz < z + height) : (pz += chunk.pos.voxelSize) {
|
while(pz < z + height) : (pz += chunk.super.pos.voxelSize) {
|
||||||
const j = @divFloor(height - (pz - z), 2);
|
const j = @divFloor(height - (pz - z), 2);
|
||||||
var px = chunk.startIndex(x + 1 - j);
|
var px = chunk.startIndex(x + 1 - j);
|
||||||
while(px < x + j) : (px += chunk.pos.voxelSize) {
|
while(px < x + j) : (px += chunk.super.pos.voxelSize) {
|
||||||
var py = chunk.startIndex(y + 1 - j);
|
var py = chunk.startIndex(y + 1 - j);
|
||||||
while(py < y + j) : (py += chunk.pos.voxelSize) {
|
while(py < y + j) : (py += chunk.super.pos.voxelSize) {
|
||||||
if(chunk.liesInChunk(px, py, pz))
|
if(chunk.liesInChunk(px, py, pz))
|
||||||
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
||||||
}
|
}
|
||||||
@ -97,11 +97,11 @@ pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chu
|
|||||||
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
|
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
|
||||||
const center = z + height;
|
const center = z + height;
|
||||||
var pz = chunk.startIndex(center - leafRadius);
|
var pz = chunk.startIndex(center - leafRadius);
|
||||||
while(pz < center + leafRadius) : (pz += chunk.pos.voxelSize) {
|
while(pz < center + leafRadius) : (pz += chunk.super.pos.voxelSize) {
|
||||||
var px = chunk.startIndex(x - leafRadius);
|
var px = chunk.startIndex(x - leafRadius);
|
||||||
while(px < x + leafRadius) : (px += chunk.pos.voxelSize) {
|
while(px < x + leafRadius) : (px += chunk.super.pos.voxelSize) {
|
||||||
var py = chunk.startIndex(y - leafRadius);
|
var py = chunk.startIndex(y - leafRadius);
|
||||||
while(py < y + leafRadius) : (py += chunk.pos.voxelSize) {
|
while(py < y + leafRadius) : (py += chunk.super.pos.voxelSize) {
|
||||||
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
|
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
|
||||||
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
|
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
|
||||||
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
||||||
@ -122,11 +122,11 @@ pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chu
|
|||||||
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
|
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
|
||||||
const center = z + height;
|
const center = z + height;
|
||||||
var pz = chunk.startIndex(center - leafRadius);
|
var pz = chunk.startIndex(center - leafRadius);
|
||||||
while(pz < center + leafRadius) : (pz += chunk.pos.voxelSize) {
|
while(pz < center + leafRadius) : (pz += chunk.super.pos.voxelSize) {
|
||||||
var px = chunk.startIndex(x - leafRadius);
|
var px = chunk.startIndex(x - leafRadius);
|
||||||
while(px < x + leafRadius) : (px += chunk.pos.voxelSize) {
|
while(px < x + leafRadius) : (px += chunk.super.pos.voxelSize) {
|
||||||
var py = chunk.startIndex(y - leafRadius);
|
var py = chunk.startIndex(y - leafRadius);
|
||||||
while(py < y + leafRadius) : (py += chunk.pos.voxelSize) {
|
while(py < y + leafRadius) : (py += chunk.super.pos.voxelSize) {
|
||||||
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
|
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
|
||||||
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
|
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
|
||||||
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
|
||||||
|
@ -29,13 +29,13 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: JsonElement)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(self: *SimpleVegetation, x: i32, y: i32, z: i32, chunk: *main.chunk.Chunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
pub fn generate(self: *SimpleVegetation, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
|
||||||
if(chunk.pos.voxelSize > 2 and (x & chunk.pos.voxelSize-1 != 0 or y & chunk.pos.voxelSize-1 != 0)) return;
|
if(chunk.super.pos.voxelSize > 2 and (x & chunk.super.pos.voxelSize-1 != 0 or y & chunk.super.pos.voxelSize-1 != 0)) return;
|
||||||
if(chunk.liesInChunk(x, y, z)) {
|
if(chunk.liesInChunk(x, y, z)) {
|
||||||
const height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight+1);
|
const height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight+1);
|
||||||
if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) return; // Space is too small.
|
if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) return; // Space is too small.
|
||||||
var pz: i32 = chunk.startIndex(z);
|
var pz: i32 = chunk.startIndex(z);
|
||||||
while(pz < z + height) : (pz += chunk.pos.voxelSize) {
|
while(pz < z + height) : (pz += chunk.super.pos.voxelSize) {
|
||||||
if(chunk.liesInChunk(x, y, pz)) {
|
if(chunk.liesInChunk(x, y, pz)) {
|
||||||
chunk.updateBlockIfDegradable(x, y, pz, .{.typ = self.blockType, .data = 0}); // TODO: Natural standard.
|
chunk.updateBlockIfDegradable(x, y, pz, .{.typ = self.blockType, .data = 0}); // TODO: Natural standard.
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ pub const CaveMap = @import("CaveMap.zig");
|
|||||||
pub const BlockGenerator = struct {
|
pub const BlockGenerator = struct {
|
||||||
init: *const fn(parameters: JsonElement) void,
|
init: *const fn(parameters: JsonElement) void,
|
||||||
deinit: *const fn() void,
|
deinit: *const fn() void,
|
||||||
generate: *const fn(seed: u64, chunk: *main.chunk.Chunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void,
|
generate: *const fn(seed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void,
|
||||||
/// Used to prioritize certain generators over others.
|
/// Used to prioritize certain generators over others.
|
||||||
priority: i32,
|
priority: i32,
|
||||||
/// To avoid duplicate seeds in similar generation algorithms, the SurfaceGenerator xors the world-seed with the generator specific seed.
|
/// To avoid duplicate seeds in similar generation algorithms, the SurfaceGenerator xors the world-seed with the generator specific seed.
|
||||||
|
@ -5,7 +5,7 @@ const Block = main.blocks.Block;
|
|||||||
const Cache = main.utils.Cache;
|
const Cache = main.utils.Cache;
|
||||||
const chunk = main.chunk;
|
const chunk = main.chunk;
|
||||||
const ChunkPosition = chunk.ChunkPosition;
|
const ChunkPosition = chunk.ChunkPosition;
|
||||||
const Chunk = chunk.Chunk;
|
const ServerChunk = chunk.ServerChunk;
|
||||||
const files = main.files;
|
const files = main.files;
|
||||||
const utils = main.utils;
|
const utils = main.utils;
|
||||||
const ItemDropManager = main.itemdrop.ItemDropManager;
|
const ItemDropManager = main.itemdrop.ItemDropManager;
|
||||||
@ -29,7 +29,7 @@ const ChunkManager = struct {
|
|||||||
|
|
||||||
// There will be at most 1 GiB of chunks in here. TODO: Allow configuring this in the server settings.
|
// There will be at most 1 GiB of chunks in here. TODO: Allow configuring this in the server settings.
|
||||||
const reducedChunkCacheMask = 2047;
|
const reducedChunkCacheMask = 2047;
|
||||||
var chunkCache: Cache(Chunk, reducedChunkCacheMask+1, 4, chunkDeinitFunctionForCache) = .{};
|
var chunkCache: Cache(ServerChunk, reducedChunkCacheMask+1, 4, chunkDeinitFunctionForCache) = .{};
|
||||||
|
|
||||||
const ChunkLoadTask = struct {
|
const ChunkLoadTask = struct {
|
||||||
pos: ChunkPosition,
|
pos: ChunkPosition,
|
||||||
@ -191,24 +191,27 @@ const ChunkManager = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunkInitFunctionForCacheAndIncreaseRefCount(pos: ChunkPosition) *Chunk {
|
fn chunkInitFunctionForCacheAndIncreaseRefCount(pos: ChunkPosition) *ServerChunk {
|
||||||
const regionSize = pos.voxelSize*chunk.chunkSize*storage.RegionFile.regionSize;
|
const regionSize = pos.voxelSize*chunk.chunkSize*storage.RegionFile.regionSize;
|
||||||
const regionMask: i32 = regionSize - 1;
|
const regionMask: i32 = regionSize - 1;
|
||||||
const region = storage.loadRegionFileAndIncreaseRefCount(pos.wx & ~regionMask, pos.wy & ~regionMask, pos.wz & ~regionMask, pos.voxelSize);
|
const region = storage.loadRegionFileAndIncreaseRefCount(pos.wx & ~regionMask, pos.wy & ~regionMask, pos.wz & ~regionMask, pos.voxelSize);
|
||||||
defer region.decreaseRefCount();
|
defer region.decreaseRefCount();
|
||||||
|
const ch = ServerChunk.initAndIncreaseRefCount(pos);
|
||||||
|
ch.mutex.lock();
|
||||||
|
defer ch.mutex.unlock();
|
||||||
if(region.getChunk(
|
if(region.getChunk(
|
||||||
main.stackAllocator,
|
main.stackAllocator,
|
||||||
@as(usize, @intCast(pos.wx -% region.pos.wx))/pos.voxelSize/chunk.chunkSize,
|
@as(usize, @intCast(pos.wx -% region.pos.wx))/pos.voxelSize/chunk.chunkSize,
|
||||||
@as(usize, @intCast(pos.wy -% region.pos.wy))/pos.voxelSize/chunk.chunkSize,
|
@as(usize, @intCast(pos.wy -% region.pos.wy))/pos.voxelSize/chunk.chunkSize,
|
||||||
@as(usize, @intCast(pos.wz -% region.pos.wz))/pos.voxelSize/chunk.chunkSize,
|
@as(usize, @intCast(pos.wz -% region.pos.wz))/pos.voxelSize/chunk.chunkSize,
|
||||||
)) |ch| blk: { // Load chunk from file:
|
)) |data| blk: { // Load chunk from file:
|
||||||
defer main.stackAllocator.free(ch);
|
defer main.stackAllocator.free(data);
|
||||||
return storage.ChunkCompression.decompressChunkAndIncreaseRefCount(ch) catch {
|
storage.ChunkCompression.decompressChunk(&ch.super, data) catch {
|
||||||
std.log.err("Storage for chunk {} in region file at {} is corrupted", .{pos, region.pos});
|
std.log.err("Storage for chunk {} in region file at {} is corrupted", .{pos, region.pos});
|
||||||
break :blk;
|
break :blk;
|
||||||
};
|
};
|
||||||
|
return ch;
|
||||||
}
|
}
|
||||||
const ch = Chunk.initAndIncreaseRefCount(pos);
|
|
||||||
ch.generated = true;
|
ch.generated = true;
|
||||||
const caveMap = terrain.CaveMap.CaveMapView.init(ch);
|
const caveMap = terrain.CaveMap.CaveMapView.init(ch);
|
||||||
defer caveMap.deinit();
|
defer caveMap.deinit();
|
||||||
@ -217,24 +220,25 @@ const ChunkManager = struct {
|
|||||||
for(server.world.?.chunkManager.terrainGenerationProfile.generators) |generator| {
|
for(server.world.?.chunkManager.terrainGenerationProfile.generators) |generator| {
|
||||||
generator.generate(server.world.?.seed ^ generator.generatorSeed, ch, caveMap, biomeMap);
|
generator.generate(server.world.?.seed ^ generator.generatorSeed, ch, caveMap, biomeMap);
|
||||||
}
|
}
|
||||||
|
ch.setChanged();
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunkDeinitFunctionForCache(ch: *Chunk) void {
|
fn chunkDeinitFunctionForCache(ch: *ServerChunk) void {
|
||||||
ch.decreaseRefCount();
|
ch.decreaseRefCount();
|
||||||
}
|
}
|
||||||
/// Generates a normal chunk at a given location, or if possible gets it from the cache.
|
/// Generates a normal chunk at a given location, or if possible gets it from the cache.
|
||||||
pub fn getOrGenerateChunkAndIncreaseRefCount(pos: ChunkPosition) *Chunk { // TODO: This is not thread safe! The chunk could get removed from the cache while in use. Reference counting should probably be used here.
|
pub fn getOrGenerateChunkAndIncreaseRefCount(pos: ChunkPosition) *ServerChunk {
|
||||||
const mask = pos.voxelSize*chunk.chunkSize - 1;
|
const mask = pos.voxelSize*chunk.chunkSize - 1;
|
||||||
std.debug.assert(pos.wx & mask == 0 and pos.wy & mask == 0 and pos.wz & mask == 0);
|
std.debug.assert(pos.wx & mask == 0 and pos.wy & mask == 0 and pos.wz & mask == 0);
|
||||||
const result = chunkCache.findOrCreate(pos, chunkInitFunctionForCacheAndIncreaseRefCount, Chunk.increaseRefCount);
|
const result = chunkCache.findOrCreate(pos, chunkInitFunctionForCacheAndIncreaseRefCount, ServerChunk.increaseRefCount);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getChunkFromCacheAndIncreaseRefCount(pos: ChunkPosition) ?*Chunk {
|
pub fn getChunkFromCacheAndIncreaseRefCount(pos: ChunkPosition) ?*ServerChunk {
|
||||||
const mask = pos.voxelSize*chunk.chunkSize - 1;
|
const mask = pos.voxelSize*chunk.chunkSize - 1;
|
||||||
std.debug.assert(pos.wx & mask == 0 and pos.wy & mask == 0 and pos.wz & mask == 0);
|
std.debug.assert(pos.wx & mask == 0 and pos.wy & mask == 0 and pos.wz & mask == 0);
|
||||||
const result = chunkCache.find(pos, Chunk.increaseRefCount) orelse return null;
|
const result = chunkCache.find(pos, ServerChunk.increaseRefCount) orelse return null;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -329,7 +333,7 @@ pub const ServerWorld = struct {
|
|||||||
regionUpdateQueue: main.utils.CircularBufferQueue(RegionUpdateRequest),
|
regionUpdateQueue: main.utils.CircularBufferQueue(RegionUpdateRequest),
|
||||||
|
|
||||||
const ChunkUpdateRequest = struct {
|
const ChunkUpdateRequest = struct {
|
||||||
ch: *Chunk,
|
ch: *ServerChunk,
|
||||||
milliTimeStamp: i64,
|
milliTimeStamp: i64,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -497,12 +501,18 @@ pub const ServerWorld = struct {
|
|||||||
// Stores at least one chunk and one region per iteration.
|
// Stores at least one chunk and one region per iteration.
|
||||||
// All chunks and regions will be stored within the storage time.
|
// All chunks and regions will be stored within the storage time.
|
||||||
const insertionTime = newTime -% main.settings.storageTime;
|
const insertionTime = newTime -% main.settings.storageTime;
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
while(self.chunkUpdateQueue.dequeue()) |updateRequest| {
|
while(self.chunkUpdateQueue.dequeue()) |updateRequest| {
|
||||||
|
self.mutex.unlock();
|
||||||
|
defer self.mutex.lock();
|
||||||
updateRequest.ch.save(self);
|
updateRequest.ch.save(self);
|
||||||
updateRequest.ch.decreaseRefCount();
|
updateRequest.ch.decreaseRefCount();
|
||||||
if(updateRequest.milliTimeStamp -% insertionTime <= 0) break;
|
if(updateRequest.milliTimeStamp -% insertionTime <= 0) break;
|
||||||
}
|
}
|
||||||
while(self.regionUpdateQueue.dequeue()) |updateRequest| {
|
while(self.regionUpdateQueue.dequeue()) |updateRequest| {
|
||||||
|
self.mutex.unlock();
|
||||||
|
defer self.mutex.lock();
|
||||||
updateRequest.region.store();
|
updateRequest.region.store();
|
||||||
updateRequest.region.decreaseRefCount();
|
updateRequest.region.decreaseRefCount();
|
||||||
if(updateRequest.milliTimeStamp -% insertionTime <= 0) break;
|
if(updateRequest.milliTimeStamp -% insertionTime <= 0) break;
|
||||||
@ -523,7 +533,7 @@ pub const ServerWorld = struct {
|
|||||||
self.chunkManager.queueLightMap(pos, source);
|
self.chunkManager.queueLightMap(pos, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getChunk(self: *ServerWorld, x: i32, y: i32, z: i32) ?*Chunk {
|
pub fn getChunk(self: *ServerWorld, x: i32, y: i32, z: i32) ?*ServerChunk {
|
||||||
_ = self;
|
_ = self;
|
||||||
_ = x;
|
_ = x;
|
||||||
_ = y;
|
_ = y;
|
||||||
@ -532,7 +542,7 @@ pub const ServerWorld = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOrGenerateChunkAndIncreaseRefCount(_: *ServerWorld, pos: chunk.ChunkPosition) *Chunk {
|
pub fn getOrGenerateChunkAndIncreaseRefCount(_: *ServerWorld, pos: chunk.ChunkPosition) *ServerChunk {
|
||||||
return ChunkManager.getOrGenerateChunkAndIncreaseRefCount(pos);
|
return ChunkManager.getOrGenerateChunkAndIncreaseRefCount(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,9 +573,9 @@ pub const ServerWorld = struct {
|
|||||||
var ch = baseChunk;
|
var ch = baseChunk;
|
||||||
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) {
|
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) {
|
||||||
ch = ChunkManager.getOrGenerateChunkAndIncreaseRefCount(.{
|
ch = ChunkManager.getOrGenerateChunkAndIncreaseRefCount(.{
|
||||||
.wx = baseChunk.pos.wx + nx & ~@as(i32, chunk.chunkMask),
|
.wx = baseChunk.super.pos.wx + nx & ~@as(i32, chunk.chunkMask),
|
||||||
.wy = baseChunk.pos.wy + ny & ~@as(i32, chunk.chunkMask),
|
.wy = baseChunk.super.pos.wy + ny & ~@as(i32, chunk.chunkMask),
|
||||||
.wz = baseChunk.pos.wz + nz & ~@as(i32, chunk.chunkMask),
|
.wz = baseChunk.super.pos.wz + nz & ~@as(i32, chunk.chunkMask),
|
||||||
.voxelSize = 1,
|
.voxelSize = 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -589,7 +599,7 @@ pub const ServerWorld = struct {
|
|||||||
baseChunk.updateBlockAndSetChanged(x, y, z, newBlock);
|
baseChunk.updateBlockAndSetChanged(x, y, z, newBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queueChunkUpdateAndDecreaseRefCount(self: *ServerWorld, ch: *Chunk) void {
|
pub fn queueChunkUpdateAndDecreaseRefCount(self: *ServerWorld, ch: *ServerChunk) void {
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
self.chunkUpdateQueue.enqueue(.{.ch = ch, .milliTimeStamp = std.time.milliTimestamp()});
|
self.chunkUpdateQueue.enqueue(.{.ch = ch, .milliTimeStamp = std.time.milliTimestamp()});
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
|
@ -1599,14 +1599,14 @@ pub const TimeDifference = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn assertLocked(mutex: *std.Thread.Mutex) void {
|
pub fn assertLocked(mutex: *const std.Thread.Mutex) void {
|
||||||
if(builtin.mode == .Debug) {
|
if(builtin.mode == .Debug) {
|
||||||
std.debug.assert(!mutex.tryLock());
|
std.debug.assert(!@constCast(mutex).tryLock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assertLockedShared(lock: *std.Thread.RwLock) void {
|
pub fn assertLockedShared(lock: *const std.Thread.RwLock) void {
|
||||||
if(builtin.mode == .Debug) {
|
if(builtin.mode == .Debug) {
|
||||||
std.debug.assert(!lock.tryLock());
|
std.debug.assert(!@constCast(lock).tryLock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user