Remove reference counting in terrain generation data structures.

more progress towards #1413
This commit is contained in:
IntegratedQuantum 2025-07-27 10:07:01 +02:00
parent 949900f518
commit 77fb637fe3
12 changed files with 72 additions and 126 deletions

View File

@ -602,8 +602,7 @@ pub const ServerChunk = struct { // MARK: ServerChunk
for(0..2) |dy| {
const mapX = mapStartX +% main.server.terrain.SurfaceMap.MapFragment.mapSize*@as(i32, @intCast(dx));
const mapY = mapStartY +% main.server.terrain.SurfaceMap.MapFragment.mapSize*@as(i32, @intCast(dy));
const map = main.server.terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(mapX, mapY, self.super.pos.voxelSize);
defer map.decreaseRefCount();
const map = main.server.terrain.SurfaceMap.getOrGenerateFragment(mapX, mapY, self.super.pos.voxelSize);
if(!map.wasStored.swap(true, .monotonic)) {
map.save(null, .{});
}

View File

@ -711,7 +711,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
return self;
}
pub fn deinit(self: *ChunkMesh, _: usize) void {
fn privateDeinit(self: *ChunkMesh, _: usize) void {
chunkBuffer.free(self.chunkAllocation);
self.opaqueMesh.deinit();
self.transparentMesh.deinit();
@ -729,6 +729,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
mesh_storage.meshMemoryPool.destroy(self);
}
pub fn deferredDeinit(self: *ChunkMesh) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
pub fn scheduleLightRefresh(pos: chunk.ChunkPosition) void {
LightRefreshTask.schedule(pos);
}

View File

@ -371,10 +371,7 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16) void {
if(oldMesh) |mesh| {
node.finishedMeshing = false;
updateHigherLodNodeFinishedMeshing(mesh.pos, false);
main.heap.GarbageCollection.deferredFree(.{
.ptr = mesh,
.freeFunction = main.utils.castFunctionSelfToAnyopaque(ChunkMesh.deinit),
});
mesh.deferredDeinit();
}
node.isNeighborLod = @splat(false);
}
@ -897,7 +894,7 @@ pub const MeshGenerationTask = struct { // MARK: MeshGenerationTask
defer main.globalAllocator.destroy(self);
const pos = self.mesh.pos;
const mesh = ChunkMesh.init(pos, self.mesh);
mesh.generateLightingData() catch mesh.deinit(undefined);
mesh.generateLightingData() catch mesh.deferredDeinit();
}
pub fn clean(self: *MeshGenerationTask) void {

View File

@ -27,8 +27,7 @@ pub fn execute(args: []const u8, source: *User) void {
var dir: main.chunk.Neighbor = .dirNegX;
var stepsRemaining: usize = 1;
for(0..spiralLen) |_| {
const map = main.server.terrain.ClimateMap.getOrGenerateFragmentAndIncreaseRefCount(wx, wy);
defer map.decreaseRefCount();
const map = main.server.terrain.ClimateMap.getOrGenerateFragment(wx, wy);
for(0..map.map.len) |_| {
const x = main.random.nextIntBounded(u31, &main.seed, map.map.len);
const y = main.random.nextIntBounded(u31, &main.seed, map.map.len);

View File

@ -39,12 +39,12 @@ pub const CaveBiomeMapFragment = struct { // MARK: caveBiomeMapFragment
};
}
fn deinit(self: *CaveBiomeMapFragment, _: usize) void {
fn privateDeinit(self: *CaveBiomeMapFragment, _: usize) void {
memoryPool.destroy(self);
}
pub fn deferredDeinit(self: *CaveBiomeMapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(CaveBiomeMapFragment.deinit)});
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
const rotationMatrixShift = 30;
@ -154,10 +154,10 @@ pub const InterpolatableCaveBiomeMapView = struct { // MARK: InterpolatableCaveB
var result = InterpolatableCaveBiomeMapView{
.fragments = Array3D(*CaveBiomeMapFragment).init(allocator, caveBiomeFragmentWidth, caveBiomeFragmentWidth, caveBiomeFragmentWidth),
.surfaceFragments = [_]*MapFragment{
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(center[0] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(center[0] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(center[0] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(center[0] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragment(center[0] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragment(center[0] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragment(center[0] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] -% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
SurfaceMap.getOrGenerateFragment(center[0] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, center[1] +% SurfaceMap.MapFragment.mapSize/2*pos.voxelSize, pos.voxelSize),
},
.pos = pos,
.width = width,
@ -182,9 +182,6 @@ pub const InterpolatableCaveBiomeMapView = struct { // MARK: InterpolatableCaveB
pub fn deinit(self: InterpolatableCaveBiomeMapView) void {
self.fragments.deinit(self.allocator);
for(self.surfaceFragments) |mapFragment| {
mapFragment.decreaseRefCount();
}
}
fn rotate231(in: Vec3i) Vec3i {

View File

@ -21,7 +21,6 @@ pub const CaveMapFragment = struct { // MARK: CaveMapFragment
data: [width*width]u64 = undefined,
pos: ChunkPosition,
voxelShift: u5,
refCount: Atomic(u16) = .init(0),
pub fn init(self: *CaveMapFragment, wx: i32, wy: i32, wz: i32, voxelSize: u31) void {
self.* = .{
@ -36,6 +35,14 @@ pub const CaveMapFragment = struct { // MARK: CaveMapFragment
@memset(&self.data, std.math.maxInt(u64));
}
fn privateDeinit(self: *CaveMapFragment, _: usize) void {
memoryPool.destroy(self);
}
pub fn deferredDeinit(self: *CaveMapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
fn getIndex(x: i32, y: i32) usize {
std.debug.assert(x >= 0 and x < width and y >= 0 and y < width); // Coordinates out of range.
return @intCast(x*width + y);
@ -50,19 +57,6 @@ pub const CaveMapFragment = struct { // MARK: CaveMapFragment
return maskLower | maskUpper;
}
pub fn increaseRefCount(self: *CaveMapFragment) void {
const prevVal = self.refCount.fetchAdd(1, .monotonic);
std.debug.assert(prevVal != 0);
}
pub fn decreaseRefCount(self: *CaveMapFragment) void {
const prevVal = self.refCount.fetchSub(1, .monotonic);
std.debug.assert(prevVal != 0);
if(prevVal == 1) {
memoryPool.destroy(self);
}
}
pub fn addRange(self: *CaveMapFragment, _relX: i32, _relY: i32, _start: i32, _end: i32) void {
const relX = _relX >> self.voxelShift;
const relY = _relY >> self.voxelShift;
@ -132,30 +126,24 @@ pub const CaveMapView = struct { // MARK: CaveMapView
reference: *ServerChunk,
fragments: [8]*CaveMapFragment,
pub fn init(chunk: *ServerChunk) CaveMapView {
pub fn findMapsAround(chunk: *ServerChunk) CaveMapView {
const pos = chunk.super.pos;
const width = chunk.super.width;
return CaveMapView{
.reference = chunk,
.fragments = [_]*CaveMapFragment{
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragment(pos.wx -% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragment(pos.wx -% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragment(pos.wx -% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragment(pos.wx -% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragment(pos.wx +% width, pos.wy -% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragment(pos.wx +% width, pos.wy -% width, pos.wz +% width, pos.voxelSize),
getOrGenerateFragment(pos.wx +% width, pos.wy +% width, pos.wz -% width, pos.voxelSize),
getOrGenerateFragment(pos.wx +% width, pos.wy +% width, pos.wz +% width, pos.voxelSize),
},
};
}
pub fn deinit(self: CaveMapView) void {
for(self.fragments) |mapFragment| {
mapFragment.decreaseRefCount();
}
}
pub fn isSolid(self: CaveMapView, relX: i32, relY: i32, relZ: i32) bool {
const wx = relX +% self.reference.super.pos.wx;
const wy = relY +% self.reference.super.pos.wy;
@ -289,7 +277,7 @@ pub const CaveMapView = struct { // MARK: CaveMapView
const cacheSize = 1 << 11; // Must be a power of 2!
const cacheMask = cacheSize - 1;
const associativity = 8; // 512 MiB Cache size
var cache: Cache(CaveMapFragment, cacheSize, associativity, CaveMapFragment.decreaseRefCount) = .{};
var cache: Cache(CaveMapFragment, cacheSize, associativity, CaveMapFragment.deferredDeinit) = .{};
var profile: TerrainGenerationProfile = undefined;
var memoryPool: main.heap.MemoryPool(CaveMapFragment) = undefined;
@ -300,7 +288,6 @@ fn cacheInit(pos: ChunkPosition) *CaveMapFragment {
for(profile.caveGenerators) |generator| {
generator.generate(mapFragment, profile.seed ^ generator.generatorSeed);
}
_ = @atomicRmw(u16, &mapFragment.refCount.raw, .Add, 1, .monotonic);
return mapFragment;
}
@ -325,13 +312,13 @@ pub fn deinit() void {
cache.clear();
}
fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) *CaveMapFragment {
fn getOrGenerateFragment(wx: i32, wy: i32, wz: i32, voxelSize: u31) *CaveMapFragment {
const compare = ChunkPosition{
.wx = wx & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize - 1),
.wy = wy & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize - 1),
.wz = wz & ~@as(i32, CaveMapFragment.heightMask*voxelSize | voxelSize - 1),
.voxelSize = voxelSize,
};
const result = cache.findOrCreate(compare, cacheInit, CaveMapFragment.increaseRefCount);
const result = cache.findOrCreate(compare, cacheInit, null);
return result;
}

View File

@ -48,30 +48,23 @@ pub const ClimateMapFragment = struct {
pos: ClimateMapFragmentPosition,
map: [mapEntrysSize][mapEntrysSize]BiomeSample = undefined,
refCount: Atomic(u16) = .init(0),
pub fn init(self: *ClimateMapFragment, wx: i32, wy: i32) void {
self.* = .{
.pos = .{.wx = wx, .wy = wy},
};
}
fn privateDeinit(self: *ClimateMapFragment, _: usize) void {
memoryPool.destroy(self);
}
pub fn deferredDeinit(self: *ClimateMapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
pub fn hashCode(wx: i32, wy: i32) u32 {
return @bitCast((wx >> mapShift)*%33 + (wy >> mapShift));
}
pub fn increaseRefCount(self: *ClimateMapFragment) void {
const prevVal = self.refCount.fetchAdd(1, .monotonic);
std.debug.assert(prevVal != 0);
}
pub fn decreaseRefCount(self: *ClimateMapFragment) void {
const prevVal = self.refCount.fetchSub(1, .monotonic);
std.debug.assert(prevVal != 0);
if(prevVal == 1) {
memoryPool.destroy(self);
}
}
};
/// Generates the climate(aka Biome) map, which is a rough representation of the world.
@ -102,7 +95,7 @@ pub const ClimateMapGenerator = struct {
const cacheSize = 1 << 5; // Must be a power of 2!
const cacheMask = cacheSize - 1;
const associativity = 8; // ~400 MiB
var cache: Cache(ClimateMapFragment, cacheSize, associativity, ClimateMapFragment.decreaseRefCount) = .{};
var cache: Cache(ClimateMapFragment, cacheSize, associativity, ClimateMapFragment.deferredDeinit) = .{};
var profile: TerrainGenerationProfile = undefined;
var memoryPool: main.heap.MemoryPool(ClimateMapFragment) = undefined;
@ -124,7 +117,6 @@ fn cacheInit(pos: ClimateMapFragmentPosition) *ClimateMapFragment {
const mapFragment = memoryPool.create();
mapFragment.init(pos.wx, pos.wy);
profile.climateGenerator.generateMapFragment(mapFragment, profile.seed);
_ = @atomicRmw(u16, &mapFragment.refCount.raw, .Add, 1, .monotonic);
return mapFragment;
}
@ -136,9 +128,9 @@ pub fn deinit() void {
cache.clear();
}
pub fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32) *ClimateMapFragment {
pub fn getOrGenerateFragment(wx: i32, wy: i32) *ClimateMapFragment {
const compare = ClimateMapFragmentPosition{.wx = wx, .wy = wy};
const result = cache.findOrCreate(compare, cacheInit, ClimateMapFragment.increaseRefCount);
const result = cache.findOrCreate(compare, cacheInit, null);
return result;
}
@ -152,8 +144,7 @@ pub fn getBiomeMap(allocator: NeverFailingAllocator, wx: i32, wy: i32, width: u3
while(wxEnd -% x >= 0) : (x +%= ClimateMapFragment.mapSize) {
var y = wzStart;
while(wzEnd -% y >= 0) : (y +%= ClimateMapFragment.mapSize) {
const mapPiece = getOrGenerateFragmentAndIncreaseRefCount(x, y);
defer mapPiece.decreaseRefCount();
const mapPiece = getOrGenerateFragment(x, y);
// Offset of the indices in the result map:
const xOffset = (x -% wx) >> MapFragment.biomeShift;
const yOffset = (y -% wy) >> MapFragment.biomeShift;

View File

@ -26,12 +26,12 @@ pub const LightMapFragment = struct {
};
}
fn deinit(self: *const LightMapFragment, _: usize) void {
fn privateDeinit(self: *const LightMapFragment, _: usize) void {
main.globalAllocator.destroy(self);
}
pub fn deferredDeinit(self: *LightMapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(LightMapFragment.deinit)});
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
pub fn getHeight(self: *LightMapFragment, wx: i32, wy: i32) i32 {
@ -49,8 +49,7 @@ var cache: Cache(LightMapFragment, cacheSize, associativity, LightMapFragment.de
fn cacheInit(pos: MapFragmentPosition) *LightMapFragment {
const mapFragment = main.globalAllocator.create(LightMapFragment);
mapFragment.init(pos.wx, pos.wy, pos.voxelSize);
const surfaceMap = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx, pos.wy, pos.voxelSize);
defer surfaceMap.decreaseRefCount();
const surfaceMap = terrain.SurfaceMap.getOrGenerateFragment(pos.wx, pos.wy, pos.voxelSize);
comptime std.debug.assert(LightMapFragment.mapSize == terrain.SurfaceMap.MapFragment.mapSize);
for(0..LightMapFragment.mapSize) |x| {
for(0..LightMapFragment.mapSize) |y| {

View File

@ -40,7 +40,6 @@ pub const StructureMapFragment = struct {
pos: ChunkPosition,
voxelShift: u5,
refCount: Atomic(u16) = .init(0),
arena: main.heap.NeverFailingArenaAllocator,
allocator: main.heap.NeverFailingAllocator,
@ -68,11 +67,15 @@ pub const StructureMapFragment = struct {
@memset(self.tempData.lists, .{});
}
pub fn deinit(self: *StructureMapFragment) void {
fn privateDeinit(self: *StructureMapFragment, _: usize) void {
self.arena.deinit();
memoryPool.destroy(self);
}
pub fn deferredDeinit(self: *StructureMapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
fn finishGeneration(self: *StructureMapFragment) void {
for(0..self.data.len) |i| {
std.sort.insertion(Structure, self.tempData.lists[i].items, {}, Structure.lessThan);
@ -93,19 +96,6 @@ pub const StructureMapFragment = struct {
return @intCast(((x >> main.chunk.chunkShift + self.voxelShift)*chunkedSize + (y >> main.chunk.chunkShift + self.voxelShift))*chunkedSize + (z >> main.chunk.chunkShift + self.voxelShift));
}
pub fn increaseRefCount(self: *StructureMapFragment) void {
const prevVal = self.refCount.fetchAdd(1, .monotonic);
std.debug.assert(prevVal != 0);
}
pub fn decreaseRefCount(self: *StructureMapFragment) void {
const prevVal = self.refCount.fetchSub(1, .monotonic);
std.debug.assert(prevVal != 0);
if(prevVal == 1) {
self.deinit();
}
}
pub fn generateStructuresInChunk(self: *const StructureMapFragment, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView) void {
const index = self.getIndex(chunk.super.pos.wx - self.pos.wx, chunk.super.pos.wy - self.pos.wy, chunk.super.pos.wz - self.pos.wz);
for(self.data[index]) |structure| {
@ -175,7 +165,7 @@ pub const StructureMapGenerator = struct {
const cacheSize = 1 << 10; // Must be a power of 2!
const cacheMask = cacheSize - 1;
const associativity = 8;
var cache: Cache(StructureMapFragment, cacheSize, associativity, StructureMapFragment.decreaseRefCount) = .{};
var cache: Cache(StructureMapFragment, cacheSize, associativity, StructureMapFragment.deferredDeinit) = .{};
var profile: TerrainGenerationProfile = undefined;
var memoryPool: main.heap.MemoryPool(StructureMapFragment) = undefined;
@ -187,7 +177,6 @@ fn cacheInit(pos: ChunkPosition) *StructureMapFragment {
generator.generate(mapFragment, profile.seed ^ generator.generatorSeed);
}
mapFragment.finishGeneration();
_ = @atomicRmw(u16, &mapFragment.refCount.raw, .Add, 1, .monotonic);
return mapFragment;
}
@ -212,13 +201,13 @@ pub fn deinit() void {
cache.clear();
}
pub fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) *StructureMapFragment {
pub fn getOrGenerateFragment(wx: i32, wy: i32, wz: i32, voxelSize: u31) *StructureMapFragment {
const compare = ChunkPosition{
.wx = wx & ~@as(i32, StructureMapFragment.sizeMask*voxelSize | voxelSize - 1),
.wy = wy & ~@as(i32, StructureMapFragment.sizeMask*voxelSize | voxelSize - 1),
.wz = wz & ~@as(i32, StructureMapFragment.sizeMask*voxelSize | voxelSize - 1),
.voxelSize = voxelSize,
};
const result = cache.findOrCreate(compare, cacheInit, StructureMapFragment.increaseRefCount);
const result = cache.findOrCreate(compare, cacheInit, null);
return result;
}

View File

@ -74,25 +74,18 @@ pub const MapFragment = struct { // MARK: MapFragment
wasStored: Atomic(bool) = .init(false),
refCount: Atomic(u16) = .init(0),
pub fn init(self: *MapFragment, wx: i32, wy: i32, voxelSize: u31) void {
self.* = .{
.pos = MapFragmentPosition.init(wx, wy, voxelSize),
};
}
pub fn increaseRefCount(self: *MapFragment) void {
const prevVal = self.refCount.fetchAdd(1, .monotonic);
std.debug.assert(prevVal != 0);
fn privateDeinit(self: *MapFragment, _: usize) void {
memoryPool.destroy(self);
}
pub fn decreaseRefCount(self: *MapFragment) void {
const prevVal = self.refCount.fetchSub(1, .monotonic);
std.debug.assert(prevVal != 0);
if(prevVal == 1) {
memoryPool.destroy(self);
}
pub fn deferredDeinit(self: *MapFragment) void {
main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(privateDeinit)});
}
pub fn getBiome(self: *MapFragment, wx: i32, wy: i32) *const Biome {
@ -254,7 +247,7 @@ pub const MapGenerator = struct {
const cacheSize = 1 << 6; // Must be a power of 2!
const cacheMask = cacheSize - 1;
const associativity = 8; // ~400MiB MiB Cache size
var cache: Cache(MapFragment, cacheSize, associativity, MapFragment.decreaseRefCount) = .{};
var cache: Cache(MapFragment, cacheSize, associativity, MapFragment.deferredDeinit) = .{};
var profile: TerrainGenerationProfile = undefined;
var memoryPool: main.heap.MemoryPool(MapFragment) = undefined;
@ -278,7 +271,6 @@ fn cacheInit(pos: MapFragmentPosition) *MapFragment {
_ = mapFragment.load(main.server.world.?.biomePalette, null) catch {
profile.mapFragmentGenerator.generateMapFragment(mapFragment, profile.seed);
};
_ = @atomicRmw(u16, &mapFragment.refCount.raw, .Add, 1, .monotonic);
return mapFragment;
}
@ -577,7 +569,6 @@ pub fn regenerateLOD(worldName: []const u8) !void { // MARK: regenerateLOD()
mapFragment.save(&originalHeightMap, neighborInfo); // Store the interpolated map
// Generate LODs
var cur = mapFragment;
defer if(cur.pos.voxelSize != 1) cur.decreaseRefCount();
while(cur.pos.voxelSizeShift < main.settings.highestSupportedLod) {
var nextPos = cur.pos;
nextPos.voxelSize *= 2;
@ -585,7 +576,7 @@ pub fn regenerateLOD(worldName: []const u8) !void { // MARK: regenerateLOD()
const nextMask = ~@as(i32, nextPos.voxelSize*MapFragment.mapSize - 1);
nextPos.wx &= nextMask;
nextPos.wy &= nextMask;
const next = getOrGenerateFragmentAndIncreaseRefCount(nextPos.wx, nextPos.wy, nextPos.voxelSize);
const next = getOrGenerateFragment(nextPos.wx, nextPos.wy, nextPos.voxelSize);
const offSetX: usize = @intCast((cur.pos.wx -% nextPos.wx) >> nextPos.voxelSizeShift);
const offSetY: usize = @intCast((cur.pos.wy -% nextPos.wy) >> nextPos.voxelSizeShift);
for(0..MapFragment.mapSize/2) |x| {
@ -627,7 +618,6 @@ pub fn regenerateLOD(worldName: []const u8) !void { // MARK: regenerateLOD()
}
next.save(null, .{});
next.wasStored.store(true, .monotonic);
if(cur.pos.voxelSize != 1) cur.decreaseRefCount();
cur = next;
}
}
@ -643,12 +633,12 @@ pub fn deinit() void {
}
/// Call deinit on the result.
pub fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, voxelSize: u31) *MapFragment {
pub fn getOrGenerateFragment(wx: i32, wy: i32, voxelSize: u31) *MapFragment {
const compare = MapFragmentPosition.init(
wx & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize - 1),
wy & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize - 1),
voxelSize,
);
const result = cache.findOrCreate(compare, cacheInit, MapFragment.increaseRefCount);
const result = cache.findOrCreate(compare, cacheInit, null);
return result;
}

View File

@ -26,7 +26,6 @@ pub fn init(parameters: ZonElement) void {
pub fn deinit() void {}
pub fn generate(_: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
const structureMap = terrain.StructureMap.getOrGenerateFragmentAndIncreaseRefCount(chunk.super.pos.wx, chunk.super.pos.wy, chunk.super.pos.wz, chunk.super.pos.voxelSize);
defer structureMap.decreaseRefCount();
const structureMap = terrain.StructureMap.getOrGenerateFragment(chunk.super.pos.wx, chunk.super.pos.wy, chunk.super.pos.wz, chunk.super.pos.voxelSize);
structureMap.generateStructuresInChunk(chunk, caveMap, biomeMap);
}

View File

@ -321,8 +321,7 @@ const ChunkManager = struct { // MARK: ChunkManager
return ch;
}
ch.generated = true;
const caveMap = terrain.CaveMap.CaveMapView.init(ch);
defer caveMap.deinit();
const caveMap = terrain.CaveMap.CaveMapView.findMapsAround(ch);
const biomeMap = terrain.CaveBiomeMap.CaveBiomeMapView.init(main.stackAllocator, ch.super.pos, ch.super.width, 32);
defer biomeMap.deinit();
for(server.world.?.chunkManager.terrainGenerationProfile.generators) |generator| {
@ -721,8 +720,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
for(0..2) |dy| {
const mapX = mapStartX +% main.server.terrain.SurfaceMap.MapFragment.mapSize*@as(i32, @intCast(dx));
const mapY = mapStartY +% main.server.terrain.SurfaceMap.MapFragment.mapSize*@as(i32, @intCast(dy));
const map = main.server.terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(mapX, mapY, ch.super.pos.voxelSize);
defer map.decreaseRefCount();
const map = main.server.terrain.SurfaceMap.getOrGenerateFragment(mapX, mapY, ch.super.pos.voxelSize);
if(!map.wasStored.swap(true, .monotonic)) {
map.save(null, .{});
}
@ -855,8 +853,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
var dir: main.chunk.Neighbor = .dirNegX;
var stepsRemaining: usize = 1;
for(0..spiralLen) |_| {
const map = main.server.terrain.ClimateMap.getOrGenerateFragmentAndIncreaseRefCount(wx, wy);
defer map.decreaseRefCount();
const map = main.server.terrain.ClimateMap.getOrGenerateFragment(wx, wy);
for(0..map.map.len) |_| {
const x = main.random.nextIntBounded(u31, &main.seed, map.map.len);
const y = main.random.nextIntBounded(u31, &main.seed, map.map.len);
@ -895,8 +892,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
}
std.log.err("Found no valid spawn location", .{});
}
const map = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(self.spawn[0], self.spawn[1], 1);
defer map.decreaseRefCount();
const map = terrain.SurfaceMap.getOrGenerateFragment(self.spawn[0], self.spawn[1], 1);
self.spawn[2] = map.getHeight(self.spawn[0], self.spawn[1]) + 1;
}
const newBiomeCheckSum: i64 = @bitCast(terrain.biomes.getBiomeCheckSum(self.seed));
@ -1038,8 +1034,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
}
fn isValidSpawnLocation(_: *ServerWorld, wx: i32, wy: i32) bool {
const map = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(wx, wy, 1);
defer map.decreaseRefCount();
const map = terrain.SurfaceMap.getOrGenerateFragment(wx, wy, 1);
return map.getBiome(wx, wy).isValidPlayerSpawn;
}