From 958f00c9f06d4cc45fc912f1946bbbb8d9ec3466 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 23 Feb 2025 21:16:21 +0100 Subject: [PATCH] Improve the spawn searching algorithm. It now uses a spiral starting at (0, 0), and it should be a lot faster too. fixes #1093 --- src/server/world.zig | 55 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/server/world.zig b/src/server/world.zig index 3aff528f..83209402 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -745,11 +745,56 @@ pub const ServerWorld = struct { // MARK: ServerWorld if(!self.generated) { var seed: u64 = @bitCast(@as(i64, @truncate(std.time.nanoTimestamp()))); std.log.info("Finding position..", .{}); - for(0..1000) |_| { - self.spawn[0] = main.random.nextIntBounded(u31, &seed, 65536); - self.spawn[1] = main.random.nextIntBounded(u31, &seed, 65536); - std.log.info("Trying ({}, {})", .{self.spawn[0], self.spawn[1]}); - if(self.isValidSpawnLocation(self.spawn[0], self.spawn[1])) break; + foundPosition: { + // Explore chunks in a spiral from the center: + const radius = 65536; + const mapSize = terrain.ClimateMap.ClimateMapFragment.mapSize; + const spiralLen = 2*radius/mapSize*2*radius/mapSize; + var wx: i32 = 0; + var wy: i32 = 0; + var dirChanges: usize = 1; + 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(); + 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); + const biomeSize = main.server.terrain.SurfaceMap.MapFragment.biomeSize; + std.log.info("Trying roughly ({}, {})", .{wx + x*biomeSize, wy + y*biomeSize}); + const sample = map.map[x][y]; + if(sample.biome.isValidPlayerSpawn) { + for(0..16) |_| { + self.spawn[0] = wx + x*biomeSize + main.random.nextIntBounded(u31, &seed, biomeSize*2) - biomeSize; + self.spawn[1] = wy + y*biomeSize + main.random.nextIntBounded(u31, &seed, biomeSize*2) - biomeSize; + std.log.info("Trying ({}, {})", .{self.spawn[0], self.spawn[1]}); + if(self.isValidSpawnLocation(self.spawn[0], self.spawn[1])) break :foundPosition; + } + } + } + switch (dir) { + .dirNegX => wx -%= mapSize, + .dirPosX => wx +%= mapSize, + .dirNegY => wy -%= mapSize, + .dirPosY => wy +%= mapSize, + else => unreachable, + } + stepsRemaining -= 1; + if(stepsRemaining == 0) { + switch (dir) { + .dirNegX => dir = .dirNegY, + .dirPosX => dir = .dirPosY, + .dirNegY => dir = .dirPosX, + .dirPosY => dir = .dirNegX, + else => unreachable, + } + dirChanges += 1; + // Every second turn the number of steps needed doubles. + stepsRemaining = dirChanges/2; + } + } + std.log.err("Found no valid spawn location", .{}); } const map = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(self.spawn[0], self.spawn[1], 1); defer map.decreaseRefCount();